Skip to content

Automate upstream release docs PRs via Renovate#748

Merged
rdimitrov merged 14 commits intomainfrom
feat/upstream-release-docs
Apr 21, 2026
Merged

Automate upstream release docs PRs via Renovate#748
rdimitrov merged 14 commits intomainfrom
feat/upstream-release-docs

Conversation

@rdimitrov
Copy link
Copy Markdown
Member

@rdimitrov rdimitrov commented Apr 21, 2026

Closes #749

Summary

  • Adds a Renovate custom manager that watches the four tracked upstream ToolHive projects via .github/upstream-projects.yaml and opens a version-bump PR whenever any of them releases.
  • Adds .github/workflows/upstream-release-docs.yml that reacts to Renovate's PRs to produce source-verified content edits using the upstream-release-docs skill (run three times with docs-review), assigns reviewers from non-bot release contributors, and augments the PR body in a marker-delimited section.
  • Replaces the @latest CDN reference for the Registry Server Swagger with a version pinned in the source-of-truth YAML.

See the full design in /Users/dimitrovr/.claude/plans/i-want-to-make-synchronous-axolotl.md (local plan file).

What's tracked

Four projects in .github/upstream-projects.yaml:

id repo pinned at
toolhive stacklok/toolhive v0.22.0
toolhive-registry-server stacklok/toolhive-registry-server v1.2.1
toolhive-studio stacklok/toolhive-studio v0.30.0
toolhive-cloud-ui stacklok/toolhive-cloud-ui v0.5.1

Architecture

There are two trigger paths, both producing a single PR per upstream release.

Path A: stacklok/toolhive releases (unified via update-toolhive-reference.yml)

  1. ToolHive's release CI dispatches repository_dispatch: published-release to this repo (or someone invokes workflow_dispatch manually with a version).
  2. update-toolhive-reference.yml:
    • Regenerates reference assets (CLI help, Swagger, CRD schemas)
    • Bumps version: for toolhive in .github/upstream-projects.yaml
    • Applies pin_files substitutions
    • Opens one PR on branch docs/upstream-toolhive-<version> with labels autogen-docs + upstream-content
  3. upstream-release-docs.yml fires on the opened PR (gated to bot authors + upstream-content label), shallow-clones the upstream, runs the multi-pass skill, assigns reviewers, pushes content commits, and augments the PR body between <!-- upstream-release-docs:start --> markers.
  4. Renovate is explicitly disabled for stacklok/toolhive in renovate.json so it doesn't race.

Path B: the other three projects

  1. Renovate detects version: drift for toolhive-registry-server, toolhive-studio, or toolhive-cloud-ui and opens a PR with the upstream-content label.
  2. upstream-release-docs.yml fires on that PR and does the same augmentation as Path A step 3.

**Path C: workflow_dispatch (manual)**accepts a pr_number input for manual retry if any step fails.

