crates.io¶
registry: crates.io publishes crates from source with cargo publish.
crates.io packages take no artifacts.
- name: onto
registry: crates.io
manifest: crates/onto/Cargo.toml
version: "0.2.0"
The name must equal the Cargo.toml package name, and crates must be
listed after the listed crates they depend on. release.py check also
refuses a crate that crates.io would refuse: see
Publishing to crates.io.
Credentials¶
crates.io offers Trusted Publishing, but only for a crate that already exists. So rab uses two credentials:
- Existing crates use Trusted Publishing.
rust-lang/crates-io-auth-actionexchanges the job's OIDC token for a short-lived crates.io token. - A crate's first version uses an API token: the
CARGO_REGISTRY_TOKENsecret of thecrates-ioenvironment.
One-time setup¶
- Create a
crates-ioenvironment in the repository's settings. - For each crate that is already on crates.io, open its settings page on
crates.io and add a Trusted Publisher: your repository, the workflow
release.yml, and the environmentcrates-io. - If a release will publish a crate's first version, add a
CARGO_REGISTRY_TOKENsecret to thecrates-ioenvironment: a crates.io API token with thepublish-newscope (andpublish-updateif new and existing crates share it). After the first version is out, add that crate's Trusted Publisher. You can then delete the secret.
Publish¶
The template's publish-crates job:
- id: preflight
if: needs.gate.outputs.verify-only != 'true'
env:
SELECTION: ${{ needs.gate.outputs.selection }}
run: python3 .github/rab/scripts/release.py preflight --registry crates.io --selection "$SELECTION"
- id: auth
if: steps.preflight.outputs.existing_crate == 'true'
uses: rust-lang/crates-io-auth-action@3268eb413133e2960fa4ae0e963ca76380c54cd9 # v1.0.6
- uses: ./.github/rab/publish-crates
with:
selection: ${{ needs.gate.outputs.selection }}
new-crates: ${{ steps.preflight.outputs.new_crates || '[]' }}
token: ${{ steps.auth.outputs.token }}
new-crate-token: ${{ steps.preflight.outputs.new_crate == 'true' && secrets.CARGO_REGISTRY_TOKEN || '' }}
verify-only: ${{ needs.gate.outputs.verify-only }}
preflightrefuses any selected crate version already on crates.io, and writesnew_crates(the selected crates with no version yet),new_crateandexisting_crate.crates-io-auth-actionruns only when an existing crate is selected.- The secret reaches the action only when a new crate is selected.
-
release.py publish-cratesruns onecargo publish --dry-run --lockedover all the selected crates, then onecargo publish --lockedper consecutive run of existing crates, and one per new crate. Order is kept, so each crate is published after the crates it depends on. If a needed token is missing, it refuses before uploading anything:error: cannot publish: missing the new-crate token (the environment's CARGO_REGISTRY_TOKEN secret)
Publishing several crates in one cargo publish needs Cargo 1.90 or later;
the job installs stable Rust.
Many new crates at once¶
crates.io limits how many new crates an account publishes: a short burst,
then one every few minutes. A first release of a whole workspace hits it.
When crates.io answers a new crate with 429 Too Many Requests,
publish-crates waits until the time the answer names (ten minutes if it
names none) and tries that crate again, as often as it takes. Any other
failure stops at once. Eighteen new crates take about two hours, inside a
job's six-hour limit; crates.io can raise an account's limit on request.
Example: a first release¶
onto (a library) is new; onto-cli, which depends on it, already exists.
preflight writes new_crates=["onto"], new_crate=true,
existing_crate=true. publish-crates dry-runs both, publishes onto with
CARGO_REGISTRY_TOKEN, then onto-cli with the Trusted Publishing token.
Action inputs¶
| Input | Default | Meaning |
|---|---|---|
selection |
required | the gate's selection |
new-crates |
"[]" |
preflight's new_crates output |
token |
"" |
the Trusted Publishing token; needed when any selected crate exists |
new-crate-token |
"" |
a crates.io API token; needed only when a selected crate is new |
verify-only |
"false" |
"true" skips the upload |
Verify¶
verify --registry crates.io waits (up to 15 minutes) until
https://crates.io/api/v1/crates/<name>/<version> answers for every selected
crate.
Consume¶
consume --registry crates.io then, for each crate, in a fresh directory with
no token:
- a crate with a binary (a
[[bin]]table, orsrc/main.rsbeside itsCargo.toml):cargo install <name> --version =<version> --locked; - a library: a new crate,
cargo add <name>@=<version>, thencargo check.
The install or add step is retried up to 10 times, 30 seconds apart, because the crates.io index can lag behind its API.