diff --git a/.github/bump-callers/README.md b/.github/bump-callers/README.md index 1c4e1aa..7f22349 100644 --- a/.github/bump-callers/README.md +++ b/.github/bump-callers/README.md @@ -24,6 +24,7 @@ forward automatically instead of silently drifting commits behind. | Entrypoint | Triggers on a change to | Caller variable | Seeded | |---|---|---|---| | [`bump-cursor-review-callers.yml`](../workflows/bump-cursor-review-callers.yml) | `cursor-review.yml` or `cursor-review/**` | `CURSOR_REVIEW_CALLERS` | non-empty (hard-fails if empty) | +| [`bump-cursor-review-auto-label-callers.yml`](../workflows/bump-cursor-review-auto-label-callers.yml) | `cursor-review-auto-label.yml` | `CURSOR_REVIEW_AUTO_LABEL_CALLERS` | empty `[]` (register existing callers, then grows) | | [`bump-agents-md-callers.yml`](../workflows/bump-agents-md-callers.yml) | `agents-md-integrity.yml` or `agents-md-integrity/**` | `AGENTS_MD_CALLERS` | empty `[]` (grows as callers land) | | [`bump-pr-size-callers.yml`](../workflows/bump-pr-size-callers.yml) | `pr-size.yml` or `scripts/check-pr-size/**` | `PR_SIZE_CALLERS` | empty `[]` (grows as callers land) | | [`bump-assign-reviewers-callers.yml`](../workflows/bump-assign-reviewers-callers.yml) | `assign-reviewers.yml` | `ASSIGN_REVIEWERS_CALLERS` | empty `[]` (grows as callers land) | diff --git a/.github/bump-callers/bump-callers.sh b/.github/bump-callers/bump-callers.sh index d758184..4bf9dcf 100755 --- a/.github/bump-callers/bump-callers.sh +++ b/.github/bump-callers/bump-callers.sh @@ -4,10 +4,10 @@ # # When a reusable workflow (e.g. cursor-review.yml or agents-md-integrity.yml) # is updated on main, this opens a SHA-bump PR in every repo that pins a caller -# against it. It is fleet-agnostic: the thin workflow entrypoints -# (bump-cursor-review-callers.yml, bump-agents-md-callers.yml, -# bump-pr-size-callers.yml) invoke it with a different caller list, human tag, -# and reusable-workflow filename. There is ONE implementation so the fleets +# against it. It is fleet-agnostic: the thin workflow entrypoints (the +# bump-*-callers.yml workflows — see the fleet table in this directory's +# README) invoke it with a different caller list, human tag, and +# reusable-workflow filename. There is ONE implementation so the fleets # cannot drift apart (a forked copy is how other shared machinery in the org # has rotted); the entrypoints differ only in their path-filter triggers and # the parameters below. diff --git a/.github/bump-callers/tests/test_bump_callers.sh b/.github/bump-callers/tests/test_bump_callers.sh index ec6e980..0078b97 100755 --- a/.github/bump-callers/tests/test_bump_callers.sh +++ b/.github/bump-callers/tests/test_bump_callers.sh @@ -6,7 +6,8 @@ # scripts.yml / test-agents-md-integrity.yml lineage of guarding shared CI # machinery with a unit run on change — this drives the real script against a # stubbed `gh` and asserts the behavior that a consumer repo depends on: -# * BOTH caller variables (CURSOR_REVIEW_CALLERS + AGENTS_MD_CALLERS) parse, +# * each fleet's caller variable (CURSOR_REVIEW_CALLERS, +# CURSOR_REVIEW_AUTO_LABEL_CALLERS, AGENTS_MD_CALLERS, ...) parses, # * every private repo name is masked out of the public run logs, # * the caller's pinned SHA (and only it) is rewritten, the pin comment is # normalized, and the committed file keeps its single trailing newline, @@ -315,6 +316,45 @@ check "exit 0" "[[ $RC -eq 0 ]]" check "reported already at SHORT (+ wired)" "grep -q 'already at $SHORT' <<<\"\$OUT\"" check "committed nothing" "[[ ! -f \"\$STUB_PUT_DIR/count\" ]]" +echo "== cursor-review-auto-label fleet: two callers each get a SHA-bump PR (BE-4005) ==" +# The new fleet's exact entrypoint parameters (VAR_NAME/TAG/WORKFLOW_FILE, +# ALLOW_EMPTY=true), driven with two callers — mirroring the two consumers the +# variable is seeded with — so the bumper provably opens one SHA-bump PR per +# consumer instead of letting their auto-label callers drift behind the +# sibling ci-cursor-review.yml. +new_case autolabel +AL_FIXTURE="${WORK}/autolabel_caller.yml" +printf '%s\n' \ + 'name: CI - Cursor Review Auto-Label' \ + 'jobs:' \ + ' auto-label:' \ + ' uses: Comfy-Org/github-workflows/.github/workflows/cursor-review-auto-label.yml@3333333333333333333333333333333333333333 # github-workflows#44' \ + > "$AL_FIXTURE" +STUB_CONTENT_FILE="$AL_FIXTURE" run_bump \ + VAR_NAME=CURSOR_REVIEW_AUTO_LABEL_CALLERS TAG=cursor-review-auto-label WORKFLOW_FILE=cursor-review-auto-label.yml ALLOW_EMPTY=true \ + CALLERS_JSON='[{"repo":"Comfy-Org/secret-delta","file":".github/workflows/cursor-review-auto-label.yml","label":""},{"repo":"Comfy-Org/secret-epsilon","file":".github/workflows/cursor-review-auto-label.yml","label":""}]' +check "exit 0" "[[ $RC -eq 0 ]]" +check "masked caller delta" "grep -q '::add-mask::Comfy-Org/secret-delta' <<<\"\$OUT\"" +check "masked caller epsilon" "grep -q '::add-mask::Comfy-Org/secret-epsilon' <<<\"\$OUT\"" +check "committed both callers" "[[ \$(cat \"\$STUB_PUT_DIR/count\") -eq 2 ]]" +check "opened one PR per caller" "[[ \$(grep -c '^pr-create' \"\$STUB_PUT_DIR/pr.log\") -eq 2 ]]" +PUT="${STUB_PUT_DIR}/put.last.txt" +check "new SHA written" "grep -qF '$NEW_SHA' \"$PUT\"" +check "old pin removed" "! grep -qF '3333333333333333333333333333333333333333' \"$PUT\"" +check "pin comment normalized" "grep -qF '# github-workflows main ($SHORT)' \"$PUT\"" +check "reported fleet complete" "grep -q 'cursor-review-auto-label bump complete' <<<\"\$OUT\"" + +echo "== cursor-review-auto-label fleet: empty list is a clean no-op (ALLOW_EMPTY) ==" +# The variable is repo config the merge itself cannot create, so the fleet must +# no-op cleanly (not hard-fail) until it is seeded. +new_case autolabelempty +STUB_CONTENT_FILE="$AL_FIXTURE" run_bump \ + VAR_NAME=CURSOR_REVIEW_AUTO_LABEL_CALLERS TAG=cursor-review-auto-label WORKFLOW_FILE=cursor-review-auto-label.yml ALLOW_EMPTY=true \ + CALLERS_JSON='' +check "exit 0 on unseeded variable" "[[ $RC -eq 0 ]]" +check "logged no-op" "grep -q 'no callers yet' <<<\"\$OUT\"" +check "no commit made" "[[ ! -f \"\$STUB_PUT_DIR/count\" ]]" + echo "== agents-md fleet: two callers, two SHA refs, '# v1' preserved ==" new_case amd AMD_FIXTURE="${WORK}/amd_caller.yml" diff --git a/.github/workflows/bump-cursor-review-auto-label-callers.yml b/.github/workflows/bump-cursor-review-auto-label-callers.yml new file mode 100644 index 0000000..5959f29 --- /dev/null +++ b/.github/workflows/bump-cursor-review-auto-label-callers.yml @@ -0,0 +1,114 @@ +name: Bump cursor-review-auto-label callers + +# When the cursor-review-auto-label reusable workflow is updated on main, open +# a SHA-bump PR in every repo that pins a caller against it. PRs are opened by +# Cloud Code Bot so they are easy to filter and merge. +# +# This is a thin entrypoint over the shared bumper at +# .github/bump-callers/bump-callers.sh — the same script drives the +# cursor-review, agents-md-integrity, pr-size, AND assign-reviewers caller +# fleets (bump-cursor-review-callers.yml, bump-agents-md-callers.yml, +# bump-pr-size-callers.yml, bump-assign-reviewers-callers.yml). Keeping ONE +# implementation is deliberate: a forked copy is how other shared machinery in +# the org has drifted. The entrypoints differ only in their path-filter trigger +# and the parameters passed below. (They stay separate rather than a single +# matrix because their triggers differ — a cursor-review-auto-label.yml change +# must not spuriously bump the other fleets' callers, and vice versa. In +# particular, repos pinning BOTH cursor-review.yml and +# cursor-review-auto-label.yml get each caller bumped by its own fleet, so the +# two siblings stay in lock-step instead of the auto-label caller silently +# drifting behind.) +# +# The caller list is NOT hardcoded here. This repo is PUBLIC (workflow file and +# Actions run logs are both publicly viewable), and most callers are private, so +# their names must never appear in this file or its logs. The list lives in the +# repo-level Actions variable `CURSOR_REVIEW_AUTO_LABEL_CALLERS` (config, not a +# credential — a variable, not a secret, since secrets are write-only via the +# API) as a JSON array of {"repo","file","label"} objects, same shape as +# CURSOR_REVIEW_CALLERS. Every repo name is `::add-mask::`ed out of the (public) +# run logs before it is ever echoed. The variable is seeded EMPTY (`[]`) — an +# empty list is a clean no-op here (ALLOW_EMPTY below); existing consumers' +# auto-label callers are registered by editing the variable (see the update +# flow), and new entries are added as callers land. +# +# Update flow — adding/removing a caller needs NO public commit: +# gh variable set CURSOR_REVIEW_AUTO_LABEL_CALLERS --repo Comfy-Org/github-workflows \ +# --body "$(jq -c . callers.json)" +# Keep the canonical callers.json in a PRIVATE infra/ops repo so variable edits +# have a reviewed source of truth; the org audit log records each edit. (The +# specific home repo is intentionally not named here — this file is public.) + +on: + workflow_dispatch: {} # allow on-demand runs (e.g. to re-bump callers) + push: + branches: [main] + paths: + # cursor-review-auto-label.yml is entirely self-contained — its labeling + # logic runs inline via actions/github-script, with no external + # prompt/script asset dir (unlike cursor-review/** or + # scripts/check-pr-size/**). So the workflow file itself is the only path + # that can change its behavior. + - .github/workflows/cursor-review-auto-label.yml + +permissions: + contents: read + +# Serialize runs of this fleet. The bumper pushes to a STABLE branch +# (ci/bump-cursor-review-auto-label) shared across runs, so two overlapping +# runs (a rapid second main push, or a push racing a manual re-run) would +# force-reset that branch and race the PR update — an older run finishing last +# could leave the committed diff pinned to a stale SHA. cancel-in-progress: +# false lets the running bump finish; GitHub keeps only the newest pending run, +# so the latest SHA always wins (BE-3882). +concurrency: + group: bump-cursor-review-auto-label-callers + cancel-in-progress: false + +jobs: + bump: + # Guard against a workflow_dispatch run from a non-main ref: github.sha is + # the tip of whatever ref was selected, and the bumper force-resets a stable + # shared branch — a manual run from an older ref would pin every caller to a + # stale SHA (and run this job's script, with the App token minted below, + # from an unreviewed commit). The push trigger is already main-only, so this + # only ever skips stray manual runs. + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false + + - name: Generate Cloud Code Bot token + uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1.12.0 + id: token + with: + app-id: ${{ vars.APP_ID }} + private-key: ${{ secrets.CLOUD_CODE_BOT_PRIVATE_KEY }} + owner: Comfy-Org + + - name: Bump SHA in caller repos + env: + GH_TOKEN: ${{ steps.token.outputs.token }} + NEW_SHA: ${{ github.sha }} + VAR_NAME: CURSOR_REVIEW_AUTO_LABEL_CALLERS + TAG: cursor-review-auto-label + WORKFLOW_FILE: cursor-review-auto-label.yml + # Seeded empty; an empty list is a clean no-op, not an error (the + # variable is repo config the merge itself cannot create — see the + # header comment for the registration flow). + ALLOW_EMPTY: "true" + # JSON array of {"repo","file","label"} — see the header comment for + # the update flow. Kept in a variable (not the file) so private caller + # names never land in this public repo or its logs. + CALLERS_JSON: ${{ vars.CURSOR_REVIEW_AUTO_LABEL_CALLERS }} + run: | + # The push path filter also matches a commit that DELETES the + # reusable workflow; bumping callers to a SHA where the file is gone + # would break every caller. Deletion means decommissioning — no-op. + if [[ ! -f .github/workflows/cursor-review-auto-label.yml ]]; then + echo "cursor-review-auto-label.yml absent at this SHA — decommissioned; nothing to bump" + exit 0 + fi + bash .github/bump-callers/bump-callers.sh diff --git a/.github/workflows/test-bump-callers.yml b/.github/workflows/test-bump-callers.yml index d82e981..8fd0ffe 100644 --- a/.github/workflows/test-bump-callers.yml +++ b/.github/workflows/test-bump-callers.yml @@ -2,8 +2,8 @@ name: Test bump-callers script # Runs the functional tests + shellcheck for the shared caller-bump script # (.github/bump-callers/bump-callers.sh). That one script drives the SHA-bump -# fan-out for the cursor-review, agents-md-integrity, pr-size, AND -# assign-reviewers caller fleets, +# fan-out for the cursor-review, cursor-review-auto-label, agents-md-integrity, +# pr-size, AND assign-reviewers caller fleets, # so a regression here silently breaks every consumer repo's pin auto-bump (or, # worse, leaks a private caller name into this public repo's run logs) — cheap # to guard with a unit run on change. Mirrors test-cursor-review-scripts.yml / @@ -14,6 +14,7 @@ on: paths: - '.github/bump-callers/**' - '.github/workflows/bump-cursor-review-callers.yml' + - '.github/workflows/bump-cursor-review-auto-label-callers.yml' - '.github/workflows/bump-agents-md-callers.yml' - '.github/workflows/bump-pr-size-callers.yml' - '.github/workflows/bump-assign-reviewers-callers.yml' @@ -23,6 +24,7 @@ on: paths: - '.github/bump-callers/**' - '.github/workflows/bump-cursor-review-callers.yml' + - '.github/workflows/bump-cursor-review-auto-label-callers.yml' - '.github/workflows/bump-agents-md-callers.yml' - '.github/workflows/bump-pr-size-callers.yml' - '.github/workflows/bump-assign-reviewers-callers.yml' diff --git a/AGENTS.md b/AGENTS.md index 134ae61..21009f7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -78,9 +78,10 @@ tests — run the matching command above for whatever you touched. - `assign-reviewers.yml` — expertise-aware, load-balanced reviewer requests. - `assign-prs-to-author.yml` — assigns unassigned open PRs to their author. - `detect-unreviewed-merge.yml` — SOC 2: flags PRs merged without approval. -- `bump-cursor-review-callers.yml` / `bump-agents-md-callers.yml` / - `bump-pr-size-callers.yml` / `bump-assign-reviewers-callers.yml` — thin - entrypoints over `bump-callers.sh` that fan SHA bumps out to consumers. +- `bump-cursor-review-callers.yml` / `bump-cursor-review-auto-label-callers.yml` / + `bump-agents-md-callers.yml` / `bump-pr-size-callers.yml` / + `bump-assign-reviewers-callers.yml` — thin entrypoints over `bump-callers.sh` + that fan SHA bumps out to consumers. ## Conventions & gotchas