Security posture

  • Double gate: Renovate-bot user identity (GitHub App, can't be impersonated) + required label
  • No use of pull_request_target
  • detect-change.mjs refuses to proceed if a PR tries to change repo: alongside version:
  • All step-outputs and PR-derived values passed through env: vars in run: blocks (no direct \${{ }} shell interpolation); actionlint clean
  • prev_tag existence is verified upstream before the skill runs
  • Failure path labels the PR upstream-docs-failed and comments a retry pointer

Trade-offs intentionally chosen

  • Unsigned commits: the workflow pushes with plain git push as github-actions[bot]. If branch protection rejects unsigned bot commits on Renovate branches, will fix-forward with a GitHub App token rather than migrate to peter-evans speculatively.
  • External-contributor reviewers: added without filtering against repo collaborators. If that causes notification etiquette issues, will add a filter step.
  • No groupName: each upstream release gets its own PR even when two release in the same Renovate cycle.

Upstream dependencies

This PR's code is written assuming stacklok/toolhive#4982 is merged. That PR:

  • Adds thv-crds.tar.gz as a release asset (13 CRD YAMLs)
  • Adds four re-exported toolhive-core schema JSONs as release assets
  • Deletes the repository_dispatch: published-release chain that previously triggered reference-doc regeneration on this repo

All three are purely additive on toolhive's side except the dispatch retirement, which is safe in either merge order (this repo already deleted the receiver workflow earlier in this PR).

Impact of #4982 being merged, reflected in the latest commit here

  • .github/upstream-projects.yaml — toolhive gains five new release_asset: entries; no more source: reliance on a clone for its reference artifacts
  • .github/workflows/upstream-release-docs.yml — the toolhive-specific step downloads thv-crds.tar.gz, extracts to a temp dir, and runs extract-crd-schemas.mjs + generate-crd-pages.mjs + bundle-upstream-schema.mjs inline. No shell-script wrapper.
  • scripts/update-toolhive-reference.sh — deleted entirely

A new "Commit regenerated reference assets" step commits the regen output as a distinct commit before the skill runs, so the autogen-touch detection below only sees skill-introduced changes (fixes a false-positive that would have fired on every toolhive run).

Merge ordering

Either order is safe:

  • #4982 merges first → this PR's workflow works on next toolhive release immediately, pulling the new assets
  • Automate upstream release docs PRs via Renovate #748 merges first → the workflow exists on main but the first toolhive release after merge would fail the CRD-tarball download until #4982 lands. workflow_dispatch retry covers the gap.

Recommend: merge #4982 first if it's ready; otherwise merge #748 and coordinate the #4982 merge before the next toolhive release.

Asks dropped

Two upstream asks were explored and dropped:

  • Pre-generated CRD JSON schemas upstream (would have eliminated extract-crd-schemas.mjs) — rejected because it would add a Node toolchain to an otherwise-pure-Go repo
  • Pre-bundled upstream-registry.schema.json in toolhive-core (would have eliminated bundle-upstream-schema.mjs) — rejected because it introduces a URL reference to maintain upstream; bundling stays colocated with the docs renderer that needs it

Test plan

  • Merge this PR
  • Wait for Renovate's next scan (could take a few hours; the repo's global schedule is Mondays 0-7 NY but this packageRule overrides to at any time)
  • First validation option (fast): after merge, manually backdate one version: in .github/upstream-projects.yaml on a throwaway PR (e.g., bump toolhive-registry-server from v1.2.1 back to v1.2.0). On next Renovate scan it should open a bump PR; confirm the workflow fires and produces expected output.
  • First validation option (organic): wait for any upstream repo to ship a real release; confirm Renovate opens the PR and the workflow augments it end-to-end
  • For the first real run, watch for:
    • Workflow completes within the 60-minute action timeout (skill is multi-pass)
    • The anthropics/claude-code-action@v1 honors the "do not ask questions" directive
    • PR body has the marker-delimited content section inserted (not appended infinitely)
    • Reviewers are assigned (check gh pr view --json reviewRequests)
    • pin_files substitution in docusaurus.config.ts rewrites the Swagger @v1.2.1 to the new tag
    • Content commits pushed by github-actions[bot] are accepted by branch protection (signed-commits check)
    • GAPS.md / NO_CHANGES.md are captured into the PR body and not committed
  • Failure-path smoke: if a real run fails, confirm the upstream-docs-failed label + retry comment appear and workflow_dispatch with pr_number=<n> reruns augmentation idempotently
  • No collision with update-toolhive-reference.yml: for the next ToolHive release, both workflows fire; confirm branches and labels are disjoint and both PRs open cleanly

Manual validation via workflow_dispatch bootstrap

After this PR merges, you can exercise the full end-to-end flow without waiting for Renovate:

Actions → Upstream Release Docs → Run workflow, then either:

  • Bootstrap a new PR: leave pr_number blank, fill project_id (e.g. toolhive-registry-server) and new_tag (e.g. v1.3.0). The workflow creates manual/upstream-<id>-<new_tag>, bumps the YAML, opens a PR with the right labels, and runs the full augmentation in the same run.
  • Retry an existing Renovate PR: fill pr_number, leave the others blank.

Bootstrap mode is gated the same way as Renovate PRs (must supply both project_id and new_tag; collisions with an existing branch fail fast).

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings April 21, 2026 14:45
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs-website Ready Ready Preview, Comment Apr 21, 2026 7:09pm

