Skip to content

Publish crates.io 5.0.0 [38310343691-1] #1

Publish crates.io 5.0.0 [38310343691-1]

Publish crates.io 5.0.0 [38310343691-1] #1

Workflow file for this run

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 }}