Skip to content

feat: bulk-install-claude-review.sh for smartwatermelon fleet - #69

Merged
twistedmelonman merged 5 commits into
mainfrom
feat/bulk-install-script
Apr 30, 2026
Merged

feat: bulk-install-claude-review.sh for smartwatermelon fleet#69
twistedmelonman merged 5 commits into
mainfrom
feat/bulk-install-script

Conversation

@twistedmelonman

Copy link
Copy Markdown
Member

Summary

Adds bulk-install-claude-review.sh at the repo root. Closes the workflow-templates gap for smartwatermelon, which is a user account — GitHub's workflow-templates/ picker is org-only, so the templates in smartwatermelon/.github/workflow-templates/ never appear in the picker UI for smartwatermelon/* repos. This script opens install/refresh PRs to roll the canonical caller stub across the fleet instead.

Behavior:

  • Dry-run by default; --apply opens PRs.
  • Classifies each repo: CURRENT / STALE / MISSING / CUSTOMIZED / LOCAL / ERROR.
  • Idempotent — re-running on a clean fleet produces no PRs.
  • Target version derived from the @v… pin in smartwatermelon/.github/workflow-templates/claude-blocking-review.yml. Bumping that template is the single fleet-wide trigger.
  • PR bodies carry [skip-claude-review: bulk-install] so the blocking-review workflow doesn't gate its own install/bump PR.

Live dry-run results against the smartwatermelon fleet right now:

Class Count Repos
CURRENT 14 (already at @v3.0.0)
STALE 4 ralph-burndown, mac-server-setup, scripts, projectinsomnia
MISSING 1 smartwatermelon/.github
LOCAL 1 github-workflows itself (self-review)

Two commits:

  1. Initial implementation
  2. Five fixes from code-reviewer's first pass: validate per-repo fetch, reorder customization check before pin check, tighten extract_pin regex against trailing punctuation, validate --only argument, exit non-zero on ERROR class.

Plan: docs/plans/2026-04-30-bulk-install-smartwatermelon-fleet.md.

Test plan

  • shellcheck -S info clean
  • Dry-run against full fleet correctly classifies all 20 repos
  • --only --apply (missing arg) errors out instead of silently iterating fleet
  • code-reviewer + adversarial-reviewer PASS on second commit
  • CI green
  • Manual --apply rollout still pending — bellwether 1-2 repos before fleet-wide

🤖 Generated with Claude Code

Claude Code Bot and others added 3 commits April 30, 2026 10:01
Closes the workflow-templates gap for the smartwatermelon user
account. Since GitHub's `workflow-templates/` picker is
organization-only, repos under `smartwatermelon` (a user
account) never see the org-default stub in their Actions UI.
The script opens install/refresh PRs to roll the canonical
caller stub across the fleet.

Behavior:
- Dry-run by default; --apply to actually open PRs.
- Classifies each repo: CURRENT / STALE / MISSING / CUSTOMIZED /
  LOCAL. CUSTOMIZED and LOCAL are skipped automatically.
- Idempotent: re-running on a clean fleet produces no PRs.
- Target version is derived from the @v… pin in
  smartwatermelon/.github/workflow-templates/claude-blocking-review.yml,
  so bumping that file is the single fleet-wide trigger.
- PRs carry the [skip-claude-review: bulk-install] tag so the
  blocking-review workflow doesn't gate its own install/bump PR.

Tested via dry-run against the live fleet:
- 14 CURRENT, 4 STALE (mix of @V3 floating and @v2.0.2),
  1 LOCAL (github-workflows itself), 1 MISSING (.github).

Plan: docs/plans/2026-04-30-bulk-install-smartwatermelon-fleet.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Five issues raised by code-reviewer on the prior commit:

1. Validate fetch_file output for the per-repo caller file
   (mirrors the canonical-fetch validation that already existed).
   Empty content now classifies as ERROR instead of falling
   through and misclassifying as "no @Version pin found".

2. Reorder customization check before pin comparison. Previously,
   a repo with caller-side customizations on a stale pin would
   get its pin sed-bumped without flagging the customizations.
   New behavior matches what the README claimed: any customized
   caller is skipped for human review regardless of pin status.

3. Tighten extract_pin regex from `[^[:space:]]+` to
   `[A-Za-z0-9._/-]+` so trailing punctuation (commas, quotes
   from quoted YAML values) doesn't get captured into the pin.
   Same fix applied to the canonical-version extraction.