Request Review

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Automates creation and augmentation of upstream-release documentation PRs by having Renovate bump pinned upstream versions and a workflow generate source-verified doc updates and PR metadata.

Changes:

  • Add Renovate custom manager + rules to monitor .github/upstream-projects.yaml and open version-bump PRs for tracked upstream repos.
  • Add Upstream Release Docs workflow to detect the changed project, run the multi-pass upstream-release-docs + docs-review process, push commits, and update PR body/reviewers.
  • Pin the Registry Server Swagger CDN URL to a specific tag and add tooling (pin_files) to keep it updated.

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
scripts/upstream-release/detect-change.mjs Detects which upstream project version changed vs origin/main and emits outputs for the workflow.
scripts/upstream-release/apply-pin-files.mjs Applies per-project pin_files substitutions after version bumps (e.g., replacing @latest/old tags).
renovate.json Adds a custom regex manager and packageRule to open/label upstream-content PRs on releases.
docusaurus.config.ts Pins Swagger spec URL from @latest to a concrete upstream tag.
.gitignore Ignores workflow signal files GAPS.md and NO_CHANGES.md.
.github/workflows/upstream-release-docs.yml Implements the automation workflow that augments Renovate PRs with generated docs updates and PR body edits.
.github/upstream-projects.yaml Adds the source-of-truth config for tracked upstream repos, pinned versions, docs hints, and pin substitutions.

Comment thread .github/workflows/upstream-release-docs.yml Outdated
Comment thread .github/workflows/upstream-release-docs.yml Outdated
Comment thread .github/workflows/upstream-release-docs.yml Outdated
Comment thread scripts/upstream-release/detect-change.mjs
Comment thread scripts/upstream-release/apply-pin-files.mjs
@rdimitrov rdimitrov changed the title Automate upstream release docs PRs via Renovate Draft: Automate upstream release docs PRs via Renovate Apr 21, 2026
@rdimitrov rdimitrov marked this pull request as draft April 21, 2026 16:11
@rdimitrov rdimitrov marked this pull request as ready for review April 21, 2026 16:11
rdimitrov added a commit that referenced this pull request Apr 21, 2026
- Switch upstream-release scripts and the inline node snippet in the
  workflow from `js-yaml` to the already-declared `yaml` package, so
  the workflow does not rely on a transitive dependency that could
  disappear in a future install. Rewrites the `.load()` calls to
  `.parse()` to match the new package's API.
- Filter out null author logins in the `gh api compare` reviewers
  extraction (`.commits[].author.login? // empty`) so a commit with an
  unlinked GitHub user cannot pass an empty value into --add-reviewer.
- Replace the nested `$([ ... ] && ... || ...)` has_gaps expression
  with an explicit `if/else` block so the quoting stays obviously
  correct and resists accidental breakage in future edits.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
rdimitrov and others added 4 commits April 21, 2026 19:25
Adds a Renovate custom manager that watches version: pins in
.github/upstream-projects.yaml for the four upstream ToolHive projects.
When an upstream ships, Renovate opens a version-bump PR; a new
workflow reacts to push source-verified content edits produced by the
upstream-release-docs skill (three passes with docs-review), assigns
reviewers from non-bot release contributors, and augments the PR body
in a marker-delimited section.

- .github/upstream-projects.yaml: source of truth for tracked projects
- renovate.json: customManagers + packageRule (ignoreUnstable,
  rebaseWhen: never, recreateWhen: never, labels)
- .github/workflows/upstream-release-docs.yml: pull_request + dispatch
- scripts/upstream-release/detect-change.mjs: finds the changed project
  and asserts repo: hasn't been tampered with
- scripts/upstream-release/apply-pin-files.mjs: rewrites @latest pins
- docusaurus.config.ts: pins Registry Server Swagger at v1.2.1

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
workflow_dispatch now accepts either `pr_number` (retry an existing
Renovate PR) or `project_id` + `new_tag` (bootstrap a fresh PR without
waiting for Renovate). The bootstrap path branches off main, bumps
the YAML via scripts/upstream-release/bump-yaml.mjs, creates the PR
with the same labels Renovate applies, and feeds its number into the
rest of the workflow so content augmentation runs identically.

