Sync from upstream #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Sync from upstream | |
| # Cuts a branch from bluesky-social/atproto (the `upstream` remote) and merges | |
| # our `main` into it, producing "upstream + our custom changes". It then opens a | |
| # PR back into `main` so CI (.github/workflows/repo.yaml) validates the result | |
| # before a human merges it. | |
| # | |
| # Requirements: | |
| # - An `upstream` reference to bluesky-social/atproto. This workflow adds it at | |
| # runtime, so no remote config is needed in the repo. | |
| # | |
| # Note on tokens/CI: the PR is opened with the default GITHUB_TOKEN, which by | |
| # design does NOT trigger the `on: pull_request` CI in repo.yaml. That is fine | |
| # here because the PR is opened as a draft (we don't want CI yet). When a human | |
| # marks it "Ready for review", that human-triggered `ready_for_review` event | |
| # does start CI. So no GitHub App / PAT is needed. | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| upstream_ref: | |
| description: 'Upstream ref to sync from (branch, tag, or SHA)' | |
| required: true | |
| default: 'main' | |
| branch_suffix: | |
| description: 'Optional suffix for the sync branch name' | |
| required: false | |
| default: '' | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| jobs: | |
| sync: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout main (full history) | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: main | |
| fetch-depth: 0 | |
| - name: Add upstream and fetch | |
| run: | | |
| git remote add upstream https://github.com/bluesky-social/atproto.git | |
| git fetch upstream --no-tags "${{ github.event.inputs.upstream_ref }}" | |
| - name: Configure git identity | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| - name: Create sync branch from upstream | |
| id: branch | |
| run: | | |
| DATE="$(date +'%Y-%m-%d')" | |
| SUFFIX="${{ github.event.inputs.branch_suffix }}" | |
| BRANCH="sync/upstream-${DATE}" | |
| if [ -n "$SUFFIX" ]; then | |
| BRANCH="${BRANCH}-${SUFFIX}" | |
| fi | |
| # Disambiguate if a branch for today already exists. | |
| if git ls-remote --exit-code --heads origin "$BRANCH" >/dev/null 2>&1; then | |
| BRANCH="${BRANCH}-${{ github.run_number }}" | |
| fi | |
| echo "name=$BRANCH" >> "$GITHUB_OUTPUT" | |
| git checkout -b "$BRANCH" FETCH_HEAD | |
| - name: Merge main into the sync branch | |
| id: merge | |
| run: | | |
| set +e | |
| git merge --no-ff --no-edit origin/main | |
| STATUS=$? | |
| set -e | |
| if [ "$STATUS" -eq 0 ]; then | |
| echo "conflicts=false" >> "$GITHUB_OUTPUT" | |
| echo "No conflicts merging origin/main." | |
| else | |
| CONFLICTED="$(git diff --name-only --diff-filter=U)" | |
| echo "conflicts=true" >> "$GITHUB_OUTPUT" | |
| { | |
| echo 'files<<EOF' | |
| echo "$CONFLICTED" | |
| echo 'EOF' | |
| } >> "$GITHUB_OUTPUT" | |
| # Record the conflict markers so a human can resolve them in-branch. | |
| git add -A | |
| git commit --no-edit | |
| echo "Committed conflict markers for: $CONFLICTED" | |
| fi | |
| - name: Push sync branch | |
| run: git push origin "${{ steps.branch.outputs.name }}" | |
| - name: Open pull request | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| BRANCH: ${{ steps.branch.outputs.name }} | |
| UPSTREAM_REF: ${{ github.event.inputs.upstream_ref }} | |
| CONFLICTS: ${{ steps.merge.outputs.conflicts }} | |
| CONFLICT_FILES: ${{ steps.merge.outputs.files }} | |
| run: | | |
| if [ "$CONFLICTS" = "true" ]; then | |
| TITLE="Sync upstream (${UPSTREAM_REF}) — conflicts to resolve" | |
| BODY=$(cat <<EOF | |
| Automated upstream sync. | |
| This branch was cut from \`upstream/${UPSTREAM_REF}\` and \`origin/main\` was merged into it. | |
| ⚠️ **Merge conflicts were committed as markers and must be resolved before merging.** | |
| Conflicted files: | |
| \`\`\` | |
| ${CONFLICT_FILES} | |
| \`\`\` | |
| To resolve: | |
| \`\`\` | |
| git fetch origin | |
| git checkout ${BRANCH} | |
| # resolve conflict markers, then: | |
| git add -A && git commit | |
| git push | |
| \`\`\` | |
| Once resolved, mark this PR **Ready for review** to trigger CI. | |
| EOF | |
| ) | |
| gh pr create --base main --head "$BRANCH" --title "$TITLE" --body "$BODY" --draft | |
| else | |
| TITLE="Sync upstream (${UPSTREAM_REF})" | |
| BODY=$(cat <<EOF | |
| Automated upstream sync. | |
| This branch was cut from \`upstream/${UPSTREAM_REF}\` and \`origin/main\` was merged into it cleanly. | |
| Mark this PR **Ready for review** to trigger CI, then merge once it is green. | |
| EOF | |
| ) | |
| gh pr create --base main --head "$BRANCH" --title "$TITLE" --body "$BODY" --draft | |
| fi |