tambo 0.4.0

Install and prove the whole AI knowledge-tool kit
Documentation
name: release

on:
  push:
    tags:
      - 'v*'
    branches: [main]

# Release-PR model (aegis-ebal6v.7.1, as in bobbin/yupana): every main push opens or
# refreshes the release PR; merging it makes release-please create the tag and a
# DRAFT release. A tag created with GITHUB_TOKEN does not trigger another workflow,
# so the jobs below run in THIS run, gated on releases_created, and take the version
# from the release-please tag_name (github.ref_name is `main` there). The tag-push
# arm still works for an emergency hand release.

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 # v4
        id: release
        with:
          token: ${{ secrets.GITHUB_TOKEN }}

  build:
    needs: release-please
    # always(): release-please is SKIPPED on the tag-push arm, which would skip this job.
    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" = scbrown/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 # v1
      - 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