From 31e5ae96a6bd00ec20267b7a51e35bb2edddbcac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bj=C3=B6rkert?= Date: Fri, 26 Jun 2026 14:44:22 +0200 Subject: [PATCH 1/7] Derive Fastlane bundle identifiers from app_suffix Read app_suffix from LoopFollowDisplayNameConfig.xcconfig in the Fastfile and build the app and Live Activity extension identifiers from it, replacing the hardcoded com..LoopFollow strings. The same Fastfile now produces the correct bundle identifiers in LoopFollow, LoopFollow_Second and LoopFollow_Third without per-repo edits. Update release.sh so the conflict notice no longer lists the Fastfile, which is now identical across the sister repositories. --- fastlane/Fastfile | 49 +++++++++++++++++++++++++++++++++-------------- release.sh | 2 +- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 120b9f061..8f46645c5 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -23,6 +23,27 @@ DEVICE_NAME = ENV["DEVICE_NAME"] DEVICE_ID = ENV["DEVICE_ID"] ENV["FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT"] = "120" +# Reads the per-app suffix from LoopFollowDisplayNameConfig.xcconfig so the same +# Fastfile produces the correct bundle identifiers in every sister repository +# (LoopFollow, LoopFollow_Second, LoopFollow_Third) without per-repo edits. +def loopfollow_app_suffix + root = GITHUB_WORKSPACE || File.expand_path("..", __dir__) + path = File.join(root, "LoopFollowDisplayNameConfig.xcconfig") + return "" unless File.exist?(path) + + File.foreach(path) do |line| + next if line.strip.start_with?("//") + if (match = line.match(/^\s*app_suffix\s*=\s*(.*)$/)) + return match[1].strip + end + end + "" +end + +APP_SUFFIX = loopfollow_app_suffix +APP_IDENTIFIER = "com.#{TEAMID}.LoopFollow#{APP_SUFFIX}" +LA_IDENTIFIER = "#{APP_IDENTIFIER}.LoopFollowLAExtension" + platform :ios do desc "Build Loop Follow" lane :build_LoopFollow do @@ -40,7 +61,7 @@ platform :ios do ) previous_build_number = latest_testflight_build_number( - app_identifier: "com.#{TEAMID}.LoopFollow", + app_identifier: APP_IDENTIFIER, api_key: api_key, ) @@ -55,8 +76,8 @@ platform :ios do type: "appstore", git_basic_authorization: Base64.strict_encode64("#{GITHUB_REPOSITORY_OWNER}:#{GH_PAT}"), app_identifier: [ - "com.#{TEAMID}.LoopFollow", - "com.#{TEAMID}.LoopFollow.LoopFollowLAExtension" + APP_IDENTIFIER, + LA_IDENTIFIER ] ) @@ -66,14 +87,14 @@ platform :ios do update_code_signing_settings( path: "#{GITHUB_WORKSPACE}/LoopFollow.xcodeproj", - profile_name: mapping["com.#{TEAMID}.LoopFollow"], + profile_name: mapping[APP_IDENTIFIER], code_sign_identity: "iPhone Distribution", targets: ["LoopFollow"] ) update_code_signing_settings( - path: "#{GITHUB_WORKSPACE}/LoopFollow.xcodeproj", - profile_name: mapping["com.#{TEAMID}.LoopFollow.LoopFollowLAExtension"], + path: "#{GITHUB_WORKSPACE}/LoopFollow.xcodeproj", + profile_name: mapping[LA_IDENTIFIER], code_sign_identity: "iPhone Distribution", targets: ["LoopFollowLAExtensionExtension"] ) @@ -87,10 +108,10 @@ platform :ios do buildlog_path: 'buildlog', export_options: { provisioningProfiles: { - "com.#{TEAMID}.LoopFollow" => mapping["com.#{TEAMID}.LoopFollow"], - "com.#{TEAMID}.LoopFollow.LoopFollowLAExtension" => mapping["com.#{TEAMID}.LoopFollow.LoopFollowLAExtension"] + APP_IDENTIFIER => mapping[APP_IDENTIFIER], + LA_IDENTIFIER => mapping[LA_IDENTIFIER] } - } + } ) copy_artifacts( @@ -138,12 +159,12 @@ platform :ios do end end - configure_bundle_id("LoopFollow", "com.#{TEAMID}.LoopFollow", [ + configure_bundle_id("LoopFollow", APP_IDENTIFIER, [ Spaceship::ConnectAPI::BundleIdCapability::Type::APP_GROUPS, Spaceship::ConnectAPI::BundleIdCapability::Type::PUSH_NOTIFICATIONS ]) - - configure_bundle_id("LoopFollow Live Activity Extension", "com.#{TEAMID}.LoopFollow.LoopFollowLAExtension", [ + + configure_bundle_id("LoopFollow Live Activity Extension", LA_IDENTIFIER, [ Spaceship::ConnectAPI::BundleIdCapability::Type::APP_GROUPS ]) @@ -166,8 +187,8 @@ platform :ios do verbose: true, git_basic_authorization: Base64.strict_encode64("#{GITHUB_REPOSITORY_OWNER}:#{GH_PAT}"), app_identifier: [ - "com.#{TEAMID}.LoopFollow", - "com.#{TEAMID}.LoopFollow.LoopFollowLAExtension" + APP_IDENTIFIER, + LA_IDENTIFIER ] ) end diff --git a/release.sh b/release.sh index 3ba67c2fb..023428337 100755 --- a/release.sh +++ b/release.sh @@ -48,7 +48,7 @@ update_follower () { # 3 · Pause if any conflict markers remain if git ls-files -u | grep -q .; then echo "⚠️ Conflicts detected." - echo " If Fastfile or build_LoopFollow.yml were modified, these are expected." + echo " If build_LoopFollow.yml was modified, a conflict on the UPSTREAM_REPO line is expected." echo " Open your merge tool, resolve, then press Enter." pause fi From a98e8da6f22556a2a7aafbf4221a6f61c4e13738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bj=C3=B6rkert?= Date: Fri, 26 Jun 2026 15:08:28 +0200 Subject: [PATCH 2/7] Make swiftformat and build workflow identical across sister repos Accept any LoopFollow* directory in Scripts/swiftformat.sh instead of only the exact 'LoopFollow' folder, so formatting runs consistently in LoopFollow, LoopFollow_Second and LoopFollow_Third. Drive the variant name in build_LoopFollow.yml's not-configured summary from ${{ github.event.repository.name }} / ${{ env.UPSTREAM_REPO }} and drop the variant name from two comments, so the workflow no longer hardcodes 'LoopFollow' in cosmetic text. The only intentional per-repo differences left are the cron minute and UPSTREAM_REPO. --- .github/workflows/build_LoopFollow.yml | 12 ++++++------ Scripts/swiftformat.sh | 13 ++++++++----- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build_LoopFollow.yml b/.github/workflows/build_LoopFollow.yml index 443f7bf0c..abf779d15 100644 --- a/.github/workflows/build_LoopFollow.yml +++ b/.github/workflows/build_LoopFollow.yml @@ -131,10 +131,10 @@ jobs: if: steps.workflow-permission.outputs.has_permission != 'true' run: | echo "### :calendar: Scheduled Sync and Build Disabled :mobile_phone_off:" >> $GITHUB_STEP_SUMMARY - echo "You have not yet configured the scheduled sync and build for LoopFollow's browser build." >> $GITHUB_STEP_SUMMARY - echo "Synchronizing your fork of LoopFollow with the upstream repository loopandlearn/LoopFollow will be skipped." >> $GITHUB_STEP_SUMMARY - echo "If you want to enable automatic builds and updates for your LoopFollow, please follow the instructions \ - under the following path LoopFollow/fastlane/testflight.md." >> $GITHUB_STEP_SUMMARY + echo "You have not yet configured the scheduled sync and build for ${{ github.event.repository.name }}'s browser build." >> $GITHUB_STEP_SUMMARY + echo "Synchronizing your fork of ${{ github.event.repository.name }} with the upstream repository ${{ env.UPSTREAM_REPO }} will be skipped." >> $GITHUB_STEP_SUMMARY + echo "If you want to enable automatic builds and updates for your ${{ github.event.repository.name }}, please follow the instructions \ + under the following path ${{ github.event.repository.name }}/fastlane/testflight.md." >> $GITHUB_STEP_SUMMARY # Set a logic flag if this is the second instance of this day-of-week in this month - name: Check if this is the second time this day-of-week happens this month @@ -161,7 +161,7 @@ jobs: (vars.SCHEDULED_BUILD != 'false' && needs.check_status.outputs.IS_SECOND_IN_MONTH == 'true') || (vars.SCHEDULED_SYNC != 'false' && needs.check_status.outputs.NEW_COMMITS == 'true' ) - # Builds LoopFollow + # Builds the app build: name: Build needs: [check_certs, check_status] @@ -203,7 +203,7 @@ jobs: - name: Sync clock run: sudo sntp -sS time.windows.com - # Build signed LoopFollow IPA file + # Build signed IPA file - name: Fastlane Build & Archive run: bundle exec fastlane build_LoopFollow env: diff --git a/Scripts/swiftformat.sh b/Scripts/swiftformat.sh index 575e4a04a..f833051f4 100755 --- a/Scripts/swiftformat.sh +++ b/Scripts/swiftformat.sh @@ -1,11 +1,14 @@ #! /bin/sh -# Check if the folder name is exactly "LoopFollow" +# Only run inside a LoopFollow* directory (LoopFollow, LoopFollow_Second, LoopFollow_Third) FOLDER_NAME=$(basename "${SRCROOT}") -if [ "${FOLDER_NAME}" != "LoopFollow" ]; then - echo "Skipping swiftformat: This script only runs in the LoopFollow directory, not in '${FOLDER_NAME}'" - exit 0 -fi +case "${FOLDER_NAME}" in + LoopFollow*) ;; + *) + echo "Skipping swiftformat: This script only runs in a LoopFollow* directory, not in '${FOLDER_NAME}'" + exit 0 + ;; +esac function assertEnvironment { if [ -z $1 ]; then From dfdeb7da5d124b4cfc15de85007394702a1eb279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bj=C3=B6rkert?= Date: Fri, 26 Jun 2026 15:09:38 +0200 Subject: [PATCH 3/7] Keep swiftformat folder guard intact The exact-'LoopFollow' folder check is intentional: it prevents swiftformat from reformatting source files when the tree is checked out as a sister repo (LoopFollow_Second / LoopFollow_Third), which would create spurious diffs. The script stays identical across all three repos and skips by folder name at runtime. --- Scripts/swiftformat.sh | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/Scripts/swiftformat.sh b/Scripts/swiftformat.sh index f833051f4..575e4a04a 100755 --- a/Scripts/swiftformat.sh +++ b/Scripts/swiftformat.sh @@ -1,14 +1,11 @@ #! /bin/sh -# Only run inside a LoopFollow* directory (LoopFollow, LoopFollow_Second, LoopFollow_Third) +# Check if the folder name is exactly "LoopFollow" FOLDER_NAME=$(basename "${SRCROOT}") -case "${FOLDER_NAME}" in - LoopFollow*) ;; - *) - echo "Skipping swiftformat: This script only runs in a LoopFollow* directory, not in '${FOLDER_NAME}'" - exit 0 - ;; -esac +if [ "${FOLDER_NAME}" != "LoopFollow" ]; then + echo "Skipping swiftformat: This script only runs in the LoopFollow directory, not in '${FOLDER_NAME}'" + exit 0 +fi function assertEnvironment { if [ -z $1 ]; then From f1fd436cac1dc47a2e7006eabb91034fd6dbe663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bj=C3=B6rkert?= Date: Fri, 26 Jun 2026 15:30:41 +0200 Subject: [PATCH 4/7] Sync sister repos by mirroring instead of patching Replace the git diff / git apply patch flow in release.sh's update_follower with an rsync --delete mirror of the release tree into each sister repo, followed by re-applying that instance's overlay (app_suffix, display_name, UPSTREAM_REPO, cron) and renaming the workspace. The per-instance values are derived from the sister directory name; only the staggered cron minute is passed in. Mirroring makes each sister an exact copy of the release tree except for the overlay, so transfers no longer hit patch-context conflicts and any accidental drift in a sister is corrected automatically. Only .git, local/build dirs and the local team override (LoopFollowConfigOverride.xcconfig) are protected from the sync. --- release.sh | 66 +++++++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/release.sh b/release.sh index 023428337..0f4efaf8f 100755 --- a/release.sh +++ b/release.sh @@ -14,7 +14,6 @@ VERSION_FILE="Config.xcconfig" MARKETING_KEY="LOOP_FOLLOW_MARKETING_VERSION" DEV_BRANCH="dev" MAIN_BRANCH="main" -PATCH_DIR="../${APP_NAME}_update_patches" # --------------------------------------- # --- functions here --- @@ -26,38 +25,51 @@ queue_push() { push_cmds+=("git -C \"$(pwd)\" $*"); echo "+ [queued] (in $(pwd)) update_follower () { local DIR="$1" + local cron_min="$2" + local suffix=".${DIR#${APP_NAME}_}" # LoopFollow_Second -> .Second + local display="$DIR" # LoopFollow_Second + local upstream="loopandlearn/${DIR}" # loopandlearn/LoopFollow_Second + echo; echo "🔄 Updating $DIR …" cd "$DIR" - echo; echo "If there are custom changes needed to the patch, make the change before continuing" - pause - # 1 · Make sure we’re on a clean, up-to-date main echo_run git switch "$MAIN_BRANCH" echo_run git fetch echo_run git pull - # 2 · Apply the patch - if ! git apply --whitespace=nowarn "$PATCH_FILE"; then - echo "‼️ Some changes could not be applied, so no changes were made." - echo "The command used was: git apply --whitespace=nowarn $PATCH_FILE" - echo; echo "Use a different terminal to fix and apply the patch before continuing" - pause + # 2 · Full mirror of the release tree from the primary repo. + # Every tracked file (including the overlay files) is synced; only git + # metadata, local/build dirs and the local team override are protected. + # --delete makes the tree an exact mirror, auto-correcting any drift. + echo_run rsync -a --delete \ + --exclude='.git/' \ + --exclude='.claude/' \ + --exclude='build/' \ + --exclude='DerivedData/' \ + --exclude='LoopFollowConfigOverride.xcconfig' \ + "$PRIMARY_ABS_PATH"/ ./ + + # 3 · Re-apply this instance's overlay on top of the mirror + perl -i -pe "s|^app_suffix\s*=.*|app_suffix = ${suffix}|" LoopFollowDisplayNameConfig.xcconfig + perl -i -pe "s|^display_name\s*=.*|display_name = ${display}|" LoopFollowDisplayNameConfig.xcconfig + perl -i -pe "s|^(\s*)UPSTREAM_REPO:.*|\${1}UPSTREAM_REPO: ${upstream}|" .github/workflows/build_LoopFollow.yml + perl -i -pe "s|^(\s*)- cron:.*|\${1}- cron: \"${cron_min} 10 * * 0\" # Sunday at UTC 10:${cron_min}|" .github/workflows/build_LoopFollow.yml + + # 4 · Rename the synced workspace to this instance's name + rm -rf "${DIR}.xcworkspace" + if [ -d "${APP_NAME}.xcworkspace" ]; then + mv "${APP_NAME}.xcworkspace" "${DIR}.xcworkspace" fi - # 3 · Pause if any conflict markers remain - if git ls-files -u | grep -q .; then - echo "⚠️ Conflicts detected." - echo " If build_LoopFollow.yml was modified, a conflict on the UPSTREAM_REPO line is expected." - echo " Open your merge tool, resolve, then press Enter." - pause + # 5 · Single commit capturing the mirror + overlay + git add -A + if git diff --cached --quiet; then + echo "✓ $DIR already up to date — nothing to commit." + else + echo_run git commit -m "transfer v${new_ver} updates from LF to ${DIR}" fi - # 4 · Single commit capturing all staged changes - git add -u - git add $(git ls-files --others --exclude-standard) 2>/dev/null || true - git commit -m "transfer v${new_ver} updates from LF to ${DIR}" - echo_run git status echo "💻 Build & test $DIR now."; pause # build & test checkpoint queue_push push origin "$MAIN_BRANCH" @@ -109,16 +121,10 @@ echo_run git commit -m "update version to ${new_ver} [skip ci]" "$VERSION_FILE" echo "💻 Build & test release branch now."; pause queue_push push origin "$RELEASE_BRANCH" -# --- create a patch from main..release branch (includes the bump) ----- -mkdir -p "$PATCH_DIR" -PATCH_FILE="${PATCH_DIR}/LF_diff_${old_ver}_to_${new_ver}.patch" - -git diff -M --binary "$MAIN_BRANCH" "$RELEASE_BRANCH" \ - > "$PATCH_FILE" - +# --- mirror the release tree into the sister repos (cron minute staggers builds) ---- cd .. -update_follower "$SECOND_DIR" -update_follower "$THIRD_DIR" +update_follower "$SECOND_DIR" "27" +update_follower "$THIRD_DIR" "40" # ---------- GitHub Actions Test --------- echo; From de95b4a2b06ca6e33e9e8aded92e917bac0b0afa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bj=C3=B6rkert?= Date: Fri, 26 Jun 2026 16:55:59 +0200 Subject: [PATCH 5/7] Trim release.sh sync excludes to existing dirs only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the DerivedData and LoopFollowConfigOverride.xcconfig rsync excludes — they don't exist in any of the repos, so there is nothing to protect. The mirror now only shields .git, .claude and build. --- release.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/release.sh b/release.sh index 0f4efaf8f..aa358d525 100755 --- a/release.sh +++ b/release.sh @@ -40,14 +40,12 @@ update_follower () { # 2 · Full mirror of the release tree from the primary repo. # Every tracked file (including the overlay files) is synced; only git - # metadata, local/build dirs and the local team override are protected. - # --delete makes the tree an exact mirror, auto-correcting any drift. + # metadata and local/build dirs are protected. --delete makes the tree an + # exact mirror, auto-correcting any drift. echo_run rsync -a --delete \ --exclude='.git/' \ --exclude='.claude/' \ --exclude='build/' \ - --exclude='DerivedData/' \ - --exclude='LoopFollowConfigOverride.xcconfig' \ "$PRIMARY_ABS_PATH"/ ./ # 3 · Re-apply this instance's overlay on top of the mirror From 79a0d3f25d3e19e9a27042ce9590d16c6c760cfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bj=C3=B6rkert?= Date: Fri, 26 Jun 2026 19:36:17 +0200 Subject: [PATCH 6/7] Preserve each sister's cron minute instead of hardcoding it Capture the sister's existing scheduled-build cron line before mirroring and restore it afterwards, rather than passing hardcoded minutes (27/40) into update_follower. Each repo keeps its own staggered build time with no magic numbers in the call sites; if a repo has no cron line the mirrored default is left in place. --- release.sh | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/release.sh b/release.sh index aa358d525..9d1d37629 100755 --- a/release.sh +++ b/release.sh @@ -25,7 +25,6 @@ queue_push() { push_cmds+=("git -C \"$(pwd)\" $*"); echo "+ [queued] (in $(pwd)) update_follower () { local DIR="$1" - local cron_min="$2" local suffix=".${DIR#${APP_NAME}_}" # LoopFollow_Second -> .Second local display="$DIR" # LoopFollow_Second local upstream="loopandlearn/${DIR}" # loopandlearn/LoopFollow_Second @@ -38,6 +37,11 @@ update_follower () { echo_run git fetch echo_run git pull + # Preserve this instance's scheduled-build minute (the cron is staggered so a + # user who forked all three apps doesn't trigger three simultaneous builds). + local cron_line + cron_line=$(grep -m1 -E '^[[:space:]]*- cron:' .github/workflows/build_LoopFollow.yml || true) + # 2 · Full mirror of the release tree from the primary repo. # Every tracked file (including the overlay files) is synced; only git # metadata and local/build dirs are protected. --delete makes the tree an @@ -52,7 +56,9 @@ update_follower () { perl -i -pe "s|^app_suffix\s*=.*|app_suffix = ${suffix}|" LoopFollowDisplayNameConfig.xcconfig perl -i -pe "s|^display_name\s*=.*|display_name = ${display}|" LoopFollowDisplayNameConfig.xcconfig perl -i -pe "s|^(\s*)UPSTREAM_REPO:.*|\${1}UPSTREAM_REPO: ${upstream}|" .github/workflows/build_LoopFollow.yml - perl -i -pe "s|^(\s*)- cron:.*|\${1}- cron: \"${cron_min} 10 * * 0\" # Sunday at UTC 10:${cron_min}|" .github/workflows/build_LoopFollow.yml + if [ -n "$cron_line" ]; then + CRON_LINE="$cron_line" perl -i -pe 's|^\s*- cron:.*|$ENV{CRON_LINE}|' .github/workflows/build_LoopFollow.yml + fi # 4 · Rename the synced workspace to this instance's name rm -rf "${DIR}.xcworkspace" @@ -119,10 +125,10 @@ echo_run git commit -m "update version to ${new_ver} [skip ci]" "$VERSION_FILE" echo "💻 Build & test release branch now."; pause queue_push push origin "$RELEASE_BRANCH" -# --- mirror the release tree into the sister repos (cron minute staggers builds) ---- +# --- mirror the release tree into the sister repos ---- cd .. -update_follower "$SECOND_DIR" "27" -update_follower "$THIRD_DIR" "40" +update_follower "$SECOND_DIR" +update_follower "$THIRD_DIR" # ---------- GitHub Actions Test --------- echo; From 648a30ee529d042ac8f6f8c57c9832e6bc0ed0ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bj=C3=B6rkert?= Date: Fri, 26 Jun 2026 19:53:40 +0200 Subject: [PATCH 7/7] Define sister build minute in the release script, not the sister repo Pass each app's staggered Sunday-build minute into update_follower and write it during the overlay, instead of capturing it from the sister repo. All per-app data lives in the main repo's release script; the sister owns nothing and is a pure product of the mirror plus the overlay. A comment at the call site explains the staggered minutes. --- release.sh | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/release.sh b/release.sh index 9d1d37629..fa97f02bf 100755 --- a/release.sh +++ b/release.sh @@ -25,6 +25,7 @@ queue_push() { push_cmds+=("git -C \"$(pwd)\" $*"); echo "+ [queued] (in $(pwd)) update_follower () { local DIR="$1" + local build_minute="$2" # staggered Sunday-build minute (see calls below) local suffix=".${DIR#${APP_NAME}_}" # LoopFollow_Second -> .Second local display="$DIR" # LoopFollow_Second local upstream="loopandlearn/${DIR}" # loopandlearn/LoopFollow_Second @@ -37,11 +38,6 @@ update_follower () { echo_run git fetch echo_run git pull - # Preserve this instance's scheduled-build minute (the cron is staggered so a - # user who forked all three apps doesn't trigger three simultaneous builds). - local cron_line - cron_line=$(grep -m1 -E '^[[:space:]]*- cron:' .github/workflows/build_LoopFollow.yml || true) - # 2 · Full mirror of the release tree from the primary repo. # Every tracked file (including the overlay files) is synced; only git # metadata and local/build dirs are protected. --delete makes the tree an @@ -56,9 +52,7 @@ update_follower () { perl -i -pe "s|^app_suffix\s*=.*|app_suffix = ${suffix}|" LoopFollowDisplayNameConfig.xcconfig perl -i -pe "s|^display_name\s*=.*|display_name = ${display}|" LoopFollowDisplayNameConfig.xcconfig perl -i -pe "s|^(\s*)UPSTREAM_REPO:.*|\${1}UPSTREAM_REPO: ${upstream}|" .github/workflows/build_LoopFollow.yml - if [ -n "$cron_line" ]; then - CRON_LINE="$cron_line" perl -i -pe 's|^\s*- cron:.*|$ENV{CRON_LINE}|' .github/workflows/build_LoopFollow.yml - fi + perl -i -pe "s|^(\s*)- cron:.*|\${1}- cron: \"${build_minute} 10 * * 0\" # Sunday at UTC 10:${build_minute}|" .github/workflows/build_LoopFollow.yml # 4 · Rename the synced workspace to this instance's name rm -rf "${DIR}.xcworkspace" @@ -126,9 +120,12 @@ echo "💻 Build & test release branch now."; pause queue_push push origin "$RELEASE_BRANCH" # --- mirror the release tree into the sister repos ---- +# Second arg = each app's scheduled browser-build minute (Sundays at 10:xx UTC), +# staggered from the main app (:17) so a user who forked all three apps doesn't +# trigger three simultaneous builds. cd .. -update_follower "$SECOND_DIR" -update_follower "$THIRD_DIR" +update_follower "$SECOND_DIR" "27" +update_follower "$THIRD_DIR" "40" # ---------- GitHub Actions Test --------- echo;