From 905c2d83b68962282d23a6e0818bc2548f1a1473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Mon, 13 Jul 2026 21:06:57 +0200 Subject: [PATCH 1/2] ci(dependabot): regenerate OpenSpec tool files on bump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extends the dependabot auto-fix workflow (formerly "Dependabot dedupe") to also run `openspec update --force`, so a @fission-ai/openspec bump regenerates the generated agent skills (.agents/skills/openspec-*) and opsx slash commands (.claude/commands/opsx/*) and pushes them back to the PR branch — the manual step that PR #567 had to do by hand for 1.2.0 -> 1.6.0. Kept as a single workflow (one checkout/commit/push) so the dedupe and openspec fixups don't race to push the same branch. The commit message names only the parts that actually changed; no-op when neither applies. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/dependabot-dedupe.yml | 66 ++++++++++++++++--------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/.github/workflows/dependabot-dedupe.yml b/.github/workflows/dependabot-dedupe.yml index de5e6c9..2bb3603 100644 --- a/.github/workflows/dependabot-dedupe.yml +++ b/.github/workflows/dependabot-dedupe.yml @@ -1,20 +1,28 @@ -name: Dependabot dedupe +name: Dependabot auto-fix -# Dependabot opens a PR after a bump, but `pnpm install` alone doesn't -# dedupe peer copies of packages (e.g. two versions of i18next, each -# holding their own singleton state). That split caused a hydration -# mismatch on #272 until a manual `pnpm dedupe` collapsed them. +# Post-processing that runs on every dependabot PR and pushes the result +# back to the PR branch. Two fixups, in one workflow so there is a single +# checkout / commit / push (two workflows racing to push the same branch +# would collide on a non-fast-forward): # -# This workflow fires on every dependabot PR, runs `pnpm dedupe`, and -# pushes the resulting lockfile update back to the PR branch so the -# subsequent CI run tests the deduped tree. +# 1. pnpm dedupe — `pnpm install` alone doesn't dedupe peer copies of a +# package (e.g. two versions of i18next, each holding their own +# singleton state). That split caused a hydration mismatch on #272 +# until a manual `pnpm dedupe` collapsed them. +# +# 2. openspec update — the OpenSpec agent skills (.agents/skills/openspec-*) +# and opsx slash commands (.claude/commands/opsx/*) are generated files +# stamped with the CLI version that produced them. When dependabot bumps +# @fission-ai/openspec they go stale until regenerated (see PR #567, +# which did the 1.2.0 -> 1.6.0 regen by hand). `openspec update --force` +# rewrites them to match the freshly-installed CLI. # # Requires `DEPENDABOT_DEDUPE_TOKEN` — a repo secret holding a # fine-grained PAT (or GitHub App token) with `contents: write` on # this repo. The default `GITHUB_TOKEN` would work for the push but # would NOT trigger a subsequent CI run on that push (GitHub's # anti-loop safeguard), leaving the PR with stale green CI from -# before the dedupe commit. A PAT re-triggers CI so the reviewer +# before the fixup commit. A PAT re-triggers CI so the reviewer # sees test results for the state they'd actually be merging. on: @@ -25,7 +33,7 @@ permissions: contents: write jobs: - dedupe: + autofix: if: github.actor == 'dependabot[bot]' runs-on: ubuntu-latest steps: @@ -35,7 +43,7 @@ jobs: run: | if [ -z "$TOKEN" ]; then echo "::error::DEPENDABOT_DEDUPE_TOKEN is not set. This workflow" - echo "::error::requires a PAT so the dedupe commit re-triggers CI." + echo "::error::requires a PAT so the fixup commit re-triggers CI." echo "::error::See .github/workflows/dependabot-dedupe.yml header." exit 1 fi @@ -46,7 +54,7 @@ jobs: # action (under $RUNNER_TEMP in recent versions) and made # available to subsequent git operations in this workspace — # so the later `git push` authenticates as the PAT, which is - # what gets CI to re-trigger on the dedupe commit. `true` is + # what gets CI to re-trigger on the fixup commit. `true` is # the checkout default; pinned explicitly here because it's # load-bearing for this workflow. token: ${{ secrets.DEPENDABOT_DEDUPE_TOKEN }} @@ -57,18 +65,30 @@ jobs: node-version: 24 cache: pnpm - run: pnpm install --frozen-lockfile=false - - run: pnpm dedupe - - name: Commit dedupe changes + - name: Dedupe lockfile + run: pnpm dedupe + - name: Regenerate OpenSpec tool files + # --force so the generated files always match the installed CLI, + # even if `update` would otherwise consider them up to date. No-op + # (no diff) when @fission-ai/openspec wasn't bumped in this PR. + run: pnpm exec openspec update --force + - name: Commit fixups env: GH_TOKEN: ${{ secrets.DEPENDABOT_DEDUPE_TOKEN }} run: | - if [ -n "$(git status --porcelain pnpm-lock.yaml)" ]; then - git config user.name "dependabot[bot]" - git config user.email "49699333+dependabot[bot]@users.noreply.github.com" - git add pnpm-lock.yaml - git commit -m "[github-actions] pnpm dedupe" - git push - echo "Deduped lockfile pushed." - else - echo "Lockfile already deduped." + git add pnpm-lock.yaml .agents/skills/openspec-* .claude/commands/opsx + if git diff --cached --quiet; then + echo "Nothing to fix up — lockfile deduped and OpenSpec files current." + exit 0 fi + # Build a message naming only the parts that actually changed. + parts="" + git diff --cached --name-only | grep -q '^pnpm-lock.yaml$' && parts="pnpm dedupe" + if git diff --cached --name-only | grep -qE '^(\.agents/skills/openspec-|\.claude/commands/opsx)'; then + parts="${parts:+$parts + }openspec update" + fi + git config user.name "dependabot[bot]" + git config user.email "49699333+dependabot[bot]@users.noreply.github.com" + git commit -m "[github-actions] $parts" + git push + echo "Pushed fixups: $parts" From fd80815119d5ea4bcc6098829f8a72ccaa7f4e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Mon, 13 Jul 2026 21:10:37 +0200 Subject: [PATCH 2/2] ci: rename workflow file to match its name (dependabot-auto-fix.yml) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The workflow was renamed "Dependabot dedupe" -> "Dependabot auto-fix" in the previous commit; rename the file to match and fix the self-reference in its error message. Safe — this workflow is not a required status check. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../{dependabot-dedupe.yml => dependabot-auto-fix.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{dependabot-dedupe.yml => dependabot-auto-fix.yml} (98%) diff --git a/.github/workflows/dependabot-dedupe.yml b/.github/workflows/dependabot-auto-fix.yml similarity index 98% rename from .github/workflows/dependabot-dedupe.yml rename to .github/workflows/dependabot-auto-fix.yml index 2bb3603..85e110f 100644 --- a/.github/workflows/dependabot-dedupe.yml +++ b/.github/workflows/dependabot-auto-fix.yml @@ -44,7 +44,7 @@ jobs: if [ -z "$TOKEN" ]; then echo "::error::DEPENDABOT_DEDUPE_TOKEN is not set. This workflow" echo "::error::requires a PAT so the fixup commit re-triggers CI." - echo "::error::See .github/workflows/dependabot-dedupe.yml header." + echo "::error::See .github/workflows/dependabot-auto-fix.yml header." exit 1 fi - uses: actions/checkout@v7