Useful for debugging, manual updates, and validating the pipeline
end-to-end right after merge without waiting for an upstream release.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
update-toolhive-reference.yml now also bumps the toolhive entry in
.github/upstream-projects.yaml, applies pin_files substitutions, and
applies the upstream-content label alongside autogen-docs. The PR it
opens is then picked up by upstream-release-docs.yml (via its
relaxed gate that accepts github-actions[bot] authors) which adds
skill-generated content in a second commit.

Renovate is disabled for stacklok/toolhive so it doesn't race the
reference workflow. The other three tracked projects keep their
Renovate-driven path unchanged.

Net: one PR per stacklok/toolhive release instead of two, with the
same review surface shape as Renovate-driven PRs for the other
projects.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Switch upstream-release scripts and the inline node snippet in the
  workflow from `js-yaml` to the already-declared `yaml` package, so
  the workflow does not rely on a transitive dependency that could
  disappear in a future install. Rewrites the `.load()` calls to
  `.parse()` to match the new package's API.
- Filter out null author logins in the `gh api compare` reviewers
  extraction (`.commits[].author.login? // empty`) so a commit with an
  unlinked GitHub user cannot pass an empty value into --add-reviewer.
- Replace the nested `$([ ... ] && ... || ...)` has_gaps expression
  with an explicit `if/else` block so the quoting stays obviously
  correct and resists accidental breakage in future edits.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread docusaurus.config.ts Outdated
The unified toolhive path had a broken seam: peter-evans opens PRs
with the default GITHUB_TOKEN, and GitHub intentionally does not
trigger pull_request workflows on those PRs (recursion guard).
Verified on PR #747 - no on-pr.yaml run fired. So the content
workflow's pull_request trigger would never fire for toolhive PRs.

Fix: add workflow_call trigger to upstream-release-docs.yml and call
it as a dependent job from update-toolhive-reference.yml after
peter-evans completes. The Renovate path is unaffected - Renovate is
a GitHub App identity whose PRs DO trigger workflows.

Also:
- Distinct concurrency groups per workflow
  (upstream-release-docs-reference vs -content) so the workflow_call
  from reference to content doesn't deadlock on a shared group.
- Drop the "What will be added next" section from the peter-evans
  body; the content workflow appends its own section below.
- Fix leading-whitespace leak in the bootstrap PR body by using
  a heredoc + sed strip instead of an inline quoted string.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per review feedback from Dan: pull the Swagger file from the upstream
repo at the pinned tag into static/api-specs/ and reference the local
file in docusaurus.config.ts, matching how ToolHive's own Swagger is
handled. Keeps the docs build offline-friendly and makes the pin
implicit in git history rather than a CDN URL template.

- New scripts/upstream-release/sync-assets.mjs helper copies declared
  files from the shallow clone into the docs repo. No-op when a
  project declares no assets.
- .github/upstream-projects.yaml gains an `assets:` field per project.
- Replaced the `pin_files` entry for registry-server with assets.
- static/api-specs/toolhive-registry-api.yaml seeded from upstream
  v1.2.1 (1971 lines). Regenerated automatically on every bump.
- Content workflow runs sync-assets right after the shallow clone.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Collapses update-toolhive-reference.yml into upstream-release-docs.yml
so all four tracked projects share one trigger path, one workflow, one
PR per release. Renovate now watches toolhive's version: the same as
the others; the content workflow runs a conditional reference-regen
step for toolhive only.

Also generalizes the `assets:` schema to support three source types:
  - source: <path in upstream repo>           (file-in-clone copy)
  - release_asset: <asset name>               (gh release download)
  - release_asset: <asset name>, extract: tar-gz  (download + extract)

toolhive's swagger and CLI-docs tarball move from the shell script
into declarative `assets:` entries. The shell script shrinks to just
the CRD MDX generation + toolhive-core schema download (the parts
that need custom transforms). It reuses the shallow clone the content
workflow already makes.

Changes:
- Delete .github/workflows/update-toolhive-reference.yml
- Remove workflow_call + dual concurrency groups from the content
  workflow (no chain seam needed without a second workflow)
