diff --git a/.github/workflows/initiative-driver.yml b/.github/workflows/initiative-driver.yml index 0150fdde0..53359d3c3 100644 --- a/.github/workflows/initiative-driver.yml +++ b/.github/workflows/initiative-driver.yml @@ -28,6 +28,10 @@ on: - cron: "23 */6 * * *" # safety net for missed close events workflow_dispatch: inputs: + target_repo: + description: "Target repo (owner/repo) to sweep + release stories FOR. Empty => this repo (the dogfood/self path)." + required: false + default: "" epic: description: "Epic issue number to drive (blank = sweep all initiative:auto epics)" required: false @@ -45,13 +49,17 @@ permissions: contents: read # actions/checkout; all issue mutations use the PAT (GH_TOKEN) concurrency: - # One global lane: sweeps and close events serialize so concurrent runs cannot - # race on label application. cancel-in-progress=false so queued work is not dropped. - group: initiative-driver + # One lane PER TARGET REPO: sweeps and close events for the same repo serialize + # so concurrent runs cannot race on label application, while sweeps of different + # enrolled repos no longer queue behind a single global lane. Keying mirrors + # initiative-planner.yml's per-target keying. cancel-in-progress=false so queued + # work is not dropped. + group: initiative-driver-${{ github.event.inputs.target_repo || github.repository }} cancel-in-progress: false env: - REPO: ${{ github.repository }} + # REPO is the TARGET repo to sweep; empty target_repo => this repo (self/dogfood). + REPO: ${{ github.event.inputs.target_repo || github.repository }} # Single-epic only when explicitly dispatched with a number; otherwise blank ⇒ sweep. EPIC: ${{ github.event.inputs.epic || '' }} # CLOSED_ISSUE is only meaningful on a close event — never pass the labeled diff --git a/tests/test_initiative_driver.bats b/tests/test_initiative_driver.bats index e9c1660e4..9e36329ab 100644 --- a/tests/test_initiative_driver.bats +++ b/tests/test_initiative_driver.bats @@ -237,3 +237,46 @@ EOF [[ "$output" == *"No open epics carry"* ]] ! grep -qF "issue edit" "$GH_LOG" } + +# ── cross-repo: a non-self target_repo sweep targets that repo on every call ─── +# Mirrors the workflow's REPO = target_repo || github.repository plumbing: when +# the central driver is dispatched with REPO=, every gh call — the +# epic discovery, gate read, sub_issues/blocked_by reads, and the release +# `gh issue edit --repo ` — must be repo-qualified to that repo so +# cross-repo dev-lead labeling lands in the target, not in .github-private. + +@test "cross-repo: a non-self target_repo sweep targets that repo on every API and label call" { + export EPIC="" + export REPO="other/repo" + cat > "$MOCK_BIN/gh" <<'EOF' +#!/usr/bin/env bash +printf '%s\n' "$*" >> "$GH_LOG" +args="$*" +# Discovery query against the TARGET repo: one gated epic 10 +if [[ "$args" == *"repos/other/repo/issues -f state=open"* ]]; then printf '10'; exit 0; fi +# Epic 10 (in the target repo) carries the gate label +if [[ "$args" == *"repos/other/repo/issues/10 --jq"* ]]; then printf 'initiative:auto'; exit 0; fi +# Sub-issues of epic 10 in the target repo: one open child, issue 2 +if [[ "$args" == *"repos/other/repo/issues/10/sub_issues"* ]]; then printf '2'; exit 0; fi +# Issue 2 has no dev-lead yet +if [[ "$args" == *"repos/other/repo/issues/2 --jq"* ]]; then printf ''; exit 0; fi +# Issue 2 has no open blockers +if [[ "$args" == *"repos/other/repo/issues/2/dependencies/blocked_by"* ]]; then printf ''; exit 0; fi +# Label application succeeds +if [[ "$args" == "issue edit"* ]]; then exit 0; fi +printf '[]' +EOF + chmod +x "$MOCK_BIN/gh" + + run bash "$SCRIPT" + [ "$status" -eq 0 ] + [[ "$output" == *"Found 1 gated epic(s): 10"* ]] + [[ "$output" == *"RELEASED"* ]] + # Every repo-qualified read flowed through the target repo… + grep -qF "repos/other/repo/issues -f state=open" "$GH_LOG" + grep -qF "repos/other/repo/issues/10/sub_issues" "$GH_LOG" + grep -qF "repos/other/repo/issues/2/dependencies/blocked_by" "$GH_LOG" + # …and the release labeled the sub-issue in the target repo, not self. + grep -qF "issue edit 2 --repo other/repo --add-label dev-lead" "$GH_LOG" + ! grep -qF "petry-projects/.github-private" "$GH_LOG" +}