1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
name: publish
# Builds the crate and uploads it to crates.io when a GitHub release
# is published. Requires `CARGO_REGISTRY_TOKEN` to be set as a repo
# secret (Settings → Secrets and variables → Actions). Generate the
# token at crates.io → Account Settings → API Tokens with a scope of
# at least `publish-new` + `publish-update`.
#
# crates.io versions are IMMUTABLE — a published `x.y.z` cannot be
# overwritten or deleted (only yanked, which doesn't free the version
# string). Pick the release tag carefully.
on:
release:
types:
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
# The release tag is the authoritative version source — rewrite
# the `version = "..."` line under `[package]` in Cargo.toml.
# Pattern is narrowly anchored to start-of-line `version = "..."`
# so it doesn't clobber dependency entries like
# `serde = { version = "^1.0", ... }` further down the file.
- name: Set version from release tag
if: github.event_name == 'release'
run: |
set -eu
TAG="${GITHUB_REF_NAME#v}"
echo "Using version: $TAG (from tag $GITHUB_REF_NAME)"
sed -i -E "0,/^version = \"[^\"]*\"/{s/^version = \"[^\"]*\"/version = \"${TAG}\"/}" Cargo.toml
grep -E "^version = " Cargo.toml
# `cargo publish` runs a verification build by default, which is
# what we want here — crates.io versions are immutable, so a
# broken upload is irreversible. `--locked` is skipped because
# this is a library crate and Cargo.lock isn't committed.
#
# `--allow-dirty` is required because the preceding step rewrites
# `Cargo.toml` (version from tag) without committing — the tag
# itself is the authoritative version record, so we don't bother
# committing a one-shot publish-time edit back to the SDK repo.
- name: Publish to crates.io
run: cargo publish --allow-dirty
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}