Skip to content
Merged
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
97 changes: 93 additions & 4 deletions .github/workflows/sync-upstream.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,13 @@ jobs:
echo "pr_exists=false" >> "$GITHUB_OUTPUT"
fi

- name: Setup Tools
if: steps.compare.outputs.needs_sync == 'true' && steps.check_pr.outputs.pr_exists == 'false'
uses: tanstack/config/.github/setup@main

- name: Merge upstream into fork branch
if: steps.compare.outputs.needs_sync == 'true' && steps.check_pr.outputs.pr_exists == 'false'
id: merge
run: |
VERSION=${{ steps.compare.outputs.upstream_version }}
DATE=${{ steps.compare.outputs.date }}
Expand All @@ -100,11 +105,83 @@ jobs:
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

# Merge upstream main into our branch
# Attempt the merge — allow failure so we can auto-resolve conflicts
echo "Merging upstream/main into fork branch..."
git merge upstream/main -m "Merge upstream TanStack Pacer v${VERSION} into fork"
if git merge upstream/main -m "Merge upstream TanStack Pacer v${VERSION} into fork"; then
echo "Merge completed cleanly"
echo "auto_resolved=" >> "$GITHUB_OUTPUT"
git push origin "$BRANCH"
exit 0
fi

echo "Merge has conflicts — attempting auto-resolution..."
CONFLICTED=$(git diff --name-only --diff-filter=U)

# ── Auto-resolution rules ─────────────────────────────────────
# Each rule handles a category of files that we never customize
# in the fork and can safely resolve automatically.
AUTO_RESOLVED=""
UNRESOLVED=""

for FILE in $CONFLICTED; do
case "$FILE" in
# Generated docs — take upstream; autofix CI regenerates them
docs/*)
git checkout --theirs -- "$FILE" && git add "$FILE"
AUTO_RESOLVED="${AUTO_RESOLVED} ${FILE} (took upstream — generated docs)\n"
;;
# CI workflows deleted in fork (e.g. release.yml) — keep deleted
.github/workflows/release.yml)
git rm -f "$FILE" 2>/dev/null || true
AUTO_RESOLVED="${AUTO_RESOLVED} ${FILE} (kept deleted — fork uses publish-fork.yml)\n"
;;
# Upstream changelogs — take upstream; fork doesn't add entries
packages/*/CHANGELOG.md)
git checkout --theirs -- "$FILE" && git add "$FILE"
AUTO_RESOLVED="${AUTO_RESOLVED} ${FILE} (took upstream — changelog)\n"
;;
# Lockfile — take upstream, then reconcile with fork's root package.json
pnpm-lock.yaml)
git checkout --theirs -- "$FILE" && git add "$FILE"
AUTO_RESOLVED="${AUTO_RESOLVED} ${FILE} (took upstream + pnpm install to reconcile)\n"
NEEDS_LOCKFILE_RECONCILE=true
;;
# Example app package.json — take upstream; fork doesn't modify examples
examples/*/package.json | examples/*/*/package.json)
git checkout --theirs -- "$FILE" && git add "$FILE"
AUTO_RESOLVED="${AUTO_RESOLVED} ${FILE} (took upstream — example dep versions)\n"
;;
# Everything else requires manual review
*)
UNRESOLVED="${UNRESOLVED} ${FILE}\n"
;;
esac
done

if [ -n "$AUTO_RESOLVED" ]; then
echo "Auto-resolved conflicts:"
echo -e "$AUTO_RESOLVED"
fi

# Push the branch
# If any conflicts remain that we can't auto-resolve, abort
REMAINING=$(git diff --name-only --diff-filter=U)
if [ -n "$REMAINING" ]; then
echo "::error::Unable to auto-resolve all conflicts. Manual intervention required:"
echo -e "$UNRESOLVED"
git merge --abort
exit 1
fi

# Reconcile lockfile if it was conflict-resolved
if [ "${NEEDS_LOCKFILE_RECONCILE:-}" = "true" ]; then
echo "Running pnpm install to reconcile lockfile with fork's package.json..."
pnpm install --no-frozen-lockfile
git add pnpm-lock.yaml
fi

# All conflicts resolved — complete the merge
git commit --no-edit
echo "auto_resolved=$(echo -e "$AUTO_RESOLVED" | base64 -w 0)" >> "$GITHUB_OUTPUT"
git push origin "$BRANCH"

- name: Create PR
Expand All @@ -118,6 +195,18 @@ jobs:

CHANGED=$(echo "${{ steps.compare.outputs.changed }}" | base64 -d)

AUTO_RESOLVED=""
if [ -n "${{ steps.merge.outputs.auto_resolved }}" ]; then
DECODED=$(echo "${{ steps.merge.outputs.auto_resolved }}" | base64 -d)
AUTO_RESOLVED="### Auto-resolved conflicts

\`\`\`
${DECODED}
\`\`\`

"
fi

gh pr create \
--base main \
--head "$BRANCH" \
Expand All @@ -130,7 +219,7 @@ jobs:

${CHANGED}

### After merging
${AUTO_RESOLVED}### After merging

The [publish-fork](${{ github.server_url }}/${{ github.repository }}/actions/workflows/publish-fork.yml) workflow will automatically publish any packages with changed versions.

Expand Down
Loading