Skip to content

Sync Changelog

Sync Changelog #294

name: Sync Changelog
on:
schedule:
- cron: "17 * * * *"
workflow_dispatch:
push:
branches: [main]
paths:
- "references/api/changelog.mdx"
- ".changelog/relay-kit-overrides.md"
- ".changelog/app.md"
- "scripts/build-changelog.mjs"
permissions:
contents: write
pull-requests: write
concurrency:
group: sync-changelog
cancel-in-progress: false
env:
SYNC_BRANCH: bot/changelog-sync
jobs:
sync:
runs-on: ubuntu-latest
steps:
# Pinned by commit SHA, not tag: this job can write to the repo, so a retagged action
# would be a direct write path into it. fetch-depth 0 so the sync branch is present to
# compare against.
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
fetch-depth: 0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 22
# No secret required: every hand-written source lives in this repo, and relay-kit is
# public. GITHUB_TOKEN is passed only so the clone spends a per-token rate limit rather
# than the runner's shared per-IP one.
- name: Rebuild changelog.mdx
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: node scripts/build-changelog.mjs
- name: Open or update the sync pull request
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
# Nothing pending for this job. Retire the sync branch only if it carries nothing at
# all: deleting a PR head branch closes the PR and discards its review, and the
# branch may hold something this job did not put there. Comparing the whole tree,
# not just changelog.mdx, is the point.
if git diff --quiet -- changelog.mdx; then
echo "changelog.mdx already matches main"
if git ls-remote --exit-code --heads origin "$SYNC_BRANCH" >/dev/null 2>&1; then
if git diff --quiet "origin/main" "origin/$SYNC_BRANCH"; then
echo "main has caught up and the sync branch carries nothing; deleting it"
git push origin --delete "$SYNC_BRANCH"
else
echo "::warning::$SYNC_BRANCH still differs from main — leaving it, and any open pull request, alone"
fi
fi
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
# Resolved before the content comparison below: matching content only means "nothing
# to do" when a PR is actually open on it. If a previous `gh pr create` failed, or
# someone closed the PR and left the branch, the branch is up to date and every later
# run would exit green with no PR in existence.
state=$(gh pr view "$SYNC_BRANCH" --json state --jq .state 2>/dev/null || echo NONE)
# Rebuilt as main plus one commit every run, so the PR diff is always exactly what is
# pending — no rebase, no conflict, and no pile of intermediate snapshots to read.
git checkout -B "$SYNC_BRANCH"
git add changelog.mdx
git commit -m "docs: sync changelog"
# Same content the open PR already carries? Leave it, and its review state, alone.
# The generator is byte-deterministic, so an hour with no upstream change compares
# equal and pushes nothing. `|| true` because set -e would otherwise kill the job if
# that branch existed without the file on it.
if [ "$state" = "OPEN" ]; then
current=$(git rev-parse "HEAD:changelog.mdx")
published=$(git rev-parse "origin/$SYNC_BRANCH:changelog.mdx" 2>/dev/null || true)
if [ "$current" = "$published" ]; then
echo "the open pull request already carries this changelog"
exit 0
fi
fi
git push --force origin "$SYNC_BRANCH"
if [ "$state" = "OPEN" ]; then
echo "updated the open pull request"
exit 0
fi
body=$(printf '%s\n\n%s\n' \
'Generated by `scripts/build-changelog.mjs` from the sources described in AGENTS.md section 4.6.' \
'Review the diff, but fix wording in the source an entry came from rather than here — this file is generated, and the branch is rebuilt on every sync, so the diff always shows everything pending since the last merge.')
gh pr create \
--base main \
--head "$SYNC_BRANCH" \
--title "docs: sync changelog" \
--body "$body"