diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..aedbee244 --- /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 2317d261d..a2adf3c3d 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 000000000..4fa3d1714 --- /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 c24b78f11..7d79ebb53 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 fdffd9eae..3ba67c2fb 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"