Skip to content

feat: add sync-upstream reusable workflow - #255

Merged
d-morrison merged 4 commits into
mainfrom
claude/upstream-sync-workflow-0xnq65
Jul 16, 2026
Merged

feat: add sync-upstream reusable workflow#255
d-morrison merged 4 commits into
mainfrom
claude/upstream-sync-workflow-0xnq65

Conversation

@d-morrison

Copy link
Copy Markdown
Collaborator

Closes #254.

Adds a sync-upstream.yml workflow_call reusable workflow that keeps a fork current with the upstream project it was cut from — the fork-tracking direction that the existing content-sync family (bump-submodule, sync-shared-fragments) doesn't cover.

What it does

A scheduled run:

  1. Fetches the configured upstream branch (upstream-repo, upstream-branch; optional UPSTREAM_TOKEN for a private upstream), without recording a token-bearing remote URL.
  2. git merge --squashes upstream into the fork's working tree — a real three-way merge (so the fork's own files are preserved and only upstream's changes since the last common commit are applied) that stays out of a MERGE_HEAD state, so the shared open-sync-pr composite's git switch -C works.
  3. Reuses open-sync-pr to commit the merge to a reused automation branch and open/update one PR (a no-op when the merge brings nothing).

Clean merge → mergeable PR. Conflict → by default the conflict markers are committed so the drift surfaces as a visible PR for manual resolution; fail-on-conflict: true fails the run instead.

Files

  • .github/workflows/sync-upstream.yml — the reusable workflow.
  • examples/sync-upstream.yml — caller stub (weekly schedule + workflow_dispatch), pinned @v2.
  • website/reference/sync-upstream.qmd — reference page; website/_quarto.yml sidebar entry.
  • README.md / website/workflows.qmd — table rows, permissions bullet, content-sync section, versioning note (@v2-only, postdates the @v1 freeze).
  • changelog.d/add-sync-upstream.added.md — changelog fragment.
  • CLAUDE.md — Layout + pin-list entries.

Testing / bootstrapping

Following the bump-submodule/sync-shared-fragments precedent, there's no end-to-end selftest (the workflow opens PRs / has write side effects); the shared open-sync-pr composite it reuses is already exercised by the sync-pr selftest job's no-op test. The caller stub pins @v2, which only resolves once this merges and slide-major-tag.yml advances the tag.

Consumer

d-morrison/altdoc adopts it to track etiennebacher/altdoc weekly (companion PR).

🤖 Generated with Claude Code

https://claude.ai/code/session_01UreoJrFPfJ5m9MNeCxX45w


Generated by Claude Code

Add a `sync-upstream.yml` workflow_call reusable workflow that keeps a fork
current with the upstream project it was cut from. A scheduled run merges the
configured upstream branch into a fork-owned automation branch and opens a PR
when the merge brings changes, preserving the fork's own changes.

- `git merge --squash` does a real three-way merge without entering a
  MERGE_HEAD state, so the shared open-sync-pr composite's `git switch -C`
  works and only upstream's changes since the last common commit are applied.
- Clean merge -> mergeable PR; conflict -> commit the markers for manual
  resolution (or set fail-on-conflict to fail the run instead).
- Reuses the open-sync-pr composite, alongside bump-submodule and
  sync-shared-fragments.

