diff --git a/.github/workflows/sync-preview.yml b/.github/workflows/sync-preview.yml index 61abcbc86..42bb6b55d 100644 --- a/.github/workflows/sync-preview.yml +++ b/.github/workflows/sync-preview.yml @@ -28,8 +28,8 @@ jobs: git config --global user.name "github-actions[bot]" git config --global user.email "github-actions[bot]@users.noreply.github.com" - - name: Merge main into preview - id: merge + - name: Check if sync needed + id: check run: | git fetch origin main MAIN_SHA=$(git rev-parse origin/main) @@ -37,60 +37,133 @@ jobs: if [[ "$MAIN_SHA" == "$MERGE_BASE" ]]; then echo "✅ preview already contains all of main" - echo "status=up-to-date" >> $GITHUB_OUTPUT - exit 0 + echo "needed=false" >> $GITHUB_OUTPUT + else + echo "needed=true" >> $GITHUB_OUTPUT fi - echo "ℹ️ Merging main into preview..." + - name: Skip if already synced + if: steps.check.outputs.needed == 'false' + run: echo "Nothing to sync." + + - name: Check for existing PR + if: steps.check.outputs.needed == 'true' + id: existing + env: + GH_TOKEN: ${{ github.token }} + run: | + COUNT=$(gh pr list --base preview --search "sync-preview:" --state open --json number --jq 'length') + echo "count=$COUNT" >> $GITHUB_OUTPUT + + - name: Skip if PR already open + if: steps.check.outputs.needed == 'true' && steps.existing.outputs.count != '0' + run: echo "ℹ️ Sync PR already open — skipping duplicate." + + - name: Create sync branch and merge + if: steps.check.outputs.needed == 'true' && steps.existing.outputs.count == '0' + id: merge + run: | + BRANCH="sync-preview/merge-main-$(date +%Y%m%d-%H%M%S)" + git checkout -b "$BRANCH" + + # Save preview's version before merge so we can restore it after + PREVIEW_VERSION=$(node -p "require('./package.json').version") + echo "preview_version=$PREVIEW_VERSION" >> $GITHUB_OUTPUT if git merge origin/main --no-edit -m "chore: merge main into preview"; then - git push origin preview - echo "✅ main merged into preview and pushed" - echo "status=merged" >> $GITHUB_OUTPUT + echo "status=clean" >> $GITHUB_OUTPUT else - git merge --abort - echo "status=conflict" >> $GITHUB_OUTPUT + # If package.json or package-lock.json conflict, accept main's content + # (we'll fix the version back afterwards) + for f in package.json package-lock.json; do + if git diff --name-only --diff-filter=U | grep -qx "$f"; then + git checkout --theirs "$f" + git add "$f" + echo " ↳ resolved $f conflict (accepted main, will restore version)" + fi + done + + # Check if all conflicts are now resolved + if [[ -z "$(git diff --name-only --diff-filter=U)" ]]; then + git commit --no-edit -m "chore: merge main into preview" + echo "status=clean" >> $GITHUB_OUTPUT + else + git add -A + git commit --no-edit -m "chore: merge main into preview (conflicts need resolution)" || true + echo "status=conflict" >> $GITHUB_OUTPUT + fi fi + # Restore preview's version in package.json and package-lock.json + CURRENT_VERSION=$(node -p "require('./package.json').version") + if [[ "$CURRENT_VERSION" != "$PREVIEW_VERSION" ]]; then + node -e " + const fs = require('fs'); + const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8')); + pkg.version = '$PREVIEW_VERSION'; + fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n'); + " + if [[ -f package-lock.json ]]; then + node -e " + const fs = require('fs'); + const lock = JSON.parse(fs.readFileSync('package-lock.json', 'utf8')); + lock.version = '$PREVIEW_VERSION'; + if (lock.packages && lock.packages['']) { + lock.packages[''].version = '$PREVIEW_VERSION'; + } + fs.writeFileSync('package-lock.json', JSON.stringify(lock, null, 2) + '\n'); + " + fi + git add package.json package-lock.json + git commit -m "chore: restore preview version ($PREVIEW_VERSION)" + fi + + git push origin "$BRANCH" + echo "branch=$BRANCH" >> $GITHUB_OUTPUT + - name: Get original commit author - if: steps.merge.outputs.status == 'conflict' + if: steps.merge.outputs.branch != '' id: author - run: | - AUTHOR=$(git log origin/main -1 --format='%an') - GH_USER=$(git log origin/main -1 --format='%ae' | grep -oP '.*(?=@users\.noreply\.github\.com)' || echo "") - if [[ -z "$GH_USER" ]]; then - # Try to get GitHub username from the commit - GH_USER=$(gh api "/repos/${{ github.repository }}/commits/$(git rev-parse origin/main)" --jq '.author.login // empty' 2>/dev/null || echo "") - fi - echo "name=$AUTHOR" >> $GITHUB_OUTPUT - echo "gh_user=$GH_USER" >> $GITHUB_OUTPUT env: GH_TOKEN: ${{ github.token }} + run: | + GH_USER=$(gh api "/repos/${{ github.repository }}/commits/$(git rev-parse origin/main)" --jq '.author.login // empty' 2>/dev/null || echo "") + echo "gh_user=$GH_USER" >> $GITHUB_OUTPUT - - name: Create PR for conflict resolution - if: steps.merge.outputs.status == 'conflict' + - name: Create PR (clean merge) + if: steps.merge.outputs.status == 'clean' env: GH_TOKEN: ${{ github.token }} - AUTHOR_NAME: ${{ steps.author.outputs.name }} + BRANCH: ${{ steps.merge.outputs.branch }} AUTHOR_GH: ${{ steps.author.outputs.gh_user }} run: | - BRANCH="sync-preview/merge-main-$(date +%Y%m%d-%H%M%S)" - - # Check if there's already an open sync PR - EXISTING=$(gh pr list --base preview --search "sync-preview: merge main into preview" --state open --json number --jq 'length') - if [[ "$EXISTING" != "0" ]]; then - echo "ℹ️ Sync PR already open — skipping duplicate." - exit 0 + MENTION="" + if [[ -n "$AUTHOR_GH" ]]; then + MENTION="cc @${AUTHOR_GH}" fi - # Create a branch from preview with the conflict markers - git checkout -b "$BRANCH" - git merge origin/main --no-edit -m "chore: merge main into preview" || true - git add -A - git commit --no-edit -m "chore: merge main into preview (conflicts need resolution)" || true - git push origin "$BRANCH" + gh pr create \ + --base preview \ + --head "$BRANCH" \ + --title "sync-preview: merge main into preview" \ + --body "$(cat <