chore: cascade Dependabot PR hygiene (PR template + auto-CHANGELOG workflow)#96
Conversation
…rkflow) Mirrors the dependabot-pr-hygiene playbook landed in cmeans/mcp-synology (PR #58) and cmeans/pypi-winnow-downloads (PR #25), adapted for this repo's existing conventions: - `.github/PULL_REQUEST_TEMPLATE.md` — Summary / Test plan / CHANGELOG scaffold for human contributors. Test plan items match this repo's CI commands (`pytest`, `ruff check`, `ruff format --check`, `mypy src/mcp_clipboard/`). Dependabot bypasses the template. - `.github/workflows/dependabot-changelog.yml` — pull_request_target workflow filtered to `dependabot[bot]`. Mints a GitHub App installation token (so commits attribute to cmeans-claude-dev[bot] and would re-fire required pull_request workflows under any future ruleset change), runs dependabot/fetch-metadata at v3.1.0 (which fixed empty prevVersion/newVersion on grouped PRs), and prepends an Unreleased → Changed entry. Tolerant of both `## Unreleased` and `## [Unreleased]` heading forms; defaults to brackets on creation to match this repo's existing CHANGELOG style. Subsection insertion respects Keep-a-Changelog v1.1.0 ordering. - `CLAUDE.md § Conventions` — documents the per-PR CHANGELOG rule and the Keep-a-Changelog category set, parity with mcp-synology and pypi-winnow-downloads. Operator action required before the workflow can run: configure repo secrets `BOT_APP_ID` (numeric, 3223881 for cmeans-claude-dev) and `BOT_APP_PRIVATE_KEY` (full PEM contents). Without those secrets the App-token mint step fails fast and Dependabot PRs land without an auto-CHANGELOG entry; the maintainer would have to add one manually. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
cmeans
left a comment
There was a problem hiding this comment.
QA Review — Round 1 (cascade workflow)
Head 710cb4f. 4 files / +289/0: PR template, dependabot-changelog workflow, CLAUDE.md Conventions section, CHANGELOG entry.
Playbook conformance
Cross-referenced against the dependabot-pr-hygiene playbook (mcp-synology #58 → pypi-winnow-downloads #25):
| Playbook requirement | Verified |
|---|---|
pull_request_target trigger |
✅ line 33 |
Job filtered to dependabot[bot] |
✅ line 42 |
App-token auth (NOT secrets.GITHUB_TOKEN) |
✅ line 47 |
Workflow permissions: scoped to contents: read + pull-requests: read (App token does the writes) |
✅ lines 36–38 |
| Loop guard — skip if last commit is by the bot | ✅ lines 65–68 |
Idempotency guard — skip if (#N) already in CHANGELOG |
✅ lines 70–72 |
Group preference — dependency-group first, fall back to package-ecosystem |
✅ lines 104–106 |
| Bot identity uses numeric user id, not App ID | ✅ GH_BOT_USER_ID: '272174644' (line 201, 213); verified live: gh api 'users/cmeans-claude-dev%5Bbot%5D' returns id: 272174644, type: Bot |
fetch-metadata v3.1.0 (post-grouped-PR-empty-versions fix) |
✅ line 80 |
Heading matcher tolerates both ## Unreleased and ## [Unreleased] |
✅ lines 143, 145 |
Keep-a-Changelog v1.1.0 ordering on fresh ### Changed creation |
✅ lines 183–188 (fix for the issue #26 dormant ordering bug) |
SHA pins — independently verified against upstream tags via gh api /repos/.../git/refs/tags/...
| Action | Pin in workflow | Upstream v?.?.? resolves to |
|---|---|---|
actions/create-github-app-token@v3.1.1 |
1b10c78c7865c340bc4f6099eb2f838309f1e8c3 |
✅ exact match |
actions/checkout@v6.0.2 |
de0fac2e4500dabe0009e67214ff5f5447ce83dd |
✅ exact match |
dependabot/fetch-metadata@v3.1.0 |
25dd0e34f4fe68f24cc83900b1fe3fe149efef98 |
✅ exact match |
Algorithm dry-run (against this branch's CHANGELOG.md, simulating PR #95 metadata)
Ran the workflow's inline Python locally with a synthetic DEPS_JSON for the codecov-action 5→6 bump. Took the existing-### Changed branch (idx 42), inserted at line 43:
### Changed
- **Bump github-actions group: codecov/codecov-action 5→6** (#95)
- Add `workflow_dispatch:` trigger to `pr-labels-ci.yml` ...
Newest entry at top of ### Changed, existing entries preserved, no formatting damage. Algorithm produces the expected entry shape end-to-end.
Other verification
| Check | Result |
|---|---|
python3 -c "import yaml; yaml.safe_load(open('.github/workflows/dependabot-changelog.yml'))" |
clean; triggers: ['pull_request_target']; permissions: {'contents': 'read', 'pull-requests': 'read'} |
uv run pytest -q |
488 passed, 6 deselected, 5 xfailed |
uv run ruff check src/ tests/ |
clean |
uv run mypy src/ |
clean |
PR template Test plan commands match ci.yml exactly |
✅ uv run pytest, ruff check src/ tests/, ruff format --check src/ tests/, mypy src/mcp_clipboard/ (matches ci.yml:25, :28, :45) |
CHANGELOG entry on this PR (under ### Added) |
✅ multi-bullet, accurately describes all three artifacts |
CLAUDE.md ## Conventions mirrors mcp-synology pattern |
✅ per-PR rule + Keep-a-Changelog category set + Dependabot exemption explanation |
CI rollup on 710cb4f |
all SUCCESS (lint / typecheck / test 3.11–3.13 / on-push / qa-approved / codecov-patch) |
Test plan
Items 1–5 are all post-merge — none pre-merge testable.
Verdict
Ready for QA Signoff. Zero open findings. The workflow is a faithful, exact port of the playbook with all five known footguns handled (App-token vs GITHUB_TOKEN, numeric bot user id, fetch-metadata v3.1.0, Keep-a-Changelog ordering on fresh subsections, dual heading-format support). SHA pins and bot identity verified live against upstream and GitHub API.
After merge, the unblock sequence for end-to-end cascade validation:
- Configure repo secrets
BOT_APP_IDandBOT_APP_PRIVATE_KEYoncmeans/mcp-clipboard. - You post
@dependabot recreateon PR #95 (not me — bot-posted Dependabot slash-commands are silently ignored, per the dependabot-recreate-no-bot-posts rule). - Recreated #95 will trigger this workflow on its first synchronize event; expect a follow-up commit by
cmeans-claude-dev[bot]titledchore(changelog): record dep bumps from #95, with a### Changedentry of the form- **Bump github-actions group: codecov/codecov-action 5→6** (#95). - After that's observed, mcp-clipboard joins mcp-synology and pypi-winnow-downloads as a fully-validated cascade target.
|
Applying Ready for QA Signoff as the final act of round 1: zero findings, full playbook conformance, all 3 SHA pins independently verified against upstream tags, bot user id verified live (272174644), algorithm dry-run produces correct entry shape against this branch's CHANGELOG, all CI green on |
…plate) Cascades the post-mcp-synology#63 Dependabot-PR-hygiene playbook from the validated cmeans/mcp-clipboard#96 rollout. Five files: - .github/dependabot.yml — pip + github-actions ecosystems, weekly Monday 06:00 America/Chicago, grouped per ecosystem, `chore` prefix with `include: scope` (canonical title shape `chore(deps): bump foo`; doubling to `chore(deps)` would yield `chore(deps)(deps):`). No docker ecosystem because this repo has no Dockerfile. - .github/workflows/dependabot-changelog.yml — `pull_request_target` workflow filtered to `dependabot[bot]` that prepends a Keep-a-Changelog-ordered entry under `[Unreleased] / Changed`. Authenticated via a GitHub App installation token (`actions/create-github-app-token@v3.1.1`, SHA `1b10c78c7865c340bc4f6099eb2f838309f1e8c3`) so the bot's follow-up commit re-fires the QA-Gate-required CI checks (test ubuntu / test macos / smoke-macos). `GITHUB_TOKEN`-authored pushes do NOT trigger downstream `pull_request` workflows (GitHub anti-loop policy), which would block merge under the main-protection ruleset. Uses `dependabot/fetch-metadata@v3.1.0` (SHA `25dd0e34f4fe68f24cc83900b1fe3fe149efef98`) — v2 returns empty `prevVersion`/`newVersion` strings on grouped PRs. Loop guard skips when last commit author is the bot; idempotency guard skips when `(#N)` is already present in CHANGELOG.md. Commits with NUMERIC user id `272174644` in noreply email format (not APP_ID `3223881` — APP_ID breaks `require_last_push_approval` ruleset commit attribution). Includes the post-`mcp-synology#63` Keep-a-Changelog ordering fix in the create-`### Changed`-from-scratch path. - .github/PULL_REQUEST_TEMPLATE.md — auto-fills human-authored PR bodies with Summary / Test plan / CHANGELOG checklist using this repo's commands (`.venv/bin/python -m pytest`, `ruff check`, `bash scripts/smoke-test.sh`). Dependabot bypasses templates and supplies its own body, which is why the workflow above exists. - .github/labels.yml — adds `python` (color 3572A5, linguist Python) and `github-actions` (color 2088FF, GitHub Actions blue) so the Dependabot grouped PRs get their domain labels at open time. Sync via .github/workflows/sync-labels.yml on push to main. - CHANGELOG.md — Unreleased / Added entry recording the change. Operator prereqs: `BOT_APP_ID` and `BOT_APP_PRIVATE_KEY` repo secrets configured (confirmed in-place); GitHub App installed on the repo with `contents:write` and `pull-requests:read`. SHA pins on all three third-party actions verified exact match upstream tags via `gh api repos/<owner>/<repo>/git/refs/tags/v<X>`. Bot user id 272174644 verified via `gh api 'users/cmeans-claude-dev%5Bbot%5D'`. Workflow's CHANGELOG insertion logic dry-run on this repo's current `[Unreleased]` (which has `### Changed` already) produces correct output. YAML parses on all three YAML files; Python heredoc in the compose step parses cleanly. 485 tests pass; ruff clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…plate) (#54) Cascades the post-`mcp-synology#63` Dependabot-PR-hygiene playbook from the validated `cmeans/mcp-clipboard#96` rollout. Five files: `.github/dependabot.yml` (pip + github-actions, weekly Mon 06:00 CT, grouped, `chore` prefix with `include: scope` to avoid the `chore(deps)(deps):` doubled-prefix bug), `.github/workflows/dependabot-changelog.yml` (`pull_request_target` filtered to `dependabot[bot]`, App-token-authed so the bot's commit re-fires QA-Gate-required CI checks, includes the post-#63 Keep-a-Changelog ordering fix in the create-`### Changed`-from-scratch path), `.github/PULL_REQUEST_TEMPLATE.md` (humans only — Dependabot bypasses templates), `.github/labels.yml` adds `python` + `github-actions`, and a `CHANGELOG.md` Unreleased / Added entry. Operator prereqs `BOT_APP_ID` + `BOT_APP_PRIVATE_KEY` confirmed in-place. SHA pins on all three third-party actions verified exact match upstream tags. Bot user id `272174644` verified via `gh api 'users/cmeans-claude-dev[bot]'`. Workflow's CHANGELOG insertion logic dry-run on this repo's current `[Unreleased]` (which has `### Changed` already) produces correct output. The naive simple `dependabot.yml` alone would break here because of the strict CHANGELOG-per-PR rule + required CI checks + QA-Gate ruleset combination — Dependabot PRs would QA-fail for missing CHANGELOG, and `GITHUB_TOKEN`-authored auto-fix pushes would not re-fire the required checks. The full playbook handles all three. Notes: this PR sits behind PRs #50, #52, #53 in the queue. Once it lands on main, `sync-labels.yml` runs and creates the two new labels before next Monday's Dependabot schedule fires. Dormant Gotcha 6 (Keep-a-Changelog subsection ordering bug from `mcp-synology#63`) is fixed in the workflow but won't fire on yt-dont-recommend's current `[Unreleased]` layout (which already has `### Changed`). It activates after the next release cuts a fresh empty `[Unreleased]` and a feature PR adds `### Added` before any Dependabot bump. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bump pyproject.toml 2.2.1 -> 2.3.0 and convert the [Unreleased] block into [2.3.0] - 2026-05-02. A fresh empty [Unreleased] section sits above for the next cycle. 13 PRs aggregated since v2.2.1: #88, #92, #93, #94, #95, #96, #98, #99, #100, #101, #102, #103, #104. Tag-push (v2.3.0) after merge triggers .github/workflows/publish.yml. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Cascades the dependabot-pr-hygiene playbook from
cmeans/mcp-synology(PR #58) andcmeans/pypi-winnow-downloads(PR #25) onto this repo, completing parity with the other two repos in the cascade. Builds on PR #94, which landed.github/dependabot.yml.What's added
.github/PULL_REQUEST_TEMPLATE.md— auto-fills new human-authored PR bodies with Summary, Test plan, and CHANGELOG sections. Test plan items match this repo's CI commands exactly (uv run pytest,uv run ruff check src/ tests/,uv run ruff format --check src/ tests/,uv run mypy src/mcp_clipboard/). Dependabot bypasses the template..github/workflows/dependabot-changelog.yml—pull_request_targetworkflow filtered todependabot[bot]. Mints a GitHub App installation token (so commits attribute correctly and would re-fire requiredpull_requestworkflows under any future ruleset change), runsdependabot/fetch-metadata@v3.1.0(the v3 line fixed emptyprevVersion/newVersionon grouped PRs, per the playbook's Gotcha 3), and prepends an## [Unreleased]→### Changedentry toCHANGELOG.md. Includes the post-Date inference uses exception-driven parsing for every cell #26 fix: subsection creation respects Keep-a-Changelog v1.1.0 ordering (Added → Changed → Deprecated → Removed → Fixed → Security) so a freshly-created### Changedlands in the right position. Tolerant of both## Unreleasedand## [Unreleased]heading forms; defaults to brackets on creation to match this repo's existing style.CLAUDE.md § Conventions— documents the per-PR CHANGELOG rule and the Keep-a-Changelog category set (Added/Changed/Fixed), mirroring mcp-synology's CLAUDE.md.Operator action required
Before the workflow can run, configure two repo secrets on
cmeans/mcp-clipboard:BOT_APP_ID— numeric3223881BOT_APP_PRIVATE_KEY— full PEM contentsWithout those secrets the App-token mint step fails fast and Dependabot PRs land without an auto-CHANGELOG entry. Dependabot's first scheduled run is Monday 06:00 America/Chicago, so there is time after merge to configure secrets.
Notes vs the other repos in the cascade
## [Unreleased](with brackets); mcp-synology uses## Unreleased(no brackets). The workflow's heading matcher accepts either form (same as pypi-winnow-downloads' adapted version) and preserves whichever it found.mainruleset does not currently require status checks, so the App-token mechanism is technically optional here —secrets.GITHUB_TOKENwould be sufficient. App-token is kept anyway for parity, correct bot attribution, and forward-compatibility with any future ruleset tightening.Test plan
BOT_APP_ID+BOT_APP_PRIVATE_KEYrepo secrets.github/workflows/dependabot-changelog.ymlshows up in Actions tab@dependabot recreatean earlier one once it exists), confirm the auto-CHANGELOG commit lands attributed tocmeans-claude-dev[bot]with subjectchore(changelog): record dep bumps from #N### Changedwith correct version arrows (e.g.,actions/checkout 4→6)