diff --git a/.github/workflows/moq-release.yml b/.github/workflows/moq-release.yml index 4487d3ff9..f1484d27b 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 @@ -17,21 +25,41 @@ 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 + 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