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/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..fa97f02bf 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,49 @@ 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
+
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 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/' \
+ "$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: \"${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"
+ 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 Fastfile or build_LoopFollow.yml were modified, these are 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 +119,13 @@ 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 ----
+# 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;