diff --git a/.github/scripts/publish-if-new.sh b/.github/scripts/publish-if-new.sh new file mode 100755 index 0000000..96c1d20 --- /dev/null +++ b/.github/scripts/publish-if-new.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# publish-if-new.sh — pack-then-publish wrapper for the publish workflow. +# +# Tolerates ONLY "version already published" errors so reruns after a +# partial failure still succeed. Every other error (ENEEDAUTH, network, +# etc) fails loud. See issue #51 for the v0.3.1 / v0.3.2 silent-failure +# post-mortem that motivated this wrapper. +# +# Usage: +# .github/scripts/publish-if-new.sh +# +# Must be run from the package's working directory (where bun pm pack +# will produce the .tgz). The is used only for log +# annotations (e.g. "@aictrl/util"). + +set -euo pipefail + +label="${1:?Usage: publish-if-new.sh }" + +# Clean stale tarballs so we always publish the freshly packed one. +rm -f *.tgz + +bun pm pack + +# Use nullglob array to avoid pipefail exit on no matches (ls *.tgz +# returns exit 2 when nothing matches, which pipefail propagates). +shopt -s nullglob +tarballs=(*.tgz) +shopt -u nullglob + +if [ ${#tarballs[@]} -eq 0 ]; then + echo "::error::bun pm pack produced no .tgz files in $(pwd)" + exit 1 +fi + +if [ ${#tarballs[@]} -gt 1 ]; then + echo "::warning::bun pm pack produced ${#tarballs[@]} .tgz files in $(pwd), publishing first: ${tarballs[0]}" +fi + +tarball="${tarballs[0]}" + +set +e +output=$(npm publish "$tarball" --access public --provenance 2>&1) +code=$? +set -e + +echo "$output" + +if [ $code -ne 0 ]; then + if echo "$output" | grep -qE 'EPUBLISHCONFLICT|E409|cannot publish over|already published'; then + echo "::notice::Tolerating 'already published' error for ${label}" + else + exit $code + fi +fi diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7a73c48..cb8ddcd 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -53,27 +53,45 @@ jobs: - name: Publish @aictrl/util working-directory: packages/util - run: bun pm pack && npm publish *.tgz --access public --provenance || true + run: ${{ github.workspace }}/.github/scripts/publish-if-new.sh "@aictrl/util" - name: Publish @aictrl/plugin working-directory: packages/plugin - run: bun pm pack && npm publish *.tgz --access public --provenance || true + run: ${{ github.workspace }}/.github/scripts/publish-if-new.sh "@aictrl/plugin" - name: Publish @aictrl/sdk working-directory: packages/sdk - run: bun pm pack && npm publish *.tgz --access public --provenance || true + run: ${{ github.workspace }}/.github/scripts/publish-if-new.sh "@aictrl/sdk" - name: Publish platform binary packages working-directory: packages/cli/dist/@aictrl run: | - # Publish every @aictrl/cli--[-variant] package that the - # build step produced. Each directory contains a generated package.json - # stamped with the release version. Individual failures (e.g. version - # already published on a rerun) are tolerated to match the convention - # used by the other publish steps in this workflow. - for dir in */; do - echo "Publishing ${dir%/}" - (cd "$dir" && npm publish --access public --provenance) || true + # Publish every @aictrl/cli--[-variant] package that + # the build step produced. Each directory contains a generated + # package.json stamped with the release version. Individual + # "already published" errors are tolerated (for reruns), but every + # other failure - ENEEDAUTH, network, etc - fails loud. See #51. + shopt -s nullglob + dirs=(*/) + if [ ${#dirs[@]} -eq 0 ]; then + echo "::error::No platform binary package directories found in $(pwd)" + exit 1 + fi + for dir in "${dirs[@]}"; do + name="${dir%/}" + echo "Publishing ${name}" + set +e + output=$(cd "$dir" && npm publish --access public --provenance 2>&1) + code=$? + set -e + echo "$output" + if [ $code -ne 0 ]; then + if echo "$output" | grep -qE 'EPUBLISHCONFLICT|E409|cannot publish over|already published'; then + echo "::notice::Tolerating 'already published' error for ${name}" + else + exit $code + fi + fi done - name: Strip bundled deps and refresh platform binary optionalDependencies @@ -133,4 +151,4 @@ jobs: - name: Publish @aictrl/cli working-directory: packages/cli - run: bun pm pack && npm publish *.tgz --access public --provenance + run: ${{ github.workspace }}/.github/scripts/publish-if-new.sh "@aictrl/cli"