chore: release v1.0.0 (#9) #1
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| # Triggered by the tag that Prepare Release pushes. Runs the checks, builds the | |
| # source archive, and publishes a GitHub Release whose notes are the git-cliff | |
| # section for this tag. The archive sha256 is the interim integrity pin for the | |
| # featured index until the host's tree_hash lands (AoE #2364). | |
| # | |
| # After a successful publish, the `featured-pr` job opens a PR on | |
| # agent-of-empires/agent-of-empires that pins this version's source tree hash in | |
| # plugins/featured.toml, closing the manual featured-index step. It needs the | |
| # AOE_FEATURED_PR_TOKEN secret (cross-repo PR write) and runs behind the | |
| # required-reviewer `release` environment. | |
| on: | |
| push: | |
| tags: ["v*"] | |
| permissions: | |
| contents: write | |
| jobs: | |
| release: | |
| name: Publish release | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: clippy, rustfmt | |
| - run: cargo fmt --check | |
| - run: cargo clippy --all-targets -- -D warnings | |
| - run: cargo test | |
| - run: cargo build --release | |
| - name: Install git-cliff | |
| uses: taiki-e/install-action@v2 | |
| with: | |
| tool: git-cliff | |
| - name: Build source archive + release notes | |
| id: build | |
| run: | | |
| set -euo pipefail | |
| tag="${GITHUB_REF_NAME}" | |
| name="plugin-cron-${tag}" | |
| git cliff --config cliff.toml --current --output RELEASE_NOTES.md | |
| git archive --format=tar.gz --prefix="${name}/" -o "${name}.tar.gz" HEAD | |
| sha256sum "${name}.tar.gz" > "${name}.tar.gz.sha256" | |
| sha="$(cut -d' ' -f1 < "${name}.tar.gz.sha256")" | |
| { | |
| echo "" | |
| echo "---" | |
| echo "Featured-index pin (AoE #2364):" | |
| echo "- commit: ${GITHUB_SHA}" | |
| echo "- archive sha256: ${sha}" | |
| } >> RELEASE_NOTES.md | |
| echo "archive=${name}.tar.gz" >> "$GITHUB_OUTPUT" | |
| - name: Create GitHub Release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| set -euo pipefail | |
| tag="${GITHUB_REF_NAME}" | |
| gh release create "$tag" \ | |
| "${{ steps.build.outputs.archive }}" "${{ steps.build.outputs.archive }}.sha256" \ | |
| --title "$tag" \ | |
| --notes-file RELEASE_NOTES.md | |
| featured-pr: | |
| name: Open AoE featured-index PR | |
| needs: release | |
| runs-on: ubuntu-latest | |
| # The required-reviewer `release` environment guards AOE_FEATURED_PR_TOKEN | |
| # (a cross-repo write credential) the same way it guards the release PR. | |
| environment: release | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Skip when cross-repo token is unset | |
| id: gate | |
| env: | |
| TOKEN: ${{ secrets.AOE_FEATURED_PR_TOKEN }} | |
| run: | | |
| if [ -z "$TOKEN" ]; then | |
| echo "::warning::AOE_FEATURED_PR_TOKEN not set; skipping featured-index PR" | |
| echo "skip=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Checkout plugin-cron at the released tag | |
| if: steps.gate.outputs.skip == 'false' | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Set up Python | |
| if: steps.gate.outputs.skip == 'false' | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install tomlkit | |
| if: steps.gate.outputs.skip == 'false' | |
| run: pip install tomlkit | |
| - name: Compute released tree hash | |
| id: hash | |
| if: steps.gate.outputs.skip == 'false' | |
| env: | |
| # The aoe binary lives in the AoE release; the token reads it. | |
| GH_TOKEN: ${{ secrets.AOE_FEATURED_PR_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| tag="${GITHUB_REF_NAME}" | |
| if ! echo "$tag" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$'; then | |
| echo "::error::Unexpected release tag: $tag" | |
| exit 1 | |
| fi | |
| # Canonical hash: download the latest agent-of-empires release binary | |
| # and run `aoe plugin hash`, so this never has to track the host's | |
| # hashing algorithm. | |
| asset="aoe-linux-amd64" | |
| bindir="$(mktemp -d)" | |
| gh release download --repo agent-of-empires/agent-of-empires \ | |
| --pattern "${asset}.tar.gz" --dir "$bindir" | |
| tar -xzf "${bindir}/${asset}.tar.gz" -C "$bindir" | |
| chmod +x "${bindir}/${asset}" | |
| # Hash the released commit's tracked tree (git archive strips .git and | |
| # untracked build output), matching the host's clone-then-strip fetch. | |
| work="$(mktemp -d)" | |
| git archive --format=tar HEAD | tar -x -C "$work" | |
| tree_hash="$("${bindir}/${asset}" plugin hash "$work")" | |
| if ! echo "$tree_hash" | grep -qE '^sha256:[0-9a-f]{64}$'; then | |
| echo "::error::Bad tree hash: $tree_hash" | |
| exit 1 | |
| fi | |
| { | |
| echo "version=${tag#v}" | |
| echo "commit=$(git rev-parse HEAD)" | |
| echo "tree_hash=$tree_hash" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Checkout agent-of-empires | |
| if: steps.gate.outputs.skip == 'false' | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: agent-of-empires/agent-of-empires | |
| token: ${{ secrets.AOE_FEATURED_PR_TOKEN }} | |
| path: aoe | |
| fetch-depth: 0 | |
| persist-credentials: true | |
| - name: Open or update featured-index PR | |
| if: steps.gate.outputs.skip == 'false' | |
| env: | |
| GH_TOKEN: ${{ secrets.AOE_FEATURED_PR_TOKEN }} | |
| VERSION: ${{ steps.hash.outputs.version }} | |
| COMMIT: ${{ steps.hash.outputs.commit }} | |
| TREE_HASH: ${{ steps.hash.outputs.tree_hash }} | |
| TAG: ${{ github.ref_name }} | |
| run: | | |
| set -euo pipefail | |
| plugin_id="agent-of-empires.cron" | |
| featured="plugins/featured.toml" | |
| branch="featured/cron-v${VERSION}" | |
| release_url="https://github.com/${GITHUB_REPOSITORY}/releases/tag/${TAG}" | |
| # Edit AoE's trust root through the tomlkit-based updater. It exits | |
| # nonzero (changing nothing) if this version is already pinned to a | |
| # different hash, which would signal a retag, tamper, or algo drift. | |
| status="$(python scripts/featured_index.py update \ | |
| "aoe/${featured}" "$plugin_id" "$VERSION" "$TREE_HASH")" | |
| if [ "$status" = "unchanged" ]; then | |
| echo "::notice::${plugin_id} ${VERSION} already pinned; nothing to do" | |
| exit 0 | |
| fi | |
| cd aoe | |
| # Defense in depth: only featured.toml may have changed. | |
| dirty="$(git status --porcelain --untracked-files=no | grep -v "^ M ${featured}\$" || true)" | |
| if [ -n "$dirty" ]; then | |
| echo "::error::unexpected changes in AoE checkout" | |
| git status --porcelain | |
| exit 1 | |
| fi | |
| # Idempotent: if the deterministic branch already exists upstream, | |
| # ensure a PR points at it rather than force-pushing over it. | |
| if git ls-remote --exit-code --heads origin "$branch" >/dev/null 2>&1; then | |
| open_pr="$(gh pr list --head "$branch" --base main --state open --json number --jq '.[0].number // ""')" | |
| if [ -z "$open_pr" ]; then | |
| echo "::warning::branch $branch exists upstream with no open PR; inspect manually, not force-updating" | |
| else | |
| echo "::notice::PR for $branch already open (#$open_pr)" | |
| fi | |
| exit 0 | |
| fi | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git checkout -b "$branch" | |
| git add "$featured" | |
| git commit -m "chore(plugins): pin ${plugin_id} ${VERSION}" | |
| git push -u origin "$branch" | |
| gh pr create \ | |
| --base main \ | |
| --head "$branch" \ | |
| --title "chore(plugins): pin ${plugin_id} ${VERSION}" \ | |
| --body "$(printf '%s\n' \ | |
| "Automated by plugin-cron release CI (closes the manual featured-index step)." \ | |
| "" \ | |
| "Pins \`${plugin_id}\` \`${VERSION}\` in \`${featured}\`." \ | |
| "" \ | |
| "- Version: ${VERSION}" \ | |
| "- Tree hash: \`${TREE_HASH}\`" \ | |
| "- Hash algorithm: aoe-plugin-tree-hash-v1" \ | |
| "- Source commit: ${COMMIT}" \ | |
| "- Release: ${release_url}")" |