diff --git a/.github/workflows/publish-crates.yaml b/.github/workflows/publish-crates.yaml new file mode 100644 index 0000000..1dcb670 --- /dev/null +++ b/.github/workflows/publish-crates.yaml @@ -0,0 +1,92 @@ +# Publishes a single crate from this workspace to crates.io using Trusted Publishing. +# +# There is no `CARGO_REGISTRY_TOKEN` secret: `rust-lang/crates-io-auth-action` exchanges this +# workflow's GitHub OIDC identity for a short-lived crates.io token that expires after the run. +# +# One-time setup per crate, on https://crates.io/crates//settings/trusted-publishing: +# Repository owner: github +# Repository name: rust-gems +# Workflow name: publish-crates.yaml +# Environment: crates-io +# The environment name must match the `environment:` value below exactly, or crates.io rejects +# the token exchange. A crate must be published manually once before it can be configured. +name: Publish crates + +on: + workflow_dispatch: + inputs: + crate: + description: Crate to publish, at the version in its Cargo.toml + required: true + type: choice + options: + - bpe + - bpe-openai + - casefold + - commutative_hasher + - consistent-choose-k + - geo_filters + - hash-sorted-map + - sparse-ngrams + - string-offsets + crate_name_override: + description: Crate name to publish instead, for crates missing from the list above + required: false + type: string + dry_run: + description: Package and verify the crate without uploading it + type: boolean + default: false + +permissions: + contents: read + id-token: write # Required to mint the crates.io OIDC token. + +jobs: + publish: + name: Publish ${{ inputs.crate_name_override || inputs.crate }} + runs-on: ubuntu-latest + # Gate releases behind an environment so protection rules apply, and so the OIDC claim + # matches the trusted publisher configured on crates.io. + environment: crates-io + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - uses: rui314/setup-mold@7e4f20ad28a2e8ca6fd0892ccf72e2abb706b9c3 + + # `crate_name_override` wins when set, because a choice input always has one option + # selected and so can't express "none of these". + - name: Resolve crate + id: resolve + env: + CHOICE: ${{ inputs.crate }} + OVERRIDE: ${{ inputs.crate_name_override }} + run: | + crate=$(printf '%s' "${OVERRIDE:-$CHOICE}" | tr -d '[:space:]') + # Check the name against the workspace so a typo fails here with a clear message, + # and so nothing unvetted reaches the cargo commands below. + publishable=$(cargo metadata --no-deps --format-version 1 | + jq -r '.packages[] | select(.publish != []) | .name') + if ! printf '%s\n' "$publishable" | grep -qxF "$crate"; then + echo "::error::'$crate' is not a publishable crate. Available: $(echo $publishable)" + exit 1 + fi + echo "crate=$crate" >> "$GITHUB_OUTPUT" + + - name: Package and verify + run: cargo publish --package "$CRATE" --dry-run + env: + CRATE: ${{ steps.resolve.outputs.crate }} + + - name: Get crates.io token + if: ${{ !inputs.dry_run }} + id: auth + uses: rust-lang/crates-io-auth-action@c6f97d42243bad5fab37ca0427f495c86d5b1a18 # v1.0.5 + + # Verification already happened in the dry run above, on this exact tree. + - name: Publish + if: ${{ !inputs.dry_run }} + run: cargo publish --package "$CRATE" --no-verify + env: + CRATE: ${{ steps.resolve.outputs.crate }} + CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 17d7dd3..aa154f7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,12 +15,12 @@ These are one time installations required to be able to test your changes locall ## Submitting a pull request 1. [Fork][fork] and clone the repository -1. Make sure the tests pass on your machine: `make test` -1. Make sure linter passes on your machine: `make lint` -1. Create a new branch: `git checkout -b my-branch-name` -1. Make your change, add tests, and make sure the tests and linter still pass -1. Push to your fork and [submit a pull request][pr] -1. Pat yourself on the back and wait for your pull request to be reviewed and merged. +2. Make sure the tests pass on your machine: `make test` +3. Make sure linter passes on your machine: `make lint` +4. Create a new branch: `git checkout -b my-branch-name` +5. Make your change, add tests, and make sure the tests and linter still pass +6. Push to your fork and [submit a pull request][pr] +7. Pat yourself on the back and wait for your pull request to be reviewed and merged. Here are a few things you can do that will increase the likelihood of your pull request being accepted: @@ -29,6 +29,25 @@ Here are a few things you can do that will increase the likelihood of your pull - Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests. - Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). +## Releasing a crate + +Crates are published to [crates.io](https://crates.io) with +[Trusted Publishing](https://crates.io/docs/trusted-publishing), so there is no long-lived API +token stored in this repository. The `Publish crates` workflow exchanges its GitHub OIDC identity +for a token that is revoked when the run ends. + +1. Bump `version` in the crate's `Cargo.toml` and merge that change to `main`. +2. Run the [`Publish crates`](../../actions/workflows/publish-crates.yaml) workflow via + *Run workflow*, pick the crate, and optionally tick *dry-run* first to package and verify it + without uploading. If a newly added crate isn't in the dropdown yet, type its name into + *crate_name_override* instead — and add it to the dropdown in `publish-crates.yaml` while + you're there. + +A crate has to be published manually once before crates.io will let you configure a trusted +publisher for it. Configure it at `https://crates.io/crates//settings/trusted-publishing` +with repository `github/rust-gems`, workflow `publish-crates.yaml`, and environment `crates-io`. +The environment name must match the workflow's `environment:` exactly or the token exchange fails. + ## Resources - [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) diff --git a/crates/bpe/benchmarks/Cargo.toml b/crates/bpe/benchmarks/Cargo.toml index 0c0c9ae..0017b30 100644 --- a/crates/bpe/benchmarks/Cargo.toml +++ b/crates/bpe/benchmarks/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "bpe-benchmarks" edition = "2021" +publish = false [lib] path = "lib.rs" diff --git a/crates/bpe/tests/Cargo.toml b/crates/bpe/tests/Cargo.toml index c674718..2355c8c 100644 --- a/crates/bpe/tests/Cargo.toml +++ b/crates/bpe/tests/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "bpe-tests" edition = "2021" +publish = false [dependencies] bpe = { path = "../../bpe", features = ["rand"] } diff --git a/crates/casefold/benchmarks/Cargo.toml b/crates/casefold/benchmarks/Cargo.toml index 7c0944f..2a4a262 100644 --- a/crates/casefold/benchmarks/Cargo.toml +++ b/crates/casefold/benchmarks/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "casefold-benchmarks" edition = "2021" +publish = false [lib] path = "lib.rs" diff --git a/crates/consistent-choose-k/benchmarks/Cargo.toml b/crates/consistent-choose-k/benchmarks/Cargo.toml index 7b17102..5f671fb 100644 --- a/crates/consistent-choose-k/benchmarks/Cargo.toml +++ b/crates/consistent-choose-k/benchmarks/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "consistent-choose-k-benchmarks" edition = "2021" +publish = false [[bench]] name = "performance"