From baf293a05fc23edcabf307ffefb8e5edf9d02b63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bj=C3=B6rkert?= Date: Sun, 10 May 2026 12:17:38 +0200 Subject: [PATCH 1/3] Move release flow to PR-based and add CODEOWNERS for branch protection (#1) * 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 c2792b8363d6057e02700663b411ca9c71aadb3d. --- .github/CODEOWNERS | 6 +++ .github/workflows/auto_version_dev.yml | 22 ++++++++- .github/workflows/tag_on_main.yml | 68 ++++++++++++++++++++++++++ .github/workflows/warn_main_pr.yml | 2 +- release.sh | 66 ++++++++++++++----------- 5 files changed, 133 insertions(+), 31 deletions(-) create mode 100644 .github/CODEOWNERS create mode 100644 .github/workflows/tag_on_main.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..aedbee24 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,6 @@ +# Code owners for LoopFollow. +# Owners listed here are automatically requested for review on PRs and, +# when "Require review from Code Owners" is enabled in branch protection, +# their approval is required before a PR can be merged. + +* @marionbarker @bjorkert @codebymini diff --git a/.github/workflows/auto_version_dev.yml b/.github/workflows/auto_version_dev.yml index 2317d261..a2adf3c3 100644 --- a/.github/workflows/auto_version_dev.yml +++ b/.github/workflows/auto_version_dev.yml @@ -35,7 +35,7 @@ on: jobs: bump-version: - if: github.repository_owner == 'loopandlearn' + if: ${{ !github.event.repository.fork }} runs-on: ubuntu-latest steps: @@ -43,13 +43,32 @@ jobs: uses: actions/checkout@v5 with: token: ${{ secrets.LOOPFOLLOW_TOKEN_AUTOBUMP }} + fetch-depth: 0 + + - name: Skip if Config.xcconfig was changed in this push + id: check + run: | + BEFORE="${{ github.event.before }}" + if [ -z "$BEFORE" ] || [ "$BEFORE" = "0000000000000000000000000000000000000000" ]; then + echo "skip=false" >> "$GITHUB_OUTPUT" + echo "No previous SHA on this push; not skipping." + exit 0 + fi + if git diff "$BEFORE..HEAD" -- Config.xcconfig | grep -qE '^\+LOOP_FOLLOW_MARKETING_VERSION'; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "LOOP_FOLLOW_MARKETING_VERSION was set in this push (likely a release sync); skipping auto-bump." + else + echo "skip=false" >> "$GITHUB_OUTPUT" + fi - name: Set up Git + if: steps.check.outputs.skip != 'true' run: | git config --global user.name "github-actions[bot]" git config --global user.email "github-actions[bot]@users.noreply.github.com" - name: Bump dev version number in Config.xcconfig + if: steps.check.outputs.skip != 'true' run: | FILE=Config.xcconfig @@ -85,6 +104,7 @@ jobs: echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV - name: Commit and push changes + if: steps.check.outputs.skip != 'true' run: | git add Config.xcconfig git commit -m "CI: Bump dev version to $NEW_VERSION [skip ci]" diff --git a/.github/workflows/tag_on_main.yml b/.github/workflows/tag_on_main.yml new file mode 100644 index 00000000..4fa3d171 --- /dev/null +++ b/.github/workflows/tag_on_main.yml @@ -0,0 +1,68 @@ +# ----------------------------------------------------------------------------- +# Workflow: Tag release on push to main +# +# Description: +# Creates an annotated git tag whenever main advances to a release version +# (X.Y.0). The version is read from LOOP_FOLLOW_MARKETING_VERSION in +# Config.xcconfig and the tag name is `v`. +# +# Triggered by: any push to main (release PR merge). +# Skips if: the version on main is not X.Y.0 (e.g. a hotfix that didn't bump +# minor/major), or if the tag already exists. +# ----------------------------------------------------------------------------- + +name: Tag release on main + +on: + push: + branches: + - main + +jobs: + tag: + if: ${{ !github.event.repository.fork }} + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Checkout repository + uses: actions/checkout@v5 + with: + fetch-depth: 0 + + - name: Extract version from Config.xcconfig + id: version + run: | + VERSION=$(grep -E "^LOOP_FOLLOW_MARKETING_VERSION[[:space:]]*=" Config.xcconfig | awk '{print $3}') + if [ -z "$VERSION" ]; then + echo "::error::Could not find LOOP_FOLLOW_MARKETING_VERSION in Config.xcconfig" + exit 1 + fi + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + echo "Found version: $VERSION" + + - name: Skip non-release versions (only X.Y.0 is tagged) + id: check + run: | + VERSION="${{ steps.version.outputs.version }}" + if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.0$ ]]; then + echo "is_release=true" >> "$GITHUB_OUTPUT" + else + echo "is_release=false" >> "$GITHUB_OUTPUT" + echo "Version $VERSION is not a release version (X.Y.0); skipping tag." + fi + + - name: Create and push tag if missing + if: steps.check.outputs.is_release == 'true' + run: | + TAG="v${{ steps.version.outputs.version }}" + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + if git rev-parse "$TAG" >/dev/null 2>&1; then + echo "Tag $TAG already exists; skipping." + else + git tag -a "$TAG" -m "$TAG" + git push origin "$TAG" + echo "Created and pushed tag $TAG" + fi diff --git a/.github/workflows/warn_main_pr.yml b/.github/workflows/warn_main_pr.yml index c24b78f1..7d79ebb5 100644 --- a/.github/workflows/warn_main_pr.yml +++ b/.github/workflows/warn_main_pr.yml @@ -8,7 +8,7 @@ on: jobs: warn: - if: github.repository_owner == 'loopandlearn' + if: ${{ !github.event.repository.fork }} runs-on: ubuntu-latest permissions: diff --git a/release.sh b/release.sh index fdffd9ea..3ba67c2f 100755 --- a/release.sh +++ b/release.sh @@ -24,11 +24,6 @@ echo_run() { echo "+ $*"; "$@"; } push_cmds=() queue_push() { push_cmds+=("git -C \"$(pwd)\" $*"); echo "+ [queued] (in $(pwd)) git $*"; } -queue_push_tag () { - local tag="$1" - queue_push push origin "refs/tags/$tag" -} - update_follower () { local DIR="$1" echo; echo "πŸ”„ Updating $DIR …" @@ -97,32 +92,30 @@ esac echo "πŸ”’ Bumping version: $old_ver β†’ $new_ver" -# --- switch to dev branch ---- +# --- switch to dev so the release branch is cut from latest dev ---- echo_run git switch "$DEV_BRANCH" echo_run git fetch echo_run git pull -# --- update version number ---- +# --- create release branch from dev's tip ---- +RELEASE_BRANCH="release/v${new_ver}" +echo_run git switch -c "$RELEASE_BRANCH" + +# --- bump version on the release branch ---- sed -i '' "s/${MARKETING_KEY}[[:space:]]*=.*/${MARKETING_KEY} = ${new_ver}/" "$VERSION_FILE" echo_run git diff "$VERSION_FILE"; pause echo_run git commit -m "update version to ${new_ver} [skip ci]" "$VERSION_FILE" -echo "πŸ’» Build & test dev branch now."; pause -queue_push push origin "$DEV_BRANCH" +echo "πŸ’» Build & test release branch now."; pause +queue_push push origin "$RELEASE_BRANCH" -# --- create a patch --------------------------- +# --- 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" "$DEV_BRANCH" \ +git diff -M --binary "$MAIN_BRANCH" "$RELEASE_BRANCH" \ > "$PATCH_FILE" -# --- merge dev into main for new release -echo_run git switch "$MAIN_BRANCH" -echo_run git merge "$DEV_BRANCH" -echo "πŸ’» Build & test main branch now."; pause -queue_push push origin "$MAIN_BRANCH" - cd .. update_follower "$SECOND_DIR" update_follower "$THIRD_DIR" @@ -136,24 +129,39 @@ pause cd ${PRIMARY_ABS_PATH} # ---------- push queue ---------- -echo; echo "πŸš€ Ready to tag and push changes upstream." +echo; echo "πŸš€ Ready to push changes upstream and open the release PR." echo_run git log --oneline -2 -read -rp "β–Άβ–Ά Ready to tag? (y/n): " confirm -if [[ $confirm =~ ^[Yy]$ ]]; then - git tag -a "v${new_ver}" -m "v${new_ver}" - queue_push_tag "v${new_ver}" - echo_run git log --oneline -2 -else - echo "🚫 tag skipped, can add later" -fi - read -rp "β–Άβ–Ά Push everything now? (y/n): " confirm if [[ $confirm =~ ^[Yy]$ ]]; then for cmd in "${push_cmds[@]}"; do echo "+ $cmd"; bash -c "$cmd"; done echo "πŸŽ‰ All pushes completed." - echo; echo "πŸŽ‰ All repos updated to v${new_ver} (local)." - echo "πŸ‘‰ Remember to create a GitHub release for tag v${new_ver}." + + echo; echo "πŸ“ Opening sync PR ${RELEASE_BRANCH} β†’ ${DEV_BRANCH} …" + gh pr create \ + --base "$DEV_BRANCH" \ + --head "$RELEASE_BRANCH" \ + --title "Sync v${new_ver} version bump to dev" \ + --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. + +\`auto_version_dev\` detects that \`Config.xcconfig\` was changed in this push and skips re-bumping. + +⚠️ **Use rebase-merge** (not squash or merge-commit) so \`dev\` and \`main\` end up at the same commit SHA after the release." + + echo; echo "πŸ“ Opening release PR ${RELEASE_BRANCH} β†’ ${MAIN_BRANCH} …" + gh pr create \ + --base "$MAIN_BRANCH" \ + --head "$RELEASE_BRANCH" \ + --title "Release v${new_ver}" \ + --body "Release v${new_ver}. + +Merging this PR triggers the tagging workflow, which creates tag \`v${new_ver}\` from \`LOOP_FOLLOW_MARKETING_VERSION\` in \`Config.xcconfig\`. + +⚠️ **Use rebase-merge** (not squash or merge-commit) so \`dev\` and \`main\` end up at the same commit SHA after the release." + + echo; echo "πŸŽ‰ All repos updated to v${new_ver} (local). Release PRs opened (sync β†’ dev, release β†’ main)." + echo "πŸ‘‰ Review and merge both PRs β€” the tag will be created automatically by .github/workflows/tag_on_main.yml." + echo "πŸ‘‰ Remember to create a GitHub release for tag v${new_ver} after the tag exists." else echo "🚫 Pushes skipped. Run manually if needed:"; printf ' %s\n' "${push_cmds[@]}" echo "🚫 Release not completed, pushes to GitHub were skipped" From 1cd978f1be320baa2f77e630808cea0245811d9c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 10 May 2026 10:17:47 +0000 Subject: [PATCH 2/3] CI: Bump dev version to 6.1.1 [skip ci] --- Config.xcconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Config.xcconfig b/Config.xcconfig index 3ff1066f..9672b57e 100644 --- a/Config.xcconfig +++ b/Config.xcconfig @@ -6,4 +6,4 @@ unique_id = ${DEVELOPMENT_TEAM} //Version (DEFAULT) -LOOP_FOLLOW_MARKETING_VERSION = 6.1.0 +LOOP_FOLLOW_MARKETING_VERSION = 6.1.1 From e453a5d053d939573a96113279e28ee36387bb72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bj=C3=B6rkert?= Date: Sun, 10 May 2026 13:11:17 +0200 Subject: [PATCH 3/3] update version to 6.2.0 [skip ci] --- Config.xcconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Config.xcconfig b/Config.xcconfig index 9672b57e..9b34855d 100644 --- a/Config.xcconfig +++ b/Config.xcconfig @@ -6,4 +6,4 @@ unique_id = ${DEVELOPMENT_TEAM} //Version (DEFAULT) -LOOP_FOLLOW_MARKETING_VERSION = 6.1.1 +LOOP_FOLLOW_MARKETING_VERSION = 6.2.0