Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 23 additions & 36 deletions .github/workflows/changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,23 @@ jobs:
changelog:
if: ${{ !endsWith(github.actor, '[bot]') }}
runs-on: ubuntu-latest
permissions: {} # all repo access comes from the minted App token below
# Only the newest regeneration may land: an older one sees a stale tree.
# A cancel between mint and land leaves its one-hour token unrevoked.
concurrency:
group: changelog
cancel-in-progress: true
environment: soothfast-bot
permissions:
contents: read
id-token: write # soothfast-bot token via the broker, see bot/
steps:
- uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit
- name: Mint a soothfast-bot token
id: app-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
client-id: ${{ vars.CHANGELOG_APP_CLIENT_ID }}
private-key: ${{ secrets.CHANGELOG_APP_PRIVATE_KEY }}
permission-contents: write
permission-pull-requests: write
- name: Get soothfast-bot user id
id: app-user
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
APP_SLUG: ${{ steps.app-token.outputs.app-slug }}
run: echo "id=$(gh api "/users/${APP_SLUG}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # zizmor: ignore[artipacked]
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0 # surface diff + previous-tag lookup need history
ref: ${{ github.ref_name }}
token: ${{ steps.app-token.outputs.token }}
persist-credentials: false
- uses: dtolnay/rust-toolchain@6bed0761d98439e5a578e2877258200ad565ba87 # stable
with:
toolchain: stable
Expand All @@ -59,22 +52,16 @@ jobs:
# shellcheck disable=SC2086 # both are deliberate flag lists
cargo run --release -p cargo-soothfast -- \
report changelog $PKGS --baseline self $AGAINST
- uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
id: cpr
with:
token: ${{ steps.app-token.outputs.token }}
add-paths: CHANGELOG.md
commit-message: "docs: regenerate CHANGELOG.md"
title: "docs: regenerate CHANGELOG.md"
body: Automated CHANGELOG regeneration.
branch: bot/changelog-update
delete-branch: true
author: >-
${{ steps.app-token.outputs.app-slug }}[bot]
<${{ steps.app-user.outputs.id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com>
- name: Merge pull request
if: steps.cpr.outputs.pull-request-number
# Minted after the build so no step that compiles the tree holds it.
- name: Mint a soothfast-bot token
id: bot
run: action/bot-token.sh
- name: Land the regenerated changelog
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
PR_NUMBER: ${{ steps.cpr.outputs.pull-request-number }}
run: gh pr merge --auto --squash --delete-branch "$PR_NUMBER"
TOKEN: ${{ steps.bot.outputs.token }}
APP_SLUG: ${{ steps.bot.outputs.app_slug }}
BRANCH: bot/changelog-update
TITLE: "docs: regenerate CHANGELOG.md"
BODY: Automated CHANGELOG regeneration.
PATHS: CHANGELOG.md
run: action/land.sh
49 changes: 49 additions & 0 deletions action/land.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env bash
# Commit PATHS as APP_SLUG[bot], push them to BRANCH, open or refresh its
# pull request against the default branch, and merge it: auto-merge when the
# default branch has a rule that blocks merging, immediately otherwise. The
# working tree keeps the regenerated files but HEAD is left where it was.
# TOKEN is revoked on every exit path.
# Inputs: TOKEN APP_SLUG BRANCH TITLE BODY PATHS (space separated pathspecs).
set -euo pipefail

: "${TOKEN:?}" "${APP_SLUG:?}" "${BRANCH:?}" "${TITLE:?}" "${PATHS:?}"
export GH_TOKEN="$TOKEN"
trap 'gh api -X DELETE /installation/token >/dev/null || true' EXIT

read -ra paths <<<"$PATHS"
git add -- "${paths[@]}"
if git diff --cached --quiet; then
echo "land: nothing to commit"
exit 0
fi

bot_id=$(gh api "/users/${APP_SLUG}[bot]" --jq .id)
head=$(git rev-parse HEAD)
git -c "user.name=${APP_SLUG}[bot]" \
-c "user.email=${bot_id}+${APP_SLUG}[bot]@users.noreply.github.com" \
commit -q -m "$TITLE"
# shellcheck disable=SC2016 # git expands $TOKEN when it runs the helper
git -c credential.helper= \
-c credential.helper='!f() { echo "username=x-access-token"; echo "password=$TOKEN"; }; f' \
push --force "https://github.com/${GITHUB_REPOSITORY}" "HEAD:refs/heads/${BRANCH}"
git reset -q --soft "$head"

default=$(gh repo view --json defaultBranchRef --jq .defaultBranchRef.name)
pr=$(gh pr list --head "$BRANCH" --base "$default" --state open --json number --jq '.[0].number // empty')
if [ -z "$pr" ]; then
url=$(gh pr create --head "$BRANCH" --base "$default" --title "$TITLE" --body "${BODY:-}")
pr=${url##*/}
else
gh pr edit "$pr" --title "$TITLE" --body "${BODY:-}" >/dev/null
fi

# History-only rules (deletion, linear history) leave the PR clean, and
# --auto refuses a PR with nothing to wait for.
blocking=$(gh api "repos/${GITHUB_REPOSITORY}/rules/branches/${default}" \
--jq '[.[] | select(.type == "required_status_checks" or .type == "pull_request" or .type == "merge_queue")] | length')
if [ "$blocking" -gt 0 ]; then
gh pr merge --auto --squash --delete-branch "$pr"
else
gh pr merge --squash --delete-branch "$pr"
fi
Loading