|
| 1 | +# Publishes a single crate from this workspace to crates.io using Trusted Publishing. |
| 2 | +# |
| 3 | +# There is no `CARGO_REGISTRY_TOKEN` secret: `rust-lang/crates-io-auth-action` exchanges this |
| 4 | +# workflow's GitHub OIDC identity for a short-lived crates.io token that expires after the run. |
| 5 | +# |
| 6 | +# One-time setup per crate, on https://crates.io/crates/<crate>/settings/trusted-publishing: |
| 7 | +# Repository owner: github |
| 8 | +# Repository name: rust-gems |
| 9 | +# Workflow name: publish-crates.yaml |
| 10 | +# Environment: crates-io |
| 11 | +# The environment name must match the `environment:` value below exactly, or crates.io rejects |
| 12 | +# the token exchange. A crate must be published manually once before it can be configured. |
| 13 | +name: Publish crates |
| 14 | + |
| 15 | +on: |
| 16 | + workflow_dispatch: |
| 17 | + inputs: |
| 18 | + crate: |
| 19 | + description: Crate to publish, at the version in its Cargo.toml |
| 20 | + required: true |
| 21 | + type: choice |
| 22 | + options: |
| 23 | + - bpe |
| 24 | + - bpe-openai |
| 25 | + - casefold |
| 26 | + - commutative_hasher |
| 27 | + - consistent-choose-k |
| 28 | + - geo_filters |
| 29 | + - hash-sorted-map |
| 30 | + - sparse-ngrams |
| 31 | + - string-offsets |
| 32 | + crate_name_override: |
| 33 | + description: Crate name to publish instead, for crates missing from the list above |
| 34 | + required: false |
| 35 | + type: string |
| 36 | + dry_run: |
| 37 | + description: Package and verify the crate without uploading it |
| 38 | + type: boolean |
| 39 | + default: false |
| 40 | + |
| 41 | +permissions: |
| 42 | + contents: read |
| 43 | + id-token: write # Required to mint the crates.io OIDC token. |
| 44 | + |
| 45 | +jobs: |
| 46 | + publish: |
| 47 | + name: Publish ${{ inputs.crate_name_override || inputs.crate }} |
| 48 | + runs-on: ubuntu-latest |
| 49 | + # Gate releases behind an environment so protection rules apply, and so the OIDC claim |
| 50 | + # matches the trusted publisher configured on crates.io. |
| 51 | + environment: crates-io |
| 52 | + steps: |
| 53 | + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 |
| 54 | + |
| 55 | + - uses: rui314/setup-mold@7e4f20ad28a2e8ca6fd0892ccf72e2abb706b9c3 |
| 56 | + |
| 57 | + # `crate_name_override` wins when set, because a choice input always has one option |
| 58 | + # selected and so can't express "none of these". |
| 59 | + - name: Resolve crate |
| 60 | + id: resolve |
| 61 | + env: |
| 62 | + CHOICE: ${{ inputs.crate }} |
| 63 | + OVERRIDE: ${{ inputs.crate_name_override }} |
| 64 | + run: | |
| 65 | + crate=$(printf '%s' "${OVERRIDE:-$CHOICE}" | tr -d '[:space:]') |
| 66 | + # Check the name against the workspace so a typo fails here with a clear message, |
| 67 | + # and so nothing unvetted reaches the cargo commands below. |
| 68 | + publishable=$(cargo metadata --no-deps --format-version 1 | |
| 69 | + jq -r '.packages[] | select(.publish != []) | .name') |
| 70 | + if ! printf '%s\n' "$publishable" | grep -qxF "$crate"; then |
| 71 | + echo "::error::'$crate' is not a publishable crate. Available: $(echo $publishable)" |
| 72 | + exit 1 |
| 73 | + fi |
| 74 | + echo "crate=$crate" >> "$GITHUB_OUTPUT" |
| 75 | +
|
| 76 | + - name: Package and verify |
| 77 | + run: cargo publish --package "$CRATE" --dry-run |
| 78 | + env: |
| 79 | + CRATE: ${{ steps.resolve.outputs.crate }} |
| 80 | + |
| 81 | + - name: Get crates.io token |
| 82 | + if: ${{ !inputs.dry_run }} |
| 83 | + id: auth |
| 84 | + uses: rust-lang/crates-io-auth-action@c6f97d42243bad5fab37ca0427f495c86d5b1a18 # v1.0.5 |
| 85 | + |
| 86 | + # Verification already happened in the dry run above, on this exact tree. |
| 87 | + - name: Publish |
| 88 | + if: ${{ !inputs.dry_run }} |
| 89 | + run: cargo publish --package "$CRATE" --no-verify |
| 90 | + env: |
| 91 | + CRATE: ${{ steps.resolve.outputs.crate }} |
| 92 | + CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} |
0 commit comments