Repository navigation
Publish crates.io 5.0.0 [38310343691-1] #1
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Publish crates.io | |
| run-name: "Publish crates.io ${{ inputs.version }}${{ inputs.distinct-id != '' && format(' [{0}]', inputs.distinct-id) || '' }}" | |
| # Publishes socket-patch-core + socket-patch-cli to crates.io for an existing | |
| # v<version> tag. Dispatched two ways, both as a plain workflow_dispatch run: | |
| # - by release.yml (scripts/dispatch-publish.sh), as one leg of the | |
| # single-dispatch release fan-out — distinct-id carries the release | |
| # run's correlation id into this run's name; | |
| # - manually (Actions → Publish crates.io → Run workflow), to retry just | |
| # this registry after a mid-release failure: fix the cause, enter the | |
| # release version, leave distinct-id blank. | |
| # Every run checks out refs/tags/v<version> and publishes from source, so a | |
| # manual retry publishes exactly what the release run would have. | |
| # | |
| # Idempotent: already-published versions are probed and skipped, so re-runs | |
| # and retries after a partial publish (core landed, cli didn't) are safe. | |
| # | |
| # OIDC trusted publishing: the crates.io trusted publisher for both crates is | |
| # keyed on this repo + THIS file's name (publish-cargo.yml). Because this | |
| # workflow only ever runs as its own top-level workflow_dispatch run (never | |
| # as a called reusable workflow), the OIDC token's workflow_ref and | |
| # job_workflow_ref claims both name this file — one publisher registration | |
| # covers every path, regardless of which claim the registry matches. | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Release version (X.Y.Z; the tag v<version> must exist)' | |
| required: true | |
| type: string | |
| distinct-id: | |
| description: 'Correlation id set by release.yml to track its dispatched run — leave blank for manual runs' | |
| required: false | |
| default: '' | |
| type: string | |
| # Serialize same-version runs: the already-published probes below are | |
| # check-then-act, so two CONCURRENT runs for one version could both pass a | |
| # probe and the loser would hard-fail on the registry. Serialized, a | |
| # duplicate (e.g. re-dispatched by a release-run watcher whose `gh run | |
| # watch` timed out while this run was still going) waits behind the live | |
| # run and then no-ops. NOTE: the group holds at most ONE waiting run — a | |
| # further same-version dispatch displaces (cancels) the waiting duplicate, | |
| # and a watcher following the displaced run reports that as a failure; the | |
| # publish itself is unaffected (the surviving runs no-op or publish). | |
| concurrency: | |
| group: publish-cargo-${{ inputs.version }} | |
| permissions: {} | |
| jobs: | |
| cargo-publish: | |
| runs-on: ubuntu-latest | |
| # Bounds how long a wedged run (hung registry call) can hold this | |
| # workflow's per-version concurrency group before retries can proceed. | |
| timeout-minutes: 45 | |
| permissions: | |
| contents: read | |
| id-token: write | |
| steps: | |
| - name: Validate version input | |
| env: | |
| VERSION: ${{ inputs.version }} | |
| run: | | |
| if ! printf '%s' "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then | |
| echo "::error::'${VERSION}' is not a plain X.Y.Z release version" | |
| exit 1 | |
| fi | |
| - name: Checkout release tag | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| ref: refs/tags/v${{ inputs.version }} | |
| persist-credentials: false | |
| - name: Verify tag carries the requested version | |
| env: | |
| VERSION: ${{ inputs.version }} | |
| run: | | |
| CARGO_VERSION=$(grep '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/') | |
| if [ "$CARGO_VERSION" != "$VERSION" ]; then | |
| echo "::error::tag v${VERSION} carries workspace version ${CARGO_VERSION} — refusing to publish" | |
| exit 1 | |
| fi | |
| - name: Install Rust | |
| # rustup is pre-installed on GitHub-hosted runners. `rustup show` | |
| # reads rust-toolchain.toml in the repo root, then installs the | |
| # pinned channel + listed components if missing. | |
| run: rustup show | |
| - name: Probe crates.io for already-published versions | |
| id: published | |
| env: | |
| VERSION: ${{ inputs.version }} | |
| run: | | |
| # crates.io returns HTTP 200 for a published version and 404 | |
| # otherwise; its crawler policy requires a User-Agent identifying | |
| # the caller. Anything but a definite 200 (including transient | |
| # network errors) falls through to publishing, where `cargo publish` | |
| # gives the authoritative error. | |
| probe() { | |
| curl -fsSL -o /dev/null \ | |
| -H 'User-Agent: socket-patch-release-workflow (https://github.com/SocketDev/socket-patch)' \ | |
| "https://crates.io/api/v1/crates/${1}/${VERSION}" | |
| } | |
| if probe socket-patch-core; then | |
| echo "socket-patch-core ${VERSION} already on crates.io; skipping its publish." | |
| echo "core=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "core=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| if probe socket-patch-cli; then | |
| echo "socket-patch-cli ${VERSION} already on crates.io; skipping its publish." | |
| echo "cli=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "cli=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Authenticate with crates.io | |
| id: crates-io-auth | |
| uses: rust-lang/crates-io-auth-action@b7e9a28eded4986ec6b1fa40eeee8f8f165559ec # v1.0.3 | |
| - name: Publish socket-patch-core | |
| if: steps.published.outputs.core != 'true' | |
| run: cargo publish -p socket-patch-core | |
| env: | |
| CARGO_REGISTRY_TOKEN: ${{ steps.crates-io-auth.outputs.token }} | |
| - name: Wait for crates.io index update | |
| if: steps.published.outputs.core != 'true' | |
| run: sleep 30 | |
| - name: Copy README for CLI crate | |
| run: cp README.md crates/socket-patch-cli/README.md | |
| - name: Publish socket-patch-cli | |
| if: steps.published.outputs.cli != 'true' | |
| run: cargo publish -p socket-patch-cli | |
| env: | |
| CARGO_REGISTRY_TOKEN: ${{ steps.crates-io-auth.outputs.token }} |