Ships the full doc set: caller stub, website reference page, README and
workflows.qmd table rows / content-sync section, and a changelog fragment.
New capability -> pins @v2 (postdates the @v1 freeze).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UreoJrFPfJ5m9MNeCxX45w
Copilot AI review requested due to automatic review settings July 16, 2026 00:04
@github-actions
github-actions Bot removed the request for review from Copilot July 16, 2026 00:04
The reference page's "See examples" footer pointed at
blob/main/examples/sync-upstream.yml, which 404s in link-check until this PR
merges (the file isn't on main yet). Match request-dependabot-review.qmd's
form and link the stable tree/main/examples directory instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UreoJrFPfJ5m9MNeCxX45w
Copilot AI review requested due to automatic review settings July 16, 2026 00:06
@github-actions
github-actions Bot removed the request for review from Copilot July 16, 2026 00:06
@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread README.md
`request-dependabot-review.yml` only ever shipped at `@v2` too (it postdates
the freeze — see [gha#252](https://github.com/d-morrison/gha/issues/252)).
the freeze — see [gha#252](https://github.com/d-morrison/gha/issues/252)), as
does `sync-upstream.yml` (added after the freeze — see

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This correctly adds sync-upstream.yml to the ## Versioning section's @v2 list, but the sibling ### Pinning third-party actions subsection's equivalent list (further down this same file, ~line 340: "...request-dependabot-review.yml at @v2 — see the Versioning section above") still doesn't mention sync-upstream.yml. website/versioning.qmd has the identical pair of lists and isn't touched by this PR at all.

Per CLAUDE.md:

the same versioning convention gets restated in multiple, independently-worded spots: not just once per file, but in separate sections of the same file (e.g. README.md's ## Versioning section and its nested ### Pinning third-party actions subsection both needed the same @v1/@v2 exception clause), and across sibling pages that all describe the tag scheme (website/index.qmd's nav blurb, website/versioning.qmd, website/workflows.qmd, CLAUDE.md's own "About this repo")... gha#181 took six review rounds to fully sweep this exact pattern... because each fix only searched the files already in the diff.

This is exactly that pattern recurring. Please also add sync-upstream.yml to:

  • README.md's "Pinning third-party actions" @v2 list (~line 340)
  • website/versioning.qmd's top summary list (~lines 9–15)
  • website/versioning.qmd's own "Pinning third-party actions" list (~lines 67–76)

@claude

claude Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Code review

Reviewed the sync-upstream.yml reusable workflow addition (closes gha-254) plus its example stub, reference docs, README/website prose updates, CLAUDE.md update, and changelog fragment.

Bug scan (2 independent Opus passes) + security/logic pass: no significant bugs. Inputs/secrets are all declared and consumed correctly, the open-sync-pr handoff uses valid input names and only consumes outputs the merge step actually produces, the git merge --squash conflict-detection avoids tripping set -e, and token handling is safe (never persisted to git config, masked automatically as a registered secret, no shell-injection vector from upstream-repo). Both new/changed YAML files parse cleanly.

Confirmed CLAUDE.md violation (posted inline on README.md:284): this PR correctly adds sync-upstream.yml to the Versioning section's @v2-exception list in README.md and website/workflows.qmd, but misses the identical sibling lists in:

  • README.md's Pinning third-party actions subsection (~line 340)
  • website/versioning.qmd (not touched by this PR at all) — both its top summary list (~lines 9-15) and its own "Pinning third-party actions" list (~lines 67-76)

This is exactly the multi-site versioning-prose drift pattern CLAUDE.md's "About this repo" section calls out by name (the gha-181 precedent, which took six review rounds because each fix only searched the files already in the diff).

Non-blocking observations (not flagged as findings — documented/precedented tradeoffs):

  • When fail-on-conflict is false, a conflicting merge commits conflict markers into a PR that GitHub still reports as mergeable/green (only the run log warning, PR body, and commit message flag it). This is a deliberate, opt-outable design choice per the workflow's own doc comments, not a defect.
  • No new _selftest.yml coverage for sync-upstream.yml, but this matches the explicit precedent set for bump-submodule/sync-shared-fragments (side-effecting workflows validated only via open-sync-pr's existing no-op test).

Verdict
Needs more work — one confirmed CLAUDE.md doc-sync gap (the @v1/@v2 versioning-prose omission in README.md's "Pinning third-party actions" subsection and in website/versioning.qmd) should be fixed before merge; no other issues found.

@github-actions

Copy link
Copy Markdown
Contributor

Claude finished reviewView run


Review complete. Summary of findings for PR #255 (d-morrison/gha, sync-upstream reusable workflow):

Confirmed issue (posted inline + in summary):

  • The PR correctly adds sync-upstream.yml to the @v2-exception list in README.md's ## Versioning section and in website/workflows.qmd, but misses the identical sibling lists in README.md's ### Pinning third-party actions subsection and in website/versioning.qmd (untouched by this PR, containing two parallel lists). This is the exact multi-site versioning-prose drift pattern CLAUDE.md calls out by name (the gha#181 precedent). Verified directly by reading both files.

No significant bugs found by either of the two independent Opus bug/security passes — inputs/secrets all correctly declared and consumed, open-sync-pr handoff correct, conflict-handling shell logic sound, token handling safe (no leak/injection risk), both YAML files parse cleanly.

Non-blocking observations (design tradeoffs, not flagged as defects): a conflicting merge (with fail-on-conflict: false) produces a PR GitHub still shows as green/mergeable, signaled only in prose; and there's no new _selftest.yml coverage, though this matches the documented precedent for bump-submodule/sync-shared-fragments.

Posted one inline comment (README.md:284) and a top-level summary comment on the PR.

Verdict

Needs more work — fix the confirmed README.md/website/versioning.qmd doc-sync gap before merge; nothing else blocking.

@github-actions

Copy link
Copy Markdown
Contributor

💰 Cost: $6.6938 (review) — run

The initial commit added sync-upstream.yml to README.md's ## Versioning list
and workflows.qmd, but missed the sibling restatements the CLAUDE.md
whole-repo versioning-sweep rule covers:
- README.md's "Pinning third-party actions" @v2 list
- website/versioning.qmd's top summary list and its own "Pinning third-party
  actions" list (this file wasn't touched before)
- website/permissions.qmd's PR-opening workflows list (bump-submodule /
  sync-shared-fragments / sync-upstream)

Verified via a repo-wide grep that sync-upstream now appears everywhere
request-dependabot-review does in these lists.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UreoJrFPfJ5m9MNeCxX45w
Copilot AI review requested due to automatic review settings July 16, 2026 00:19
@github-actions
github-actions Bot removed the request for review from Copilot July 16, 2026 00:20

Copy link
Copy Markdown
Collaborator Author

Addressed (adb143d). Added sync-upstream.yml to the remaining @v2 / PR-permission restatements the whole-repo versioning-sweep rule covers:

  • README.md's ### Pinning third-party actions @v2 list
  • website/versioning.qmd's top summary list and its own Pinning third-party actions list (the file wasn't touched before)
  • website/permissions.qmd's PR-opening workflows list (bump-submodule / sync-shared-fragments / sync-upstream) — not flagged, but the same class of omission, so swept in the same pass

Verified via grep -rn that sync-upstream now appears everywhere request-dependabot-review does in these lists.


Generated by Claude Code

d-morrison pushed a commit to d-morrison/altdoc that referenced this pull request Jul 16, 2026
Document that the @v2 pin resolves only after Morrison-Lab/gha#255 merges and the
major tag advances, so a manual dispatch before then failing with "workflow not
found" is expected. Addresses review feedback on the unresolved dependency.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UreoJrFPfJ5m9MNeCxX45w
@claude

claude Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Code review

Re-reviewed after the follow-up commit (adb143d). The previously-flagged finding — sync-upstream.yml missing from README.md's "Pinning third-party actions" @v2 list and from website/versioning.qmd's two equivalent lists (see prior review comment) — is confirmed fixed in all four required locations: README.md's ## Versioning section, its ### Pinning third-party actions subsection (~L340), and both lists in website/versioning.qmd (~L9-15, ~L67-76).

One new, small finding turned up in this round, which I wasn't able to post as an inline comment because the affected lines aren't part of this PR's diff (they're unchanged context, so GitHub rejects an inline anchor there — not a permission error, just an unreachable line for the review-comment API):

CLAUDE.md:L26-28permalink

This PR updates the "Several workflows have no corresponding root composite" bullet (CLAUDE.md L41-46) to correctly list sync-upstream.yml as a third caller of the open-sync-pr composite, but leaves an earlier bullet in the same file's Layout section unedited:

`preview/`, `quarto-publish/`, and `open-sync-pr/` are action-only (the last
is the shared push-and-open-PR helper used by `bump-submodule` and
`sync-shared-fragments`).

That bullet still omits sync-upstream, even though .github/workflows/sync-upstream.yml's "Open PR if upstream brought changes" step does call d-morrison/gha/open-sync-pr@v2 — confirmed via gh pr diff 255. Both bullets state the same fact (which workflows call open-sync-pr); one is now complete, the other stale. This is the exact same-file-restated-fact drift CLAUDE.md's own guidance warns about under "When narrowing an already-fixed blanket claim, re-grep the WHOLE repo after every edit": "the same...convention gets restated in multiple, independently-worded spots: not just once per file, but in separate sections of the same file... Fixing the first instance you find and moving on invites the reviewer to find the next one in a later round." That guidance is written around the @v1/@v2 pattern specifically, but names exactly this failure mode.

Suggested fix — update the bullet to:

`preview/`, `quarto-publish/`, and `open-sync-pr/` are action-only (the last
is the shared push-and-open-PR helper used by `bump-submodule`,
`sync-shared-fragments`, and `sync-upstream`).

No other issues found: the bug/security review pass (token handling, command-injection surface, conflict-detection exit-code logic, permissions scope, git merge --squash/MERGE_HEAD interaction with open-sync-pr's git switch -C) came back clean, and the remaining CLAUDE.md doc-sync checks (new-capability @v2 exception clauses, new-input doc sync across README/workflows.qmd/reference page, DRY reuse of open-sync-pr) all check out.

Verdict

Needs more work — one small, easily-fixed same-file doc inconsistency (CLAUDE.md L26-28) before merge; everything else, including the prior round's finding, checks out clean.

@github-actions

Copy link
Copy Markdown
Contributor

Claude finished reviewView run


Posted. Summary of this review round for PR #255:

  • Prior finding confirmed fixed: sync-upstream.yml now appears in all four @v1/@v2 prose locations flagged in the previous round (README.md's Versioning section + Pinning-third-party-actions subsection, and both lists in website/versioning.qmd).
  • New finding: CLAUDE.md L26-28's "action-only" bullet still lists open-sync-pr's callers as only bump-submodule and sync-shared-fragments, while this PR's own edit to a sibling bullet (L41-46) correctly adds sync-upstream as a third caller — a same-file drift matching CLAUDE.md's own documented failure pattern. Couldn't anchor an inline comment there (the lines aren't part of the diff), so it's posted in the summary comment with a suggested fix.
  • Bug/security passes over sync-upstream.yml (token handling, injection surface, conflict-detection logic, permissions, git-state handoff to open-sync-pr) found nothing.

Verdict

Needs more work — one small doc fix remaining.

@github-actions

Copy link
Copy Markdown
Contributor

💰 Cost: $6.9619 (review) — run

The Layout section restates "which workflows call open-sync-pr" in two bullets;
the initial commit updated the later one (L41-46) but left the earlier
"action-only" bullet listing only bump-submodule and sync-shared-fragments.
sync-upstream.yml's "Open PR if upstream brought changes" step calls
open-sync-pr@v2, so it belongs in both. Same-file restated-fact drift per this
file's own re-grep-the-whole-repo guidance.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UreoJrFPfJ5m9MNeCxX45w
Copilot AI review requested due to automatic review settings July 16, 2026 00:31

Copy link
Copy Markdown
Collaborator Author

Addressed (ba21813). Added sync-upstream to the earlier "action-only" Layout bullet's open-sync-pr caller list, so both bullets now read bump-submodule, sync-shared-fragments, and sync-upstream.

Per the same "re-grep the whole repo" guidance, I swept every spot that enumerates open-sync-pr's callers before pushing: CLAUDE.md:26 was the only stale one. The two "so the two auto-PRs don't ping-pong" lines (README / workflows.qmd) are intentionally left scoped to just bump-submodule/sync-shared-fragments — that mutual-content ping-pong doesn't apply to a one-directional fork sync.


Generated by Claude Code

@github-actions
github-actions Bot removed the request for review from Copilot July 16, 2026 00:31
@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1
Preview removed because the pull request was closed.

2026-07-16 00:47 UTC

@github-actions

Copy link
Copy Markdown
Contributor

Claude finished reviewView run


Code review

This is a re-review of PR #255 after the latest commit (ba21813, current head). I verified the fix for the previously-flagged finding and re-checked the diff for new issues.

Prior finding — confirmed fixed. The previous round's finding was that CLAUDE.md's "action-only" bullet (L26-28, listing preview/, quarto-publish/, open-sync-pr/) still enumerated open-sync-pr's callers as only bump-submodule and sync-shared-fragments, while the sibling bullet elsewhere in the same file already listed sync-upstream as a third caller. I fetched CLAUDE.md at the current head SHA and confirmed both bullets now read consistently:

`preview/`, `quarto-publish/`, and `open-sync-pr/` are action-only (the last
is the shared push-and-open-PR helper used by `bump-submodule`,
`sync-shared-fragments`, and `sync-upstream`).

exactly matching the suggested fix.

Whole-repo re-sweep. Per this PR's own precedent (and CLAUDE.md's "re-grep the whole repo after every edit" guidance), I re-grepped every site that enumerates open-sync-pr's callers at the current head — README.md (both the "Content sync" section and the composite-permissions bullet), website/workflows.qmd, website/versioning.qmd, website/permissions.qmd, website/index.qmd — and all consistently say "All three" / list bump-submodule, sync-shared-fragments, sync-upstream together. No remaining stale two-item lists found.

No new issues. The only change since the last-reviewed commit (adb143dba21813) is this two-hunk CLAUDE.md text fix — no workflow, action, or other file changed, so the earlier bug/security pass (token handling, git merge --squash/MERGE_HEAD interaction, open-sync-pr handoff, permissions scope) still applies unchanged and remains clean.

Verdict

Ready for merge — the one outstanding finding from the previous round is confirmed fixed, a full re-sweep of the versioning/caller-list prose turned up nothing further, and no new issues were introduced by the latest commit.

@github-actions

Copy link
Copy Markdown
Contributor

💰 Cost: $1.0911 (review) — run

@d-morrison
d-morrison merged commit 24f404b into main Jul 16, 2026
22 checks passed
@d-morrison
d-morrison deleted the claude/upstream-sync-workflow-0xnq65 branch July 16, 2026 00:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a sync-upstream reusable workflow to keep a fork current with its upstream

2 participants