Skip to content

Commit e6327c7

Browse files
authored
Move release flow to PR-based and add CODEOWNERS for branch protection (#649)
* Move release flow to PR-based and add CODEOWNERS for branch protection - Add .github/CODEOWNERS - Cut a release branch in release.sh and open two PRs (sync to dev, release to main) instead of merging dev into main locally - Move tag creation into a workflow that fires on push to main - Skip auto_version_dev when Config.xcconfig was changed in this push, so merging the release sync-PR into dev does not double-bump * Make workflow guards portable via fork check Replace the hardcoded 'loopandlearn' owner check in workflows with a fork check, so the workflows run on any non-fork repository (including a test org) while still skipping on contributor forks. * Allow skipping sister repo updates in release.sh Set SKIP_SISTER_REPOS=1 to bypass the LoopFollow_Second / LoopFollow_Third update_follower steps. Default behavior is unchanged: both sister repos are updated as today and missing directories still cause a hard error, so a forgotten clone in production fails fast. * Revert "Allow skipping sister repo updates in release.sh" This reverts commit c2792b8. * Skip patch hunks for files missing from sister repos Sister repos (LoopFollow_Second / LoopFollow_Third) are intentionally stripped of dev-only files like release.sh, auto_version_dev.yml, lint.yml, and warn_main_pr.yml. Any release patch that touches one of those files used to abort the sister-repo update with 'No such file or directory'. Now update_follower runs git apply --check first, parses the missing-file errors, and re-applies with --exclude for each, so the sister patch covers the files that actually exist. * Revert "Skip patch hunks for files missing from sister repos" This reverts commit 45b9871.
1 parent 0d91b95 commit e6327c7

5 files changed

Lines changed: 133 additions & 31 deletions

File tree

.github/CODEOWNERS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Code owners for LoopFollow.
2+
# Owners listed here are automatically requested for review on PRs and,
3+
# when "Require review from Code Owners" is enabled in branch protection,
4+
# their approval is required before a PR can be merged.
5+
6+
* @marionbarker @bjorkert @codebymini

.github/workflows/auto_version_dev.yml

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,40 @@ on:
3535

3636
jobs:
3737
bump-version:
38-
if: github.repository_owner == 'loopandlearn'
38+
if: ${{ !github.event.repository.fork }}
3939
runs-on: ubuntu-latest
4040

4141
steps:
4242
- name: Checkout repository
4343
uses: actions/checkout@v5
4444
with:
4545
token: ${{ secrets.LOOPFOLLOW_TOKEN_AUTOBUMP }}
46+
fetch-depth: 0
47+
48+
- name: Skip if Config.xcconfig was changed in this push
49+
id: check
50+
run: |
51+
BEFORE="${{ github.event.before }}"
52+
if [ -z "$BEFORE" ] || [ "$BEFORE" = "0000000000000000000000000000000000000000" ]; then
53+
echo "skip=false" >> "$GITHUB_OUTPUT"
54+
echo "No previous SHA on this push; not skipping."
55+
exit 0
56+
fi
57+
if git diff "$BEFORE..HEAD" -- Config.xcconfig | grep -qE '^\+LOOP_FOLLOW_MARKETING_VERSION'; then
58+
echo "skip=true" >> "$GITHUB_OUTPUT"
59+
echo "LOOP_FOLLOW_MARKETING_VERSION was set in this push (likely a release sync); skipping auto-bump."
60+
else
61+
echo "skip=false" >> "$GITHUB_OUTPUT"
62+
fi
4663
4764
- name: Set up Git
65+
if: steps.check.outputs.skip != 'true'
4866
run: |
4967
git config --global user.name "github-actions[bot]"
5068
git config --global user.email "github-actions[bot]@users.noreply.github.com"
5169
5270
- name: Bump dev version number in Config.xcconfig
71+
if: steps.check.outputs.skip != 'true'
5372
run: |
5473
FILE=Config.xcconfig
5574
@@ -85,6 +104,7 @@ jobs:
85104
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV
86105
87106
- name: Commit and push changes
107+
if: steps.check.outputs.skip != 'true'
88108
run: |
89109
git add Config.xcconfig
90110
git commit -m "CI: Bump dev version to $NEW_VERSION [skip ci]"

.github/workflows/tag_on_main.yml

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# -----------------------------------------------------------------------------
2+
# Workflow: Tag release on push to main
3+
#
4+
# Description:
5+
# Creates an annotated git tag whenever main advances to a release version
6+
# (X.Y.0). The version is read from LOOP_FOLLOW_MARKETING_VERSION in
7+
# Config.xcconfig and the tag name is `v<version>`.
8+
#
9+
# Triggered by: any push to main (release PR merge).
10+
# Skips if: the version on main is not X.Y.0 (e.g. a hotfix that didn't bump
11+
# minor/major), or if the tag already exists.
12+
# -----------------------------------------------------------------------------
13+
14+
name: Tag release on main
15+
16+
on:
17+
push:
18+
branches:
19+
- main
20+
21+
jobs:
22+
tag:
23+
if: ${{ !github.event.repository.fork }}
24+
runs-on: ubuntu-latest
25+
permissions:
26+
contents: write
27+
28+
steps:
29+
- name: Checkout repository
30+
uses: actions/checkout@v5
31+
with:
32+
fetch-depth: 0
33+
34+
- name: Extract version from Config.xcconfig
35+
id: version
36+
run: |
37+
VERSION=$(grep -E "^LOOP_FOLLOW_MARKETING_VERSION[[:space:]]*=" Config.xcconfig | awk '{print $3}')
38+
if [ -z "$VERSION" ]; then
39+
echo "::error::Could not find LOOP_FOLLOW_MARKETING_VERSION in Config.xcconfig"
40+
exit 1
41+
fi
42+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
43+
echo "Found version: $VERSION"
44+
45+
- name: Skip non-release versions (only X.Y.0 is tagged)
46+
id: check
47+
run: |
48+
VERSION="${{ steps.version.outputs.version }}"
49+
if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.0$ ]]; then
50+
echo "is_release=true" >> "$GITHUB_OUTPUT"
51+
else
52+
echo "is_release=false" >> "$GITHUB_OUTPUT"
53+
echo "Version $VERSION is not a release version (X.Y.0); skipping tag."
54+
fi
55+
56+
- name: Create and push tag if missing
57+
if: steps.check.outputs.is_release == 'true'
58+
run: |
59+
TAG="v${{ steps.version.outputs.version }}"
60+
git config user.name "github-actions[bot]"
61+
git config user.email "github-actions[bot]@users.noreply.github.com"
62+
if git rev-parse "$TAG" >/dev/null 2>&1; then
63+
echo "Tag $TAG already exists; skipping."
64+
else
65+
git tag -a "$TAG" -m "$TAG"
66+
git push origin "$TAG"
67+
echo "Created and pushed tag $TAG"
68+
fi

