diff --git a/.github/workflows/upgrade-check.yml b/.github/workflows/upgrade-check.yml index 91320f5..0b61aed 100644 --- a/.github/workflows/upgrade-check.yml +++ b/.github/workflows/upgrade-check.yml @@ -1,16 +1,13 @@ -# Reusable consumer upgrade radar — the things a consuming repo owns that -# Dependabot can't bump, each in its own reviewed PR: +# Reusable consumer upgrade radar — things a consuming repo owns that its +# updater doesn't cover here, each in its own reviewed PR: # flutter-sdk — the Flutter SDK pin (.fvmrc + example/.fvmrc) → latest stable. # lockfiles — pubspec.lock files refreshed to latest in-range. -# whuppi-ci-refs — every `whuppi/ci/...@vX.Y.Z` ref across .github (workflows -# AND vendored composite action.yml) → the latest whuppi/ci -# release, in one sweep. Dependabot never touches refs inside -# composite actions (dependabot/dependabot-core#6704), so a -# grouped bump splits the pin and the pin-availability gate -# rejects it — this keeps every ref on one version. -# The shared tool/binary pins (fvm, Chrome, bore, zizmor, actionlint) that -# whuppi/ci bakes into its actions reach this repo the same way — through the -# whuppi/ci ref bump above; whuppi/ci owns their versions via self-upgrade.yml. +# whuppi/ci refs (workflows AND composite action.yml) are bumped by Renovate +# (renovate.yml) — it reads composite action.yml, which Dependabot can't +# (dependabot/dependabot-core#6704). The shared tool/binary pins (fvm, Chrome, +# bore, zizmor, actionlint) reach consumers through a whuppi/ci release + +# Renovate bumping the whuppi/ci refs; whuppi/ci owns their versions via +# self-upgrade.yml. name: Upgrade Check on: @@ -211,119 +208,3 @@ jobs: else gh pr edit "$EXISTING_PR" --title "chore: refresh lockfiles" --body "$PR_BODY" fi - - # ── whuppi/ci refs (workflows + vendored composite actions) ────── - # Dependabot can't bump whuppi/ci refs that live inside composite action.yml - # files (dependabot/dependabot-core#6704), so a grouped bump moves only the - # workflow-level refs and splits the pin — which pin-availability then rejects. - # This sweeps EVERY versioned whuppi/ci ref, workflow and composite alike, to - # the latest release in one PR. Consumers drop whuppi/ci from their Dependabot - # group; this owns it instead. - whuppi-ci-refs: - name: whuppi/ci refs - runs-on: ${{ inputs.runner }} - timeout-minutes: 15 - permissions: - contents: write # pushes the chore/whuppi-ci-refs branch - pull-requests: write # opens / edits the PR - steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - ref: ${{ inputs.branch }} - persist-credentials: false - - - name: Prepare branch - id: branch - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - gh auth setup-git - gh label create upgrade-ci-refs --description "Auto: whuppi/ci ref bump" --color "1d76db" 2>/dev/null || true - EXISTING_PR=$(gh pr list --label upgrade-ci-refs --state open --json number --jq '.[0].number // empty') - echo "existing_pr=$EXISTING_PR" >> "$GITHUB_OUTPUT" - if [ -n "$EXISTING_PR" ]; then - git fetch origin chore/whuppi-ci-refs 2>/dev/null || true - git checkout -B chore/whuppi-ci-refs origin/chore/whuppi-ci-refs 2>/dev/null || git checkout -b chore/whuppi-ci-refs - else - git checkout -b chore/whuppi-ci-refs - fi - - - name: Sweep every whuppi/ci ref to the latest release - id: sweep - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - set -euo pipefail - latest="$(gh api repos/whuppi/ci/releases/latest --jq '.tag_name' 2>/dev/null || true)" - # latest is interpolated into the sed below — reject anything but an - # exact vX.Y.Z tag, or a crafted release name becomes sed injection. - if ! printf '%s' "$latest" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then - echo "::error::implausible whuppi/ci release tag: '$latest'" >&2 - exit 1 - fi - # Every .github file pinning a whuppi/ci ref to a version tag — - # workflows AND composite action.yml. `@main` refs (intentionally - # floating) carry no @v and are left untouched. - # Fill the array the bash-3.2-portable way (macOS ships that bash). - files=() - while IFS= read -r f; do files+=("$f"); done \ - < <(grep -rlE 'whuppi/ci/[^@[:space:]]*@v[0-9.]+' .github || true) - if [ ${#files[@]} -eq 0 ]; then - echo "No versioned whuppi/ci refs found — nothing to sweep." - exit 0 - fi - for f in "${files[@]}"; do - sed -i.bak -E "s#(whuppi/ci/[^@[:space:]]*)@v[0-9.]+#\1@${latest}#g" "$f" - rm -f "$f.bak" - done - # Hand the exact rewritten paths to the commit step so it stages only - # those, matching the sibling jobs' targeted add (never a blanket add). - { - echo "files<> "$GITHUB_OUTPUT" - echo "swept ${#files[@]} file(s) → $latest" - - - name: Commit + open or update the PR - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - EXISTING_PR: ${{ steps.branch.outputs.existing_pr }} - BASE: ${{ inputs.branch }} - SWEPT_FILES: ${{ steps.sweep.outputs.files }} - run: | - # Stage only the files the sweep rewrote — never a blanket `git add`. - printf '%s\n' "$SWEPT_FILES" | while IFS= read -r f; do - [ -n "$f" ] && git add -- "$f" - done - git commit -m "ci: bump whuppi/ci refs to latest" || { - echo "whuppi/ci refs already current — nothing to bump." - exit 0 - } - if [ -n "$EXISTING_PR" ]; then - git push origin chore/whuppi-ci-refs - else - git push --force origin chore/whuppi-ci-refs - fi - - PR_BODY="$(cat <<'EOF' - Bumps every `whuppi/ci/...@vX.Y.Z` reference across `.github` — workflows - AND vendored composite actions — to the latest whuppi/ci release, in one - sweep, so the pin stays uniform. Dependabot can't do this: it never - touches refs inside composite `action.yml` (dependabot/dependabot-core#6704), - so its grouped bump splits the pin and pin-availability rejects it. - - Add `ready-to-test` for the full cross-target run, then merge once green. - - _Auto-generated by upgrade-check.yml_ - EOF - )" - - if [ -z "$EXISTING_PR" ]; then - gh pr create --base "$BASE" --head chore/whuppi-ci-refs \ - --title "ci: bump whuppi/ci refs to latest" --label upgrade-ci-refs --draft --body "$PR_BODY" - else - gh pr edit "$EXISTING_PR" --title "ci: bump whuppi/ci refs to latest" --body "$PR_BODY" - fi diff --git a/CHANGELOG.md b/CHANGELOG.md index 8edf160..5188b82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,22 @@ Releases are cut from the top heading here by `self-release.yml`; consumers pin an exact version and upgrade through grouped Dependabot PRs. Versioning rules live in the README. Newest first. +## 2.2.0 + +- Added a reusable `renovate.yml` — self-hosted Renovate that each consumer calls + from a thin wrapper (same shape as `upgrade-check.yml`), running against the + calling repo. It reads composite `action.yml` + ([dependabot-core#6704](https://github.com/dependabot/dependabot-core/issues/6704) + blind spot), so it keeps whuppi/ci refs uniform and bumps third-party actions + hidden in composites. Needs a `RENOVATE_TOKEN` org secret (Contents + Workflows + + Pull-requests + Issues: write) — Renovate must write `.github/workflows/`, which + `GITHUB_TOKEN` can't. +- `secrets.sh` gained an `org` scope for org-wide secrets (`set org/KEY`). +- Removed the `whuppi-ci-refs` job from `upgrade-check.yml`. Renovate replaces it: + the sweep needed a Workflows-scope token `GITHUB_TOKEN` couldn't provide, and + Renovate reads composites natively. Consumers migrate to the `renovate.yml` + wrapper and drop their Dependabot `github-actions` + `pub` config. + ## 2.1.0 - Added a `whuppi-ci-refs` job to the reusable `upgrade-check.yml`. It sweeps diff --git a/docs/UPDATING.md b/docs/UPDATING.md index 35832ea..4098773 100644 --- a/docs/UPDATING.md +++ b/docs/UPDATING.md @@ -11,22 +11,21 @@ consumer onboarding. | Thing | Bumped by | You do | |---|---|---| | Tool/binary pins (`tool/versions.env`) | `self-upgrade.yml` daily PR | Review the hashes, merge, cut a release | -| Third-party action SHAs (workflow files) | Dependabot (7-day cooldown) | Review, merge, cut a release | -| Consumers' Flutter SDK + lockfiles | reusable `upgrade-check.yml` in each consumer | Nothing here | -| Consumers' whuppi/ci pins | reusable `upgrade-check.yml` → `whuppi-ci-refs` job — sweeps every ref (workflow **and** composite) to the latest release | Cut the release; consumers sweep to it automatically | +| Consumer deps + every action `uses:` ref — pub, **and workflows AND composite `action.yml`** (third-party + whuppi/ci) | **Renovate** (`renovate.yml` reusable, one thin wrapper per consumer) | Review + merge the bump PRs it opens | +| Consumers' Flutter SDK + lockfiles, pre-Renovate | reusable `upgrade-check.yml` — for consumers not yet migrated to Renovate | Nothing here | -**Why the whuppi/ci sweep isn't Dependabot's job.** Dependabot's github-actions -updater never touches `uses:` refs inside composite `action.yml` +**Why Renovate, not Dependabot.** Dependabot's github-actions updater never reads +`uses:` refs inside composite `action.yml` ([dependabot/dependabot-core#6704](https://github.com/dependabot/dependabot-core/issues/6704), -open). A consumer's vendored `make-target/action.yml` pins the whuppi/ci -capability refs there, so a grouped Dependabot bump moves only the workflow-level -refs and splits the pin — which the `pin-availability` gate then rejects. The -`whuppi-ci-refs` job `sed`-sweeps every versioned whuppi/ci ref, workflow and -composite alike, to the latest release, keeping the pin uniform by construction. -Consumers therefore drop `whuppi/ci*` from their Dependabot `github-actions` -group. (The same #6704 gap applies to any third-party SHA we ever pin inside our -OWN composite actions — keep third-party pins in workflow files where Dependabot -can see them.) +open) — a consumer's vendored `make-target/action.yml`, and any third-party action +pinned inside a composite, is invisible to it. A grouped bump moves only the +workflow-level refs and splits the pin, which the `pin-availability` gate then +rejects. Renovate reads composite `action.yml`, so it keeps every whuppi/ci ref +uniform (workflow and composite alike) and bumps the third-party actions hidden in +composites. Each consumer runs `renovate.yml` (a thin wrapper calling the reusable, +same shape as this one) and drops its Dependabot `github-actions` + `pub` config +once migrated. The token is a whuppi org secret (`RENOVATE_TOKEN`); Renovate must +write `.github/workflows/`, which `GITHUB_TOKEN` can't. A pin bump merged to `main` reaches nobody until a release is cut — merging and releasing are separate, deliberate steps.