- Remove the Renovate "disable for stacklok/toolhive" packageRule
- Extend sync-assets.mjs with release_asset + extract support
- Slim update-toolhive-reference.sh; accept TOOLHIVE_CLONE_DIR to
  reuse the workflow's shallow clone

Trade-off: toolhive reference docs now inherit Renovate's 24h
minimumReleaseAge. Previously they published within minutes of a
release. Acceptable for content coherence; set minimumReleaseAge: 0
per-dep if sub-hour latency becomes needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
rdimitrov added a commit to stacklok/toolhive that referenced this pull request Apr 21, 2026
docs-website no longer consumes `repository_dispatch: published-release`
events — its reference-doc regeneration now runs via a Renovate-driven
pipeline that reads the new `thv-crds.tar.gz` and re-exported core
schemas introduced earlier in this PR. See
stacklok/docs-website#748 for context.

Changes:

- Delete `.github/workflows/update-docs-website.yml` (the dispatch
  sender, called via workflow_call from `releaser.yml`).
- Remove the `update-docs-website` job from `releaser.yml` along with
  its `extract-release-actor` dependency, which only existed to feed
  the dispatch's `assign_to` input.
- Update `notify-release-failure`'s `needs:` list to drop the removed
  jobs.

Follow-up for maintainers: the `DOCS_REPO_DISPATCH_TOKEN` repo secret
can be retired — nothing references it after this change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Assumes stacklok/toolhive#4982 has landed. That PR ships three new
release assets on toolhive:
  - thv-crds.tar.gz (the 13 CRD YAMLs)
  - thv-cli-docs.tar.gz (already existed)
  - toolhive-*.schema.json (re-exported from toolhive-core at the
    go.mod-pinned version)

And retires the repository_dispatch chain that previously triggered
our reference-regen workflow.

On our side, the shell wrapper script collapses entirely:

- .github/upstream-projects.yaml: toolhive gains five new release_asset
  entries (swagger, CLI docs tarball with extract, and the four core
  schemas). sync-assets.mjs handles all of them declaratively.
- .github/workflows/upstream-release-docs.yml: the old "run the shell
  script" step becomes an inline "download + extract CRD tarball,
  run our three Node helpers" step. Runs only for project_id=toolhive.
- A new "Commit regenerated reference assets" step lands the regen as
  its own commit, so the autogen-detect step below sees only skill-
  introduced touches (prevents false-positive warnings).
- scripts/update-toolhive-reference.sh deleted.

Net effect after #4982 merges:
  - Zero repo clones for CRD processing (tarball replaces clone)
  - Zero cross-repo downloads (toolhive re-exports core schemas)
  - Zero shell scripts for release-doc regen
  - Three Node helpers stay (extract-crd-schemas, generate-crd-pages,
    bundle-upstream-schema) — they produce docs-specific outputs and
    genuinely belong on our side.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
