Skip to content

Commit aea3219

Browse files
Bulat Yapparovclaude
andcommitted
ci: fail loud on npm publish errors that aren't EPUBLISHCONFLICT (#51)
The publish workflow used `|| true` after every `npm publish` step to tolerate "version already published" errors during reruns. The blast radius: every other failure mode was also silently masked, including ENEEDAUTH cascades. This caused the v0.3.1 silent failure (2026-04-03) and the v0.3.2 release saga (2026-04-11) - 14 publishes in a single run failed to authenticate but all reported success. This change replaces the unconditional tolerance with a wrapper that exits non-zero on any failure unless the npm output matches a known "already published" pattern (EPUBLISHCONFLICT, E409, "cannot publish over", "already published"). Also fails loud if `bun pm pack` produces zero .tgz files, which the previous glob-based `npm publish *.tgz` invocation would have silently tolerated. Closes #51 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
1 parent 9cba95b commit aea3219

1 file changed

Lines changed: 111 additions & 12 deletions

File tree

‎.github/workflows/publish.yml‎

Lines changed: 111 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,27 +53,107 @@ jobs:
5353
5454
- name: Publish @aictrl/util
5555
working-directory: packages/util
56-
run: bun pm pack && npm publish *.tgz --access public --provenance || true
56+
run: |
57+
# Pack, then publish the resulting tarball. We tolerate ONLY the
58+
# "version already published" error (EPUBLISHCONFLICT / E409 /
59+
# "cannot publish over" / "already published") so reruns after a
60+
# partial failure still succeed. Every other error - ENEEDAUTH,
61+
# network, etc - must fail loud. See issue #51 for the v0.3.1 /
62+
# v0.3.2 silent-failure post-mortem that motivated this wrapper.
63+
bun pm pack
64+
tarball=$(ls -1 *.tgz 2>/dev/null | head -n1)
65+
if [ -z "$tarball" ]; then
66+
echo "::error::bun pm pack produced no .tgz files in $(pwd)"
67+
exit 1
68+
fi
69+
set +e
70+
output=$(npm publish "$tarball" --access public --provenance 2>&1)
71+
code=$?
72+
set -e
73+
echo "$output"
74+
if [ $code -ne 0 ]; then
75+
if echo "$output" | grep -qE 'EPUBLISHCONFLICT|E409|cannot publish over|already published'; then
76+
echo "::notice::Tolerating 'already published' error for @aictrl/util"
77+
else
78+
exit $code
79+
fi
80+
fi
5781
5882
- name: Publish @aictrl/plugin
5983
working-directory: packages/plugin
60-
run: bun pm pack && npm publish *.tgz --access public --provenance || true
84+
run: |
85+
# See @aictrl/util step for wrapper rationale (issue #51).
86+
bun pm pack
87+
tarball=$(ls -1 *.tgz 2>/dev/null | head -n1)
88+
if [ -z "$tarball" ]; then
89+
echo "::error::bun pm pack produced no .tgz files in $(pwd)"
90+
exit 1
91+
fi
92+
set +e
93+
output=$(npm publish "$tarball" --access public --provenance 2>&1)
94+
code=$?
95+
set -e
96+
echo "$output"
97+
if [ $code -ne 0 ]; then
98+
if echo "$output" | grep -qE 'EPUBLISHCONFLICT|E409|cannot publish over|already published'; then
99+
echo "::notice::Tolerating 'already published' error for @aictrl/plugin"
100+
else
101+
exit $code
102+
fi
103+
fi
61104
62105
- name: Publish @aictrl/sdk
63106
working-directory: packages/sdk
64-
run: bun pm pack && npm publish *.tgz --access public --provenance || true
107+
run: |
108+
# See @aictrl/util step for wrapper rationale (issue #51).
109+
bun pm pack
110+
tarball=$(ls -1 *.tgz 2>/dev/null | head -n1)
111+
if [ -z "$tarball" ]; then
112+
echo "::error::bun pm pack produced no .tgz files in $(pwd)"
113+
exit 1
114+
fi
115+
set +e
116+
output=$(npm publish "$tarball" --access public --provenance 2>&1)
117+
code=$?
118+
set -e
119+
echo "$output"
120+
if [ $code -ne 0 ]; then
121+
if echo "$output" | grep -qE 'EPUBLISHCONFLICT|E409|cannot publish over|already published'; then
122+
echo "::notice::Tolerating 'already published' error for @aictrl/sdk"
123+
else
124+
exit $code
125+
fi
126+
fi
65127
66128
- name: Publish platform binary packages
67129
working-directory: packages/cli/dist/@aictrl
68130
run: |
69-
# Publish every @aictrl/cli-<platform>-<arch>[-variant] package that the
70-
# build step produced. Each directory contains a generated package.json
71-
# stamped with the release version. Individual failures (e.g. version
72-
# already published on a rerun) are tolerated to match the convention
73-
# used by the other publish steps in this workflow.
74-
for dir in */; do
75-
echo "Publishing ${dir%/}"
76-
(cd "$dir" && npm publish --access public --provenance) || true
131+
# Publish every @aictrl/cli-<platform>-<arch>[-variant] package that
132+
# the build step produced. Each directory contains a generated
133+
# package.json stamped with the release version. Individual
134+
# "already published" errors are tolerated (for reruns), but every
135+
# other failure - ENEEDAUTH, network, etc - fails loud. See #51.
136+
shopt -s nullglob
137+
dirs=(*/)
138+
if [ ${#dirs[@]} -eq 0 ]; then
139+
echo "::error::No platform binary package directories found in $(pwd)"
140+
exit 1
141+
fi
142+
for dir in "${dirs[@]}"; do
143+
name="${dir%/}"
144+
echo "Publishing ${name}"
145+
set +e
146+
output=$(cd "$dir" && npm publish --access public --provenance 2>&1)
147+
code=$?
148+
set -e
149+
echo "$output"
150+
if [ $code -ne 0 ]; then
151+
if echo "$output" | grep -qE 'EPUBLISHCONFLICT|E409|cannot publish over|already published'; then
152+
echo "::notice::Tolerating 'already published' error for ${name}"
153+
else
154+
exit $code
155+
fi
156+
fi
77157
done
78158
79159
- name: Strip bundled deps and refresh platform binary optionalDependencies
@@ -133,4 +213,23 @@ jobs:
133213
134214
- name: Publish @aictrl/cli
135215
working-directory: packages/cli
136-
run: bun pm pack && npm publish *.tgz --access public --provenance
216+
run: |
217+
# See @aictrl/util step for wrapper rationale (issue #51).
218+
bun pm pack
219+
tarball=$(ls -1 *.tgz 2>/dev/null | head -n1)
220+
if [ -z "$tarball" ]; then
221+
echo "::error::bun pm pack produced no .tgz files in $(pwd)"
222+
exit 1
223+
fi
224+
set +e
225+
output=$(npm publish "$tarball" --access public --provenance 2>&1)
226+
code=$?
227+
set -e
228+
echo "$output"
229+
if [ $code -ne 0 ]; then
230+
if echo "$output" | grep -qE 'EPUBLISHCONFLICT|E409|cannot publish over|already published'; then
231+
echo "::notice::Tolerating 'already published' error for @aictrl/cli"
232+
else
233+
exit $code
234+
fi
235+
fi

0 commit comments

Comments
 (0)