.github/workflows/warn_main_pr.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88

99
jobs:
1010
warn:
11-
if: github.repository_owner == 'loopandlearn'
11+
if: ${{ !github.event.repository.fork }}
1212
runs-on: ubuntu-latest
1313

1414
permissions:

release.sh

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,6 @@ echo_run() { echo "+ $*"; "$@"; }
2424
push_cmds=()
2525
queue_push() { push_cmds+=("git -C \"$(pwd)\" $*"); echo "+ [queued] (in $(pwd)) git $*"; }
2626

27-
queue_push_tag () {
28-
local tag="$1"
29-
queue_push push origin "refs/tags/$tag"
30-
}
31-
3227
update_follower () {
3328
local DIR="$1"
3429
echo; echo "🔄 Updating $DIR"
@@ -97,32 +92,30 @@ esac
9792

9893
echo "🔢 Bumping version: $old_ver$new_ver"
9994

100-
# --- switch to dev branch ----
95+
# --- switch to dev so the release branch is cut from latest dev ----
10196
echo_run git switch "$DEV_BRANCH"
10297
echo_run git fetch
10398
echo_run git pull
10499

105-
# --- update version number ----
100+
# --- create release branch from dev's tip ----
101+
RELEASE_BRANCH="release/v${new_ver}"
102+
echo_run git switch -c "$RELEASE_BRANCH"
103+
104+
# --- bump version on the release branch ----
106105
sed -i '' "s/${MARKETING_KEY}[[:space:]]*=.*/${MARKETING_KEY} = ${new_ver}/" "$VERSION_FILE"
107106
echo_run git diff "$VERSION_FILE"; pause
108107
echo_run git commit -m "update version to ${new_ver} [skip ci]" "$VERSION_FILE"
109108

110-
echo "💻 Build & test dev branch now."; pause
111-
queue_push push origin "$DEV_BRANCH"
109+
echo "💻 Build & test release branch now."; pause
110+
queue_push push origin "$RELEASE_BRANCH"
112111

113-
# --- create a patch ---------------------------
112+
# --- create a patch from main..release branch (includes the bump) -----
114113
mkdir -p "$PATCH_DIR"
115114
PATCH_FILE="${PATCH_DIR}/LF_diff_${old_ver}_to_${new_ver}.patch"
116115

117-
git diff -M --binary "$MAIN_BRANCH" "$DEV_BRANCH" \
116+
git diff -M --binary "$MAIN_BRANCH" "$RELEASE_BRANCH" \
118117
> "$PATCH_FILE"
119118

120-
# --- merge dev into main for new release
121-
echo_run git switch "$MAIN_BRANCH"
122-
echo_run git merge "$DEV_BRANCH"
123-
echo "💻 Build & test main branch now."; pause
124-
queue_push push origin "$MAIN_BRANCH"
125-
126119
cd ..
127120
update_follower "$SECOND_DIR"
128121
update_follower "$THIRD_DIR"
@@ -136,24 +129,39 @@ pause
136129
cd ${PRIMARY_ABS_PATH}
137130

138131
# ---------- push queue ----------
139-
echo; echo "🚀 Ready to tag and push changes upstream."
132+
echo; echo "🚀 Ready to push changes upstream and open the release PR."
140133
echo_run git log --oneline -2
141134

142-
read -rp "▶▶ Ready to tag? (y/n): " confirm
143-
if [[ $confirm =~ ^[Yy]$ ]]; then
144-
git tag -a "v${new_ver}" -m "v${new_ver}"
145-
queue_push_tag "v${new_ver}"
146-
echo_run git log --oneline -2
147-
else
148-
echo "🚫 tag skipped, can add later"
149-
fi
150-
151135
read -rp "▶▶ Push everything now? (y/n): " confirm
152136
if [[ $confirm =~ ^[Yy]$ ]]; then
153137
for cmd in "${push_cmds[@]}"; do echo "+ $cmd"; bash -c "$cmd"; done
154138
echo "🎉 All pushes completed."
155-
echo; echo "🎉 All repos updated to v${new_ver} (local)."
156-
echo "👉 Remember to create a GitHub release for tag v${new_ver}."
139+
140+
echo; echo "📝 Opening sync PR ${RELEASE_BRANCH}${DEV_BRANCH}"
141+
gh pr create \
142+
--base "$DEV_BRANCH" \
143+
--head "$RELEASE_BRANCH" \
144+
--title "Sync v${new_ver} version bump to dev" \
145+
--body "Syncs the v${new_ver} version bump from the release branch back to \`dev\` so subsequent auto-bumps on \`dev\` continue from the released minor.
146+
147+
\`auto_version_dev\` detects that \`Config.xcconfig\` was changed in this push and skips re-bumping.
148+
149+
⚠️ **Use rebase-merge** (not squash or merge-commit) so \`dev\` and \`main\` end up at the same commit SHA after the release."
150+
151+
echo; echo "📝 Opening release PR ${RELEASE_BRANCH}${MAIN_BRANCH}"
152+
gh pr create \
153+
--base "$MAIN_BRANCH" \
154+
--head "$RELEASE_BRANCH" \
155+
--title "Release v${new_ver}" \
156+
--body "Release v${new_ver}.
157+
158+
Merging this PR triggers the tagging workflow, which creates tag \`v${new_ver}\` from \`LOOP_FOLLOW_MARKETING_VERSION\` in \`Config.xcconfig\`.
159+
160+
⚠️ **Use rebase-merge** (not squash or merge-commit) so \`dev\` and \`main\` end up at the same commit SHA after the release."
161+
162+
echo; echo "🎉 All repos updated to v${new_ver} (local). Release PRs opened (sync → dev, release → main)."
163+
echo "👉 Review and merge both PRs — the tag will be created automatically by .github/workflows/tag_on_main.yml."
164+
echo "👉 Remember to create a GitHub release for tag v${new_ver} after the tag exists."
157165
else
158166
echo "🚫 Pushes skipped. Run manually if needed:"; printf ' %s\n' "${push_cmds[@]}"
159167
echo "🚫 Release not completed, pushes to GitHub were skipped"

0 commit comments

Comments
 (0)