rdimitrov added a commit to stacklok/toolhive that referenced this pull request Apr 21, 2026
…in (#4982)

* Bundle CRD manifests as a release asset

Adds a `thv-crds.tar.gz` tarball to each release containing the CRD
YAML manifests from `deploy/charts/operator-crds/files/crds/`.

Motivation: downstream consumers of the CRDs (notably
stacklok/docs-website, which generates per-CRD reference pages)
currently have to clone the entire toolhive repo at each release tag
just to read these 13 manifests. Shipping them as a ~94KB tarball
asset lets those consumers skip the clone and just `gh release
download` like they already do for `thv-cli-docs.tar.gz` and
`swagger.yaml`.

Purely additive — no changes to existing release assets or workflows.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Re-export toolhive-core schemas as release assets

Reads the toolhive-core version from go.mod at release time, downloads
the four JSON schema files from that version of stacklok/toolhive-core,
and ships them alongside toolhive's own release assets.

Motivation: downstream consumers (notably stacklok/docs-website)
currently have to replicate this logic: read go.mod, derive the core
version, then fetch from a different repo's release. Re-exporting the
schemas here makes toolhive's release self-contained — one `gh release
download` call gets everything.

Paired with #4982 (CRD
manifests as release asset); together these eliminate the need for
docs-website to clone toolhive or hit a second repo during its
release-doc regeneration.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Retire the docs-website repository_dispatch chain

docs-website no longer consumes `repository_dispatch: published-release`
events — its reference-doc regeneration now runs via a Renovate-driven
pipeline that reads the new `thv-crds.tar.gz` and re-exported core
schemas introduced earlier in this PR. See
stacklok/docs-website#748 for context.

Changes:

- Delete `.github/workflows/update-docs-website.yml` (the dispatch
  sender, called via workflow_call from `releaser.yml`).
- Remove the `update-docs-website` job from `releaser.yml` along with
  its `extract-release-actor` dependency, which only existed to feed
  the dispatch's `assign_to` input.
- Update `notify-release-failure`'s `needs:` list to drop the removed
  jobs.

Follow-up for maintainers: the `DOCS_REPO_DISPATCH_TOKEN` repo secret
can be retired — nothing references it after this change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two improvements from Dan Barr's review of PR #748:

1. Terminology: "regenerate" was overloaded. It now reads accurately:
   - "sync" for release-asset downloads / file copies (swagger, CLI
     tarball, 4 core schemas) — nothing is actually recreated
   - "regenerate" reserved for the toolhive CRD MDX step which truly
     transforms upstream manifests into our opinionated layout
   - "refresh" for the combined commit that may do both
   The commit that lands reference updates is now titled "Refresh
   reference assets for <project> <tag>".

2. Gap attribution: the skill's GAPS.md format now includes the PR
   number and @-mentions the PR author (non-bots only). Previously a
   gap routed to "everyone in the reviewer pool" via a label; now
   each gap directly pings the engineer who built the feature.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rdimitrov
Copy link
Copy Markdown
Member Author

Both of Dan's points addressed in ef49684:

1. Terminology

You were right — "regenerate" was overloaded. The language now distinguishes:

  • sync — for release-asset downloads / file copies (swagger, CLI docs tarball, 4 core schemas). Nothing is recreated; we're just placing files.
  • regenerate — reserved for the toolhive CRD MDX step which truly transforms upstream manifests into our opinionated docs layout via extract-crd-schemas.mjs + generate-crd-pages.mjs.
  • refresh — for the combined commit that may do both.

Concretely, the auto-commit message is now Refresh reference assets for <project> <tag> and the step/body text reads "synced or regenerated from release assets" where both apply.

2. Gap attribution to PR authors

Good catch. The prompt to the skill now requires each gap bullet in GAPS.md to reference the PR number and @-mention the PR author (bots filtered out). Format:

- Feature X (PR #123 by @alice): needs a user story explaining who this is for and the expected consumer workflow.

So when a gap lands in the PR body, the engineer who built Feature X gets directly tagged rather than "someone from the reviewer pool." The skill already deep-dives PRs in Phase 2, so it has the attribution info at hand — no additional lookups needed.

Thanks for the review!

Simpler than adding a base_ref input: workflow_dispatch always runs
against `github.ref_name` (the branch passed to --ref). For
production, that's main. For pre-merge testing, dispatch from the
feature branch with `gh workflow run --ref feat/branch` and the
bootstrap flow branches from, bumps, and opens its PR against that
branch.

- Bootstrap checkout uses github.ref_name
- Bootstrap PR's --base uses github.ref_name
- eff step emits base_ref for detect-change.mjs to use as BASE_REF
  - pull_request trigger: event.pull_request.base.ref
  - workflow_dispatch retry: gh pr view <n> --json baseRefName
  - workflow_dispatch bootstrap: github.ref_name

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Labels were doing two jobs — neither worth the friction of pre-creating
the labels in every repo that adopts this:

  1. Gating which PRs trigger augmentation. Replaced with the existing
     pull_request paths: filter (only YAML edits) + user.login check
     (must be renovate[bot]). Human PRs editing the YAML are out of
     scope; they should be reviewed normally without skill augmentation.
  2. Human filtering of "failed" / "needs-context" PRs. Replaced with
     PR body sections and a failure-path PR comment that carries the
     run URL.

Changes:
- Drop labels from Renovate packageRule in renovate.json.
- Drop --label from bootstrap gh pr create.
- Drop "Add needs-human-context label" step (gaps already shown in PR
  body).
- Simplify failure step to comment-only; drop upstream-docs-failed
  label. The PR comment already includes the run URL + retry hint.
- Drop labeled trigger type; no longer needed without label-race
  concerns.
- Drop label check from workflow_dispatch retry validation.

Also unblocks the first real dispatch, which failed on
"upstream-content not found" since the label was never pre-created.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
rdimitrov and others added 2 commits April 21, 2026 22:05
The `./.github/actions/setup` composite starts with its own
actions/checkout that defaults to the dispatching ref, so calling it
after "Checkout PR branch" clobbers the PR-branch working tree with
the dispatching branch's content. detect-change.mjs then compared the
dispatching branch's YAML against itself and reported "No version
changes detected" — blocking the first dispatch.

Fix: inline the setup-node + cache + npm ci steps after the PR-branch
checkout instead of calling the composite. The composite is still
used in the bootstrap flow where re-checkout of the dispatching
branch is harmless.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Removed earlier as 'unused'. anthropics/claude-code-action@v1 needs
id-token: write to fetch an OIDC token. Skill step was failing with
"Could not fetch an OIDC token" on the first real dispatch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rdimitrov rdimitrov changed the title Draft: Automate upstream release docs PRs via Renovate Automate upstream release docs PRs via Renovate Apr 21, 2026
Comment thread renovate.json
"recreateWhen": "never",
"commitMessageTopic": "{{depName}}",
"prBodyNotes": [
"After this PR opens, `.github/workflows/upstream-release-docs.yml` adds source-verified content edits for the new release. For `stacklok/toolhive`, the same workflow also regenerates reference docs (CLI help, Swagger, CRD schemas)."
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

One remaining instance of "regenerates" (others were addressed), but non-blocking.

Comment thread renovate.json
"matchManagers": ["custom.regex"],
"matchFileNames": ["**/.github/upstream-projects.yaml"],
"schedule": ["at any time"],
"minimumReleaseAge": "24 hours",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Just noticed this...introducing a +24-hour drift off the bat seems undesirable. Can we drop to 0, or a few hours at most, 1-4 would still allow for a smoke-test window?

A delay is sensible for third-party libraries but these are first-party Stacklok releases. The cost of "docs PR opens for a release we later yanked" is just closing the PR, or a single revert PR if already merged.

@rdimitrov rdimitrov merged commit 99fd4f8 into main Apr 21, 2026
8 checks passed
@rdimitrov rdimitrov deleted the feat/upstream-release-docs branch April 21, 2026 19:45
rdimitrov added a commit that referenced this pull request Apr 21, 2026
…rding (#757)

* Address Dan's review feedback on #748

Two small follow-ups:

1. minimumReleaseAge: 24 hours -> 1 hour. Dan flagged that 24h is
   overcautious for first-party Stacklok releases. Renovate itself
   only runs every 4h so 1h is effectively close to 0 while still
   protecting against same-day yanks/reverts.

2. prBodyNotes: drop "regenerates" where we're actually just syncing.
   Now precisely: "syncs reference assets (CLI help, Swagger) and
   regenerates the CRD MDX pages" for toolhive.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Filter reviewers to repo collaborators only

Previous behavior pulled every non-bot commit author from the upstream
release range and passed them to `gh pr edit --add-reviewer` as a
single comma-separated list. GitHub rejects reviewer requests for
non-collaborators with 422, and because the API treats the list
atomically, one community contributor in the range would fail the
entire call and drop all valid reviewers with it.

Fix:
  - Probe each candidate with `gh api repos/<repo>/collaborators/<user>`
    before adding. 204 -> keep; 404 -> skip.
  - Emit a separate `skipped` output listing non-collaborator
    contributors so the PR body can acknowledge them by name
    ("Other release contributors ... Thanks for the contribution!")
    without actually requesting review from them.

Pre-existing bot-regex filter runs first so we don't waste API calls
on [bot] users.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Drop non-collaborator acknowledgment from PR body

Filtering out non-collaborator reviewers stays (prevents the 422
whole-call-failure). But mentioning them by name in the augmented PR
body adds notification surface we don't want. Silently skip.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

Automate upstream release docs via Renovate + upstream-release-docs skill

3 participants