name: Release
on:
push:
tags: ["v[0-9]+.[0-9]+.[0-9]+"]
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
jobs:
verify:
name: verify tag and versions
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 with:
persist-credentials: false
fetch-depth: 0
- uses: dtolnay/rust-toolchain@7e38f4b43b4db5c8dd498af069a4f6196df1d067 with:
toolchain: stable
- uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 - name: Tag is annotated, named for the manifest, and has release notes
run: |
set -euo pipefail
tag="${GITHUB_REF_NAME}"
version="${tag#v}"
[ "$(git cat-file -t "refs/tags/${tag}")" = "tag" ] \
|| { echo "::error::${tag} is a lightweight tag; releases need a signed annotated tag"; exit 1; }
subject="$(git tag -l --format='%(contents:subject)' "${tag}")"
[ "${subject}" = "metadata-gen v${version}" ] \
|| { echo "::error::tag subject is '${subject}', expected 'metadata-gen v${version}'"; exit 1; }
manifest="$(grep -m1 '^version = ' Cargo.toml | cut -d'"' -f2)"
[ "${manifest}" = "${version}" ] \
|| { echo "::error::Cargo.toml says ${manifest}, tag says ${version}"; exit 1; }
grep -q '^## Highlights' "docs/releases/${tag}.md" \
|| { echo "::error::docs/releases/${tag}.md is missing or has no '## Highlights' section"; exit 1; }
- run: ./scripts/verify-release-versions.sh
- run: cargo test --all-features --locked
release:
name: package, attest, publish release
needs: verify
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: write
id-token: write
attestations: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 with:
persist-credentials: false
fetch-depth: 0
- uses: dtolnay/rust-toolchain@7e38f4b43b4db5c8dd498af069a4f6196df1d067 with:
toolchain: stable
- uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 - uses: taiki-e/cache-cargo-install-action@9ee83daaa7b96a6fab930949ecf1122bba04a389 with:
tool: cargo-cyclonedx
- name: Package the crate and generate the SBOM
run: |
set -euo pipefail
version="${GITHUB_REF_NAME#v}"
mkdir -p dist
cargo package --locked
cp "target/package/metadata-gen-${version}.crate" dist/
cargo cyclonedx --format json --all-features --override-filename "metadata-gen-${version}.cdx"
mv "metadata-gen-${version}.cdx.json" dist/
(cd dist && sha256sum -- * > ../SHA256SUMS)
cat SHA256SUMS
- uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 with:
subject-path: dist/*
- name: Compose release notes
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
tag="${GITHUB_REF_NAME}"
prev="$(git describe --tags --abbrev=0 "${tag}^" 2>/dev/null || true)"
args=(-f "tag_name=${tag}")
[ -n "${prev}" ] && args+=(-f "previous_tag_name=${prev}")
generated="$(gh api -X POST "repos/${GITHUB_REPOSITORY}/releases/generate-notes" "${args[@]}" --jq .body)"
full="$(printf '%s\n' "${generated}" | grep '^\*\*Full Changelog\*\*' || true)"
[ -n "${full}" ] || full="**Full Changelog**: https://github.com/${GITHUB_REPOSITORY}/compare/${prev}...${tag}"
{
sed -n '/^## Highlights/,$p' "docs/releases/${tag}.md"
echo
printf '%s\n' "${generated}" | grep -v '^\*\*Full Changelog\*\*'
echo
echo '## Checksums'
echo
echo 'SHA-256 of every asset attached to this release:'
echo
echo '```text'
cat SHA256SUMS
echo '```'
echo
printf '%s\n' "${full}"
} > release-notes.md
cat release-notes.md
- name: Publish the GitHub release
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
tag="${GITHUB_REF_NAME}"
gh release create "${tag}" \
--verify-tag \
--title "metadata-gen ${tag#v}" \
--notes-file release-notes.md \
dist/*