diff --git a/.github/workflows/publish-crate.yml b/.github/workflows/publish-crate.yml new file mode 100644 index 00000000..a1f828d3 --- /dev/null +++ b/.github/workflows/publish-crate.yml @@ -0,0 +1,42 @@ +# Publish the crate to crates.io as part of the CLI release. +# +# This is a dist custom publish job: it is invoked BY `release.yml` (wired via +# `publish-jobs` in dist-workspace.toml), so the crates.io publish is owned by +# the CLI release workflow — doctrine/delivery/RULES.md:2. It runs only in the +# publish phase of a real `vX.Y.Z` tag release, never on a PR. +# +# Prerequisite: a repository secret `CARGO_REGISTRY_TOKEN` (a crates.io API +# token with publish scope). +name: Publish crate + +on: + workflow_call: + inputs: + plan: + description: The dist release plan (JSON); passed by dist, unused here. + required: true + type: string + +jobs: + publish-crate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + # doctrine/delivery/RULES.md:6 — the release aborts unless the git tag, + # Cargo.toml, and Chart.yaml versions all agree. + - name: Verify tag == Cargo.toml == Chart.yaml + run: | + ver="${GITHUB_REF_NAME#v}" + cargo_ver="$(grep -m1 '^version = ' Cargo.toml | sed -E 's/.*"([^"]+)".*/\1/')" + chart_ver="$(grep -m1 '^version: ' benchmarks/_chart/Chart.yaml | awk '{print $2}')" + echo "tag=$ver cargo=$cargo_ver chart=$chart_ver" + if [ "$ver" != "$cargo_ver" ] || [ "$ver" != "$chart_ver" ]; then + echo "::error::release version mismatch (tag=$ver cargo=$cargo_ver chart=$chart_ver) — bump Cargo.toml and benchmarks/_chart/Chart.yaml to $ver before tagging" + exit 1 + fi + + - name: cargo publish + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + run: cargo publish --locked diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1dfcd0f4..d43ac936 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -278,14 +278,29 @@ jobs: gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/* + custom-publish-crate: + needs: + - plan + - host + if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }} + uses: ./.github/workflows/publish-crate.yml + with: + plan: ${{ needs.plan.outputs.val }} + secrets: inherit + # publish jobs get escalated permissions + permissions: + "id-token": "write" + "packages": "write" + announce: needs: - plan - host + - custom-publish-crate # use "always() && ..." to allow us to wait for all publish jobs while # still allowing individual publish jobs to skip themselves (for prereleases). # "host" however must run to completion, no skipping allowed! - if: ${{ always() && needs.host.result == 'success' }} + if: ${{ always() && needs.host.result == 'success' && (needs.custom-publish-crate.result == 'skipped' || needs.custom-publish-crate.result == 'success') }} runs-on: "ubuntu-22.04" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/dist-workspace.toml b/dist-workspace.toml index 0330c091..f3f9c603 100644 --- a/dist-workspace.toml +++ b/dist-workspace.toml @@ -17,3 +17,6 @@ install-path = "CARGO_HOME" hosting = "github" # Whether to install an updater program install-updater = false +# Publish the crate to crates.io as part of the release (doctrine/delivery/RULES.md:2). +# Custom job in .github/workflows/publish-crate.yml; needs a CARGO_REGISTRY_TOKEN secret. +publish-jobs = ["./publish-crate"]