Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 113 additions & 42 deletions .github/workflows/sync-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,69 +28,142 @@ 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)
MERGE_BASE=$(git merge-base HEAD origin/main)

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 <<BODY
Automated sync of \`main\` into \`preview\`. Clean merge — no conflicts.

Review the changes and merge when ready.

# Build mention string
${MENTION}

_Opened automatically by the sync-preview workflow._
BODY
)"

- name: Create PR (conflict)
if: steps.merge.outputs.status == 'conflict'
env:
GH_TOKEN: ${{ github.token }}
BRANCH: ${{ steps.merge.outputs.branch }}
AUTHOR_GH: ${{ steps.author.outputs.gh_user }}
run: |
MENTION=""
if [[ -n "$AUTHOR_GH" ]]; then
MENTION="cc @${AUTHOR_GH}"
Expand All @@ -99,11 +172,11 @@ jobs:
gh pr create \
--base preview \
--head "$BRANCH" \
--title "sync-preview: merge main into preview" \
--title "sync-preview: merge main into preview (conflicts)" \
--body "$(cat <<BODY
The automated sync-preview workflow could not cleanly merge \`main\` into \`preview\`.
The automated sync could not cleanly merge \`main\` into \`preview\`.

**This PR contains the merge with conflict markers.** To resolve:
**This PR contains conflict markers.** To resolve:

1. Check out this branch locally:
\`\`\`bash
Expand All @@ -116,8 +189,6 @@ jobs:
3. Keep preview-specific values (package version, preview tests, etc.) — accept main's changes for everything else.
4. Commit and push, then merge this PR.

This must be resolved before the next coordinated release.

${MENTION}

_Opened automatically by the sync-preview workflow._
Expand Down
Loading