name: release
on:
push:
tags:
- 'v*'
branches: [main]
permissions:
contents: write
jobs:
release-please:
name: Release Please
if: startsWith(github.ref, 'refs/heads/')
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
outputs:
releases_created: ${{ steps.release.outputs.releases_created }}
tag_name: ${{ steps.release.outputs.tag_name }}
steps:
- uses: googleapis/release-please-action@5c625bfb5d1ff62eadeeb3772007f7f66fdcf071 id: release
with:
token: ${{ secrets.GITHUB_TOKEN }}
build:
needs: release-please
if: >-
always() &&
(startsWith(github.ref, 'refs/tags/') ||
needs.release-please.outputs.releases_created == 'true')
env:
VERSION: ${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || needs.release-please.outputs.tag_name }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
- os: macos-15-intel
target: x86_64-apple-darwin
- os: macos-14
target: aarch64-apple-darwin
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ env.VERSION }}
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Require tag to match Cargo.toml
shell: bash
run: |
set -euo pipefail
package_version=$(sed -n 's/^version = "\([^"]*\)"$/\1/p' Cargo.toml | head -n 1)
test "$VERSION" = "v$package_version"
- name: Build archive and checksum
shell: bash
run: |
set -euo pipefail
cargo build --release --locked --target '${{ matrix.target }}'
archive="tambo-$VERSION-${{ matrix.target }}.tar.gz"
mkdir dist
tar -czf "dist/$archive" -C 'target/${{ matrix.target }}/release' tambo caboodle
if command -v sha256sum >/dev/null; then
(cd dist && sha256sum "$archive" > "$archive.sha256")
else
(cd dist && shasum -a 256 "$archive" > "$archive.sha256")
fi
# One compatibility release for existing Caboodle update-self clients.
legacy="caboodle-$VERSION-${{ matrix.target }}.tar.gz"
cp "dist/$archive" "dist/$legacy"
if command -v sha256sum >/dev/null; then
(cd dist && sha256sum "$legacy" > "$legacy.sha256")
else
(cd dist && shasum -a 256 "$legacy" > "$legacy.sha256")
fi
- uses: actions/upload-artifact@v4
with:
name: release-${{ matrix.target }}
path: dist/*
if-no-files-found: error
publish:
needs: [release-please, build]
if: >-
always() && needs.build.result == 'success' &&
(startsWith(github.ref, 'refs/tags/') ||
needs.release-please.outputs.releases_created == 'true')
runs-on: ubuntu-latest
env:
VERSION: ${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || needs.release-please.outputs.tag_name }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ env.VERSION }}
- uses: actions/download-artifact@v4
with:
pattern: release-*
path: dist
merge-multiple: true
- name: Verify complete release metadata
env:
TAMBO_EXPECT_TARGETS: x86_64-unknown-linux-gnu x86_64-apple-darwin aarch64-apple-darwin
run: scripts/check-release-assets.sh "$VERSION" dist
- name: Publish immutable GitHub release
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
set -euo pipefail
# release-please path: it created a DRAFT release for this tag; attach the
# verified assets, then publish it. Tag-push path: create it as before.
if gh release view "$VERSION" --json isDraft --jq .isDraft 2>/dev/null | grep -qx true; then
gh release upload "$VERSION" dist/* --clobber
gh release edit "$VERSION" --draft=false
else
gh release create "$VERSION" dist/* --verify-tag --generate-notes
fi
publish-crate:
name: Publish Tambo through crates.io Trusted Publishing
needs: [release-please, publish]
if: always() && needs.publish.result == 'success'
runs-on: ubuntu-latest
env:
VERSION: ${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || needs.release-please.outputs.tag_name }}
timeout-minutes: 20
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
with:
ref: ${{ env.VERSION }}
- uses: dtolnay/rust-toolchain@stable
- name: Require the canonical repository and matching tag
shell: bash
run: |
set -euo pipefail
test "$GITHUB_REPOSITORY" = intigraph/tambo
version=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[] | select(.name == "tambo") | .version')
test "$VERSION" = "v$version"
echo "TAMBO_PUBLISH_VERSION=$version" >> "$GITHUB_ENV"
- name: Build and verify the registry package
shell: bash
run: |
set -euo pipefail
cargo package --locked -p tambo
package_sha=$(sha256sum "target/package/tambo-$TAMBO_PUBLISH_VERSION.crate" | awk '{print $1}')
echo "TAMBO_PACKAGE_SHA256=$package_sha" >> "$GITHUB_ENV"
- name: Check whether the account bootstrap already published this version
id: registry
shell: bash
run: |
set -euo pipefail
if scripts/check-crate-version.sh tambo "$TAMBO_PUBLISH_VERSION" "$TAMBO_PACKAGE_SHA256"; then
echo 'already=true' >> "$GITHUB_OUTPUT"
else
rc=$?
test "$rc" = 1
echo 'already=false' >> "$GITHUB_OUTPUT"
fi
- name: Authenticate with crates.io
if: steps.registry.outputs.already != 'true'
id: crates-auth
uses: rust-lang/crates-io-auth-action@b7e9a28eded4986ec6b1fa40eeee8f8f165559ec - name: Publish the verified package
if: steps.registry.outputs.already != 'true'
run: cargo publish --locked -p tambo
env:
CARGO_REGISTRY_TOKEN: ${{ steps.crates-auth.outputs.token }}
- name: Verify registry visibility
shell: bash
run: |
set -euo pipefail
for attempt in $(seq 1 10); do
if scripts/check-crate-version.sh tambo "$TAMBO_PUBLISH_VERSION" "$TAMBO_PACKAGE_SHA256"; then
exit 0
fi
test "$attempt" = 10 || sleep 15
done
echo 'Registry visibility is UNKNOWN; publication is not accepted.' >&2
exit 1
repository-pendant-admission:
name: Record repository pendant admission
needs: [release-please, publish]
if: always() && needs.publish.result == 'success'
runs-on: ubuntu-latest
timeout-minutes: 2
permissions: {}
env:
ADMISSION: ${{ vars.TAMBO_PENDANT_PUBLICATION }}
steps:
- name: Record admission state
run: |
if [ "$ADMISSION" = enabled ]; then
state="admitted: the trusted host publisher must deliver and Verify repository pendant runs"
else
state="NOT ADMITTED: pendant publication not admitted for tambo (no trusted producer), so no pendant is expected and Verify repository pendant is skipped by its condition (not a pass; aegis-dics)"
fi
echo "repository pendant publication: $state"
echo "Repository pendant publication: $state" >> "$GITHUB_STEP_SUMMARY"
repository-pendant:
name: Verify repository pendant
needs: [release-please, publish]
if: always() && needs.publish.result == 'success' && vars.TAMBO_PENDANT_PUBLICATION == 'enabled'
runs-on: ubuntu-latest
timeout-minutes: 45
permissions:
contents: read
env:
RELEASE_TAG: ${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || needs.release-please.outputs.tag_name }}
GH_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ env.RELEASE_TAG }}
fetch-depth: 0
- name: Verify the bounded public pointer corpus
run: python3 scripts/verify-repository-share.py "$RELEASE_TAG" "$(git rev-parse HEAD)"