From 1f46696693c0892ff785bf5cf1ef4c11b51b9a33 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sun, 27 Sep 2026 19:21:14 -0700 Subject: [PATCH 1/2] ci: make the release workflow safe to rerun Publishes one crate at a time in dependency order, skips versions already in the crates.io index, and waits for each to reach the index before the next. A workflow_dispatch with an existing tag finishes a release that stopped partway, as v1.3.2 did when cargo's 60s index wait timed out. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/moq-release.yml | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/.github/workflows/moq-release.yml b/.github/workflows/moq-release.yml index 4487d3ff9..a959aff09 100644 --- a/.github/workflows/moq-release.yml +++ b/.github/workflows/moq-release.yml @@ -1,6 +1,9 @@ # Publishes moq-noq-proto, moq-noq-udp, moq-noq, and web-transport-moq when a `v*` tag # is pushed. The tag must match `workspace.package.version`. # +# Crates already on crates.io are skipped, so a run that stopped partway can be finished +# by dispatching this workflow with the same tag. +# # Uses crates.io trusted publishing, so each crate must list this repository # and workflow as a trusted publisher. The very first version of a crate has to # be published with a token from a maintainer's machine. @@ -10,6 +13,11 @@ on: push: tags: - "v*" + workflow_dispatch: + inputs: + tag: + description: Existing tag to publish, such as v1.3.2 + required: true permissions: contents: read @@ -21,17 +29,36 @@ jobs: environment: release permissions: id-token: write + env: + TAG: ${{ inputs.tag || github.ref_name }} steps: - uses: actions/checkout@v6 with: + ref: refs/tags/${{ env.TAG }} persist-credentials: false - uses: dtolnay/rust-toolchain@stable - name: Tag matches the workspace version run: | version=$(cargo metadata --format-version=1 --no-deps | jq -r '.packages[] | select(.name == "moq-noq") | .version') - test "v$version" = "${GITHUB_REF_NAME}" || { echo "tag ${GITHUB_REF_NAME} but Cargo.toml says $version"; exit 1; } + test "v$version" = "$TAG" || { echo "tag $TAG but Cargo.toml says $version"; exit 1; } - uses: rust-lang/crates-io-auth-action@v1 id: auth - - run: cargo publish --workspace --locked + # One crate at a time, in dependency order. Cargo waits only 60s for a published crate + # to reach the index (longer needs a nightly flag), and the next crate cannot build + # until it does, so wait here instead. + - name: Publish env: CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} + run: | + version=${TAG#v} + for crate in moq-noq-proto moq-noq-udp moq-noq web-transport-moq; do + # Sparse index path for names of four or more characters. + listed() { curl -sf "https://index.crates.io/${crate:0:2}/${crate:2:2}/$crate" | grep -qF "\"vers\":\"$version\""; } + if listed; then + echo "$crate $version is already published" + continue + fi + cargo publish -p "$crate" --locked + for _ in $(seq 60); do listed && break; sleep 10; done + listed || { echo "$crate $version is not in the index after 10 minutes"; exit 1; } + done From ba69cdb363fcad530d7283f633d29f71ea3608c3 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sun, 27 Sep 2026 19:25:04 -0700 Subject: [PATCH 2/2] ci: give the release job room for every index wait Co-Authored-By: Claude Opus 5.5 --- .github/workflows/moq-release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/moq-release.yml b/.github/workflows/moq-release.yml index a959aff09..f1484d27b 100644 --- a/.github/workflows/moq-release.yml +++ b/.github/workflows/moq-release.yml @@ -25,7 +25,8 @@ permissions: jobs: publish: runs-on: ubuntu-latest - timeout-minutes: 30 + # Room for every crate's index wait below. + timeout-minutes: 60 environment: release permissions: id-token: write