diff --git a/.github/workflows/bump-consumers.yml b/.github/workflows/bump-consumers.yml index 29bbfdd..98ad27d 100644 --- a/.github/workflows/bump-consumers.yml +++ b/.github/workflows/bump-consumers.yml @@ -1,8 +1,9 @@ # One pin-bump PR per consumer after a release (scripts/bump-consumers.sh). release.yml calls it # once the release is published; dispatch it by hand to retry or to bump to an older tag. -# It reuses the org secret MAROLA_CROSS_REPO_PAT, which needs Contents, Pull requests and -# Workflows write on every repo in .github/consumers.txt: a PR opened with GITHUB_TOKEN would start -# no CI in the consumer, and could not reach it anyway. +# It commits and opens the PRs as the org's GitHub App marola-bot (org variable +# MAROLA_BOT_APP_ID, org secret MAROLA_BOT_PRIVATE_KEY), installed with Contents, Pull requests +# and Workflows write: a PR opened with GITHUB_TOKEN would start no CI in the consumer, and could +# not reach it anyway. name: bump consumers on: @@ -10,7 +11,7 @@ on: inputs: version: { type: string, required: true } secrets: - MAROLA_CROSS_REPO_PAT: { required: true } + MAROLA_BOT_PRIVATE_KEY: { required: true } workflow_dispatch: inputs: version: { description: "X.Y.Z, an existing tag without the v", required: true } @@ -30,7 +31,16 @@ jobs: steps: - uses: actions/checkout@v7 - uses: DeterminateSystems/nix-installer-action@v23 + - id: app + uses: actions/create-github-app-token@v2 + with: + app-id: ${{ vars.MAROLA_BOT_APP_ID }} + private-key: ${{ secrets.MAROLA_BOT_PRIVATE_KEY }} + owner: marola-dev - env: - GH_TOKEN: ${{ secrets.MAROLA_CROSS_REPO_PAT }} + GH_TOKEN: ${{ steps.app.outputs.token }} + BOT: ${{ steps.app.outputs.app-slug }}[bot] VERSION: ${{ inputs.version }} - run: scripts/bump-consumers.sh "$VERSION" + run: | + BUMP_GIT_NAME="$BOT" BUMP_GIT_EMAIL="$(gh api "/users/$BOT" -q .id)+$BOT@users.noreply.github.com" \ + scripts/bump-consumers.sh "$VERSION" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d50fdf6..7fec8bc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,4 +31,4 @@ jobs: with: version: ${{ github.ref_name }} secrets: - MAROLA_CROSS_REPO_PAT: ${{ secrets.MAROLA_CROSS_REPO_PAT }} + MAROLA_BOT_PRIVATE_KEY: ${{ secrets.MAROLA_BOT_PRIVATE_KEY }} diff --git a/docs/3-development.md b/docs/3-development.md index d95bb2c..01fa97b 100644 --- a/docs/3-development.md +++ b/docs/3-development.md @@ -63,9 +63,13 @@ step 1 is skipped. Once the release is published, `release.yml` calls `bump-consumers.yml`, which opens one PR in each repo of `.github/consumers.txt` on `chore/devkit-vX.Y.Z`: the flake input and its `flake.lock` node, every devkit workflow `@v…`, `devkit-ref` and docs-lint clone, and the -marketplace `ref`. A person merges each. It uses the org secret `MAROLA_CROSS_REPO_PAT`, so the -PRs are authored by that token's owner; the token needs Contents, Pull requests and Workflows -write on every listed repo. h0ffmann/ww3-gpu is outside the org token's reach and not listed: bump +marketplace `ref`. A person merges each. The commits and PRs are marola-bot's, the org's GitHub +App, through a short-lived token `actions/create-github-app-token` mints per run. Setting it up +once: in marola-dev's Settings → Developer settings → GitHub Apps, create `marola-bot` (webhook +off) with Repository permissions Contents, Pull requests and Workflows: Read and write; install +it on the repos in `.github/consumers.txt`; put its App ID in the org variable +`MAROLA_BOT_APP_ID` and a generated private key in the org secret `MAROLA_BOT_PRIVATE_KEY`, both +visible to marola-devkit. h0ffmann/ww3-gpu is outside the org and not listed: bump the `@v…` and `devkit-ref` in its `skills.yml` by hand. Dispatch `bump-consumers.yml` by hand to retry a version: it updates the open PRs instead of adding more. Adding a consumer is one line in `.github/consumers.txt`. diff --git a/scripts/bump-consumers.sh b/scripts/bump-consumers.sh index a3e918d..6423b75 100755 --- a/scripts/bump-consumers.sh +++ b/scripts/bump-consumers.sh @@ -2,7 +2,7 @@ # bump-consumers: after a devkit release, one PR per repo in .github/consumers.txt on # chore/devkit-vX.Y.Z, moving its pins (release.py --consumer) and, where it commits one, the # flake.lock's devkit node. A re-run force-updates the branch and edits the open PR. GH_TOKEN must -# reach every repo; the PRs are authored by its owner. One repo failing doesn't stop the others. +# reach every repo; BUMP_GIT_NAME/BUMP_GIT_EMAIL author the commits (bump-consumers.yml sets marola-bot's). One repo failing doesn't stop the others. # scripts/bump-consumers.sh X.Y.Z # scripts/bump-consumers.sh --self-test set -euo pipefail @@ -53,7 +53,7 @@ bump() { echo "bump-consumers: $repo already pins $tag" >&2 return 0 fi - git -c user.name="github-actions[bot]" -c user.email="41898282+github-actions[bot]@users.noreply.github.com" \ + git -c user.name="${BUMP_GIT_NAME:-github-actions[bot]}" -c user.email="${BUMP_GIT_EMAIL:-41898282+github-actions[bot]@users.noreply.github.com}" \ commit -qam "chore: marola-devkit $tag" \ -m "Tested: release.py --consumer moved the pins${lock:+, nix flake update marola-devkit the lock}; this repo's CI gates the rest Cost: n/a (automation) @@ -74,7 +74,7 @@ if [ -n "$one" ]; then exit fi -[ -n "${GH_TOKEN:-}" ] || { echo "bump-consumers: GH_TOKEN is empty; give marola-devkit access to the org secret MAROLA_CROSS_REPO_PAT (docs/3-development.md, Releases)" >&2; exit 1; } +[ -n "${GH_TOKEN:-}" ] || { echo "bump-consumers: GH_TOKEN is empty; set up the marola-bot GitHub App (docs/3-development.md, Releases)" >&2; exit 1; } # Each repo in its own process: set -e does not apply inside a function called from `||`. gh auth setup-git failed=()