From 715266113990d84af48af30c57c99e77a2de8d07 Mon Sep 17 00:00:00 2001 From: Betim Drenica Date: Sat, 24 Oct 2026 00:36:33 +0200 Subject: [PATCH] ci: publish once per release, and treat a version another run just published as done release-please publishes three GitHub releases for one linked version, so publish-npm ran three times for 0.2.1. The first published all three packages; the queued one after it still saw voice-client-core 0.2.1 as missing, because the registry lagged, tried again and failed with E409. Only voice-client's release now runs the job, and the other two are skipped. bin/publish-npm checks with --prefer-online, and when a publish fails it looks again for up to 30 seconds before failing, so a version that is already there counts as published. --- .github/workflows/publish-npm.yml | 7 +++++-- bin/publish-npm | 18 ++++++++++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index 9e771e4..290b056 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -19,8 +19,10 @@ on: release: types: [published] -# One release per package arrives at once. Runs queue, so the first publishes every new version -# and the rest find nothing left to publish. +# The three packages share one version (linked-versions), so release-please publishes three +# GitHub releases at once. bin/publish-npm publishes every package whose version is new, so one +# run is enough: only voice-client's release runs the job, and the other two are skipped. Runs +# still queue, for a manual run that overlaps one. concurrency: group: publish-npm cancel-in-progress: false @@ -28,6 +30,7 @@ concurrency: jobs: publish: name: publish + if: github.event_name == 'workflow_dispatch' || startsWith(github.event.release.tag_name, 'voice-client-v') runs-on: ubuntu-latest permissions: contents: read diff --git a/bin/publish-npm b/bin/publish-npm index a09850d..0f812d3 100644 --- a/bin/publish-npm +++ b/bin/publish-npm @@ -23,7 +23,9 @@ for package in $(./scripts/utils/packages); do PACKAGE_NAME="$(jq -r -e '.name' ./package.json)" VERSION="$(jq -r -e '.version' ./package.json)" - if npm view "$PACKAGE_NAME@$VERSION" version >/dev/null 2>&1; then + # --prefer-online skips npm's local cache. The registry itself can still lag a version that + # was published seconds ago, which the publish below allows for. + if npm view --prefer-online "$PACKAGE_NAME@$VERSION" version >/dev/null 2>&1; then echo "$PACKAGE_NAME@$VERSION is already published, skipping" cd - >/dev/null continue @@ -57,6 +59,18 @@ for package in $(./scripts/utils/packages); do TAG="latest" fi - pnpm publish --npm-path "$NPM_PATH" --no-git-checks --tag "$TAG" + # npm refuses a version it already has with E409. Another run that published it moments ago + # is not a failure, so look again, for up to 30 seconds of registry lag, before failing. + if ! pnpm publish --npm-path "$NPM_PATH" --no-git-checks --tag "$TAG"; then + for _ in 1 2 3 4 5 6; do + if npm view --prefer-online "$PACKAGE_NAME@$VERSION" version >/dev/null 2>&1; then + echo "$PACKAGE_NAME@$VERSION was published by another run, skipping" + cd - >/dev/null + continue 2 + fi + sleep 5 + done + exit 1 + fi cd - >/dev/null done