4. Validate --only argument: error when missing or starts with
   `--`. Previously `./script --only --apply` would silently
   iterate every repo because ONLY="" fell through to the
   list-all-repos branch.

5. Exit non-zero when REPOS_ERROR is non-empty. Surfaces fetch
   failures to CI/cron/automation callers. CUSTOMIZED is
   intentionally not an error — it's a human-review signal.

README CUSTOMIZED row updated to reflect "regardless of pin"
behavior.

All verified via shellcheck -S info clean and live --dry-run
against the smartwatermelon fleet.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes #68. The `has_customization` regex used `\s` while the
rest of the script and `claude-review-audit.sh` consistently
use POSIX `[[:space:]]`. Replaced for portability and to match
the convention. Classification still produces identical results
on the live fleet.

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

claude Bot commented Apr 30, 2026

Copy link
Copy Markdown

<!-- claude-blocking-review sha=85e048f358fa640f52a66a2b8bdc7b54c8b0a529 run=25178990775 -->

This PR adds a new bulk-install-claude-review.sh utility script and README documentation. No changes to the claude-blocking-review.yml workflow itself.

Checked for: shell injection, hardcoded credentials, reliability regressions, data loss, silent async failures.

  • TARGET_VERSION is constrained to [A-Za-z0-9._/-]+ before interpolation into sed, so the |-delimited substitution is safe.
  • gh api results are passed as arguments, not eval'd.
  • No changes to the verdict file / comment parsing contract, allowed-tools, or escape-hatch grep logic.

VERDICT: PASS

Closes #66. TARGET_VERSION extraction skipped strip_comments
while extract_pin used it — inconsistent. A commented-out
@Version in the canonical stub could be picked up as the
target. No real-world hit (the canonical file has no such
comment), but the inconsistency is a footgun.

Hoists strip_comments to before the canonical-fetch block and
reuses it. Removes the duplicate definition from the helpers
section.

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

This comment has been minimized.

Two fixes from pre-push review:

Closes #71: command substitution \$() strips trailing newlines
from captured file content. Both CANONICAL_CONTENT and
current_content lose their trailing \n, so the PUT-uploaded
content was missing a final newline — every install/bump PR
would produce a file failing yamllint's
no-new-line-at-end-of-file rule. Same issue I just fixed in
smartwatermelon/.github PR #7. Fixed by switching the upload
encoder from `printf "%s"` to `printf "%s\n"`.

Closes #70: install branch was named `claude/install-blocking-
review` with no version suffix. If a re-run encountered an
already-open install PR, the git ref creation would fail.
Renamed to `claude/install-blocking-review-\${TARGET_VERSION}`
to match the bump-branch convention and let re-runs slide past
existing same-version PRs.

Issues #67, #72, #73 remain open as tracked tech-debt — they
are real but lower-priority edge cases that can be addressed
in follow-up PRs (mixed local/remote actions caller, transient
gh-API-failure misclassification, .github meta-repo opt-out).

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

claude Bot commented Apr 30, 2026

Copy link
Copy Markdown

<!-- claude-blocking-review sha=b741a56a9c15e754a888ca40fe58d713e6ba9476 run=25179472661 -->

No blocking issues found. The script constructs JSON via jq --arg (safe), restricts extracted version pins to [A-Za-z0-9._/-]+ (making the sed |-delimited substitution safe), and passes all PR bodies as flag arguments rather than through shell interpolation.

VERDICT: PASS

@claude

claude Bot commented Apr 30, 2026

Copy link
Copy Markdown

No blocking issues found. The PR adds a README section and a new bulk-install-claude-review.sh utility script with no changes to the existing claude-blocking-review.yml workflow.

  • Shell injection: TARGET_VERSION is constrained to [A-Za-z0-9._/-]+ before sed interpolation; jq -n --arg escapes all repo-derived values into JSON payloads.
  • GitHub API update calls include correct blob SHAs; branch collisions fail loudly.
  • No hardcoded credentials; no changes to the blocking-review workflow contract.

VERDICT: PASS

@twistedmelonman
twistedmelonman merged commit 0f263f9 into main Apr 30, 2026
3 checks passed
@twistedmelonman
twistedmelonman deleted the feat/bulk-install-script branch August 8, 2026 01:12
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.

1 participant