Skip to content

Commit 8a4e4d7

Browse files
Bulat Yapparovclaude
andcommitted
ci: extract publish wrapper to shared script, fix pipefail bug
The pack-then-publish wrapper was duplicated across 4 steps. Extract to .github/scripts/publish-if-new.sh so changes to the error-pattern regex or wrapper logic only need to happen in one place. Also fixes a real bug: GitHub Actions runs `bash -eo pipefail` by default, so `ls -1 *.tgz 2>/dev/null | head -n1` exits immediately (exit code 2 from ls propagated by pipefail) when no .tgz files exist, making the subsequent `if [ -z "$tarball" ]` guard and its ::error:: annotation dead code. Replaced with a nullglob array, matching the pattern already used in the platform binary step. Added a warning annotation if bun pm pack produces multiple .tgz files (unexpected, but now visible instead of silently picking the first). Refs #51 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
1 parent e3a3acd commit 8a4e4d7

2 files changed

Lines changed: 59 additions & 89 deletions

File tree

‎.github/scripts/publish-if-new.sh‎

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/env bash
2+
# publish-if-new.sh — pack-then-publish wrapper for the publish workflow.
3+
#
4+
# Tolerates ONLY "version already published" errors so reruns after a
5+
# partial failure still succeed. Every other error (ENEEDAUTH, network,
6+
# etc) fails loud. See issue #51 for the v0.3.1 / v0.3.2 silent-failure
7+
# post-mortem that motivated this wrapper.
8+
#
9+
# Usage:
10+
# .github/scripts/publish-if-new.sh <package-label>
11+
#
12+
# Must be run from the package's working directory (where bun pm pack
13+
# will produce the .tgz). The <package-label> is used only for log
14+
# annotations (e.g. "@aictrl/util").
15+
16+
set -euo pipefail
17+
18+
label="${1:?Usage: publish-if-new.sh <package-label>}"
19+
20+
# Clean stale tarballs so we always publish the freshly packed one.
21+
rm -f *.tgz
22+
23+
bun pm pack
24+
25+
# Use nullglob array to avoid pipefail exit on no matches (ls *.tgz
26+
# returns exit 2 when nothing matches, which pipefail propagates).
27+
shopt -s nullglob
28+
tarballs=(*.tgz)
29+
shopt -u nullglob
30+
31+
if [ ${#tarballs[@]} -eq 0 ]; then
32+
echo "::error::bun pm pack produced no .tgz files in $(pwd)"
33+
exit 1
34+
fi
35+
36+
if [ ${#tarballs[@]} -gt 1 ]; then
37+
echo "::warning::bun pm pack produced ${#tarballs[@]} .tgz files in $(pwd), publishing first: ${tarballs[0]}"
38+
fi
39+
40+
tarball="${tarballs[0]}"
41+
42+
set +e
43+
output=$(npm publish "$tarball" --access public --provenance 2>&1)
44+
code=$?
45+
set -e
46+
47+
echo "$output"
48+
49+
if [ $code -ne 0 ]; then
50+
if echo "$output" | grep -qE 'EPUBLISHCONFLICT|E409|cannot publish over|already published'; then
51+
echo "::notice::Tolerating 'already published' error for ${label}"
52+
else
53+
exit $code
54+
fi
55+
fi

‎.github/workflows/publish.yml‎

Lines changed: 4 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -53,80 +53,15 @@ jobs:
5353
5454
- name: Publish @aictrl/util
5555
working-directory: packages/util
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-
rm -f *.tgz
64-
bun pm pack
65-
tarball=$(ls -1 *.tgz 2>/dev/null | head -n1)
66-
if [ -z "$tarball" ]; then
67-
echo "::error::bun pm pack produced no .tgz files in $(pwd)"
68-
exit 1
69-
fi
70-
set +e
71-
output=$(npm publish "$tarball" --access public --provenance 2>&1)
72-
code=$?
73-
set -e
74-
echo "$output"
75-
if [ $code -ne 0 ]; then
76-
if echo "$output" | grep -qE 'EPUBLISHCONFLICT|E409|cannot publish over|already published'; then
77-
echo "::notice::Tolerating 'already published' error for @aictrl/util"
78-
else
79-
exit $code
80-
fi
81-
fi
56+
run: ${{ github.workspace }}/.github/scripts/publish-if-new.sh "@aictrl/util"
8257

8358
- name: Publish @aictrl/plugin
8459
working-directory: packages/plugin
85-
run: |
86-
# See @aictrl/util step for wrapper rationale (issue #51).
87-
rm -f *.tgz
88-
bun pm pack
89-
tarball=$(ls -1 *.tgz 2>/dev/null | head -n1)
90-
if [ -z "$tarball" ]; then
91-
echo "::error::bun pm pack produced no .tgz files in $(pwd)"
92-
exit 1
93-
fi
94-
set +e
95-
output=$(npm publish "$tarball" --access public --provenance 2>&1)
96-
code=$?
97-
set -e
98-
echo "$output"
99-
if [ $code -ne 0 ]; then
100-
if echo "$output" | grep -qE 'EPUBLISHCONFLICT|E409|cannot publish over|already published'; then
101-
echo "::notice::Tolerating 'already published' error for @aictrl/plugin"
102-
else
103-
exit $code
104-
fi
105-
fi
60+
run: ${{ github.workspace }}/.github/scripts/publish-if-new.sh "@aictrl/plugin"
10661

10762
- name: Publish @aictrl/sdk
10863
working-directory: packages/sdk
109-
run: |
110-
# See @aictrl/util step for wrapper rationale (issue #51).
111-
rm -f *.tgz
112-
bun pm pack
113-
tarball=$(ls -1 *.tgz 2>/dev/null | head -n1)
114-
if [ -z "$tarball" ]; then
115-
echo "::error::bun pm pack produced no .tgz files in $(pwd)"
116-
exit 1
117-
fi
118-
set +e
119-
output=$(npm publish "$tarball" --access public --provenance 2>&1)
120-
code=$?
121-
set -e
122-
echo "$output"
123-
if [ $code -ne 0 ]; then
124-
if echo "$output" | grep -qE 'EPUBLISHCONFLICT|E409|cannot publish over|already published'; then
125-
echo "::notice::Tolerating 'already published' error for @aictrl/sdk"
126-
else
127-
exit $code
128-
fi
129-
fi
64+
run: ${{ github.workspace }}/.github/scripts/publish-if-new.sh "@aictrl/sdk"
13065

13166
- name: Publish platform binary packages
13267
working-directory: packages/cli/dist/@aictrl
@@ -216,24 +151,4 @@ jobs:
216151
217152
- name: Publish @aictrl/cli
218153
working-directory: packages/cli
219-
run: |
220-
# See @aictrl/util step for wrapper rationale (issue #51).
221-
rm -f *.tgz
222-
bun pm pack
223-
tarball=$(ls -1 *.tgz 2>/dev/null | head -n1)
224-
if [ -z "$tarball" ]; then
225-
echo "::error::bun pm pack produced no .tgz files in $(pwd)"
226-
exit 1
227-
fi
228-
set +e
229-
output=$(npm publish "$tarball" --access public --provenance 2>&1)
230-
code=$?
231-
set -e
232-
echo "$output"
233-
if [ $code -ne 0 ]; then
234-
if echo "$output" | grep -qE 'EPUBLISHCONFLICT|E409|cannot publish over|already published'; then
235-
echo "::notice::Tolerating 'already published' error for @aictrl/cli"
236-
else
237-
exit $code
238-
fi
239-
fi
154+
run: ${{ github.workspace }}/.github/scripts/publish-if-new.sh "@aictrl/cli"

0 commit comments

Comments
 (0)