@@ -63,14 +63,26 @@ jobs:
6363 with :
6464 version : latest
6565
66- # OIDC trusted publishing requires npm 11.5.1+
67- - name : Update npm for OIDC trusted publishing
68- run : npm install -g npm@latest
66+ - name : Get pnpm store directory
67+ shell : bash
68+ run : echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
69+
70+ - name : Setup pnpm cache
71+ uses : actions/cache@v4
72+ with :
73+ path : ${{ env.STORE_PATH }}
74+ key : ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
75+ restore-keys : |
76+ ${{ runner.os }}-pnpm-store-
6977
70- - name : Set up Git user
78+ # OIDC trusted publishing requires npm 11.5.1+
79+ - name : Update npm and set up Git user
7180 run : |
81+ npm install -g npm@latest &
82+ NPM_PID=$!
7283 git config user.name "${{ github.actor }}"
7384 git config user.email "${{ github.actor }}@users.noreply.github.com"
85+ wait $NPM_PID || { echo "::error::Failed to update npm"; exit 1; }
7486
7587 - name : Determine publish type
7688 id : determine-publish-type
@@ -131,35 +143,76 @@ jobs:
131143 - name : Publish to npm (OIDC)
132144 run : |
133145 DIST_TAG="${{ steps.determine-publish-type.outputs.dist_tag }}"
134- PUBLISHED_PACKAGES="[]"
135146 ROOT_DIR="$(pwd)"
136- PUBLISH_COUNT=0
137147
148+ # Create a temporary directory for publish scripts
149+ mkdir -p "$ROOT_DIR/.publish-tmp"
150+
151+ # Generate publish commands for all packages (use null delimiter for safety)
138152 for pkg_json in packages/*/package.json packages/wallets/*/package.json; do
139153 pkg_dir=$(dirname "$pkg_json")
140154 pkg_name=$(node -p "require('./$pkg_json').name")
141155 pkg_version=$(node -p "require('./$pkg_json').version")
142-
143- echo "📦 Publishing $pkg_name@$pkg_version"
156+ tarball_name=$(echo "$pkg_name" | sed 's/@//;s/\//-/')-$pkg_version.tgz
144157
145158 # Pack with pnpm to resolve catalog: dependencies
146- pnpm --dir "$pkg_dir" pack --pack-destination "$ROOT_DIR"
159+ pnpm --dir "$pkg_dir" pack --pack-destination "$ROOT_DIR/.publish-tmp "
147160
148- tarball_name=$(echo "$pkg_name" | sed 's/@//;s/\//-/')-$pkg_version.tgz
149-
150- if [ -f "$tarball_name" ]; then
151- if npm publish "$tarball_name" --access public --tag "$DIST_TAG" --provenance; then
152- PUBLISHED_PACKAGES=$(echo "$PUBLISHED_PACKAGES" | node -p "JSON.stringify([...JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')), {name:'$pkg_name',version:'$pkg_version'}])")
153- PUBLISH_COUNT=$((PUBLISH_COUNT + 1))
154- fi
155- rm -f "$tarball_name"
161+ if [ -f "$ROOT_DIR/.publish-tmp/$tarball_name" ]; then
162+ # Use null delimiter to safely handle any package names
163+ printf '%s\t%s\t%s\0' "$ROOT_DIR/.publish-tmp/$tarball_name" "$pkg_name" "$pkg_version" >> "$ROOT_DIR/.publish-tmp/packages.txt"
156164 else
157165 echo "⚠️ No tarball found for $pkg_name"
158166 fi
159167 done
160168
169+ # Publish packages in parallel (4 concurrent jobs)
170+ RESULTS_FILE="$ROOT_DIR/.publish-tmp/results.txt"
171+ FAILED_FILE="$ROOT_DIR/.publish-tmp/failed.txt"
172+ touch "$RESULTS_FILE" "$FAILED_FILE"
173+
174+ publish_package() {
175+ IFS=$'\t' read -r tarball pkg_name pkg_version <<< "$1"
176+ echo "📦 Publishing $pkg_name@$pkg_version"
177+ if npm publish "$tarball" --access public --tag "$DIST_TAG" --provenance 2>&1; then
178+ echo "$pkg_name:$pkg_version" >> "$RESULTS_FILE"
179+ else
180+ echo "$pkg_name:$pkg_version" >> "$FAILED_FILE"
181+ echo "::warning::Failed to publish $pkg_name@$pkg_version"
182+ fi
183+ }
184+ export -f publish_package
185+ export DIST_TAG RESULTS_FILE FAILED_FILE
186+
187+ # Run publishes in parallel using null delimiter for safety
188+ if [ -f "$ROOT_DIR/.publish-tmp/packages.txt" ]; then
189+ xargs -0 -P 4 -I {} bash -c 'publish_package "$@"' _ {} < "$ROOT_DIR/.publish-tmp/packages.txt"
190+ fi
191+
192+ # Build results from file
193+ PUBLISH_COUNT=$(wc -l < "$RESULTS_FILE" | tr -d ' ')
194+ FAILED_COUNT=$(wc -l < "$FAILED_FILE" | tr -d ' ')
195+
196+ # Build JSON array efficiently
197+ PUBLISHED_PACKAGES=$(node -e "
198+ const fs = require('fs');
199+ const lines = fs.readFileSync('$RESULTS_FILE', 'utf8').trim().split('\n').filter(Boolean);
200+ const packages = lines.map(line => {
201+ const [name, version] = line.split(':');
202+ return { name, version };
203+ });
204+ console.log(JSON.stringify(packages));
205+ ")
206+
207+ # Cleanup
208+ rm -rf "$ROOT_DIR/.publish-tmp"
209+
161210 echo "{\"publishedPackages\":$PUBLISHED_PACKAGES}" > pnpm-publish-summary.json
162211
212+ if [ "$FAILED_COUNT" -gt 0 ]; then
213+ echo "::warning::$FAILED_COUNT package(s) failed to publish"
214+ fi
215+
163216 if [ "$PUBLISH_COUNT" -eq 0 ]; then
164217 echo "::error::No packages were published. Check npm OIDC trusted publisher configuration."
165218 exit 1
@@ -201,7 +254,7 @@ jobs:
201254 package-bump-hub :
202255 name : ' Package bump hub'
203256 runs-on : ubuntu-latest
204- needs : [ publish, package-bump-layer]
257+ needs : publish
205258 if : |
206259 always() &&
207260 (needs.publish.result == 'success' && needs.publish.outputs.publish_type == 'latest') ||
@@ -218,7 +271,7 @@ jobs:
218271 package-bump-helix :
219272 name : ' Package bump Helix'
220273 runs-on : ubuntu-latest
221- needs : [ publish, package-bump-layer]
274+ needs : publish
222275 if : |
223276 always() &&
224277 (needs.publish.result == 'success' && needs.publish.outputs.publish_type == 'latest') ||
@@ -235,7 +288,7 @@ jobs:
235288 package-bump-explorer :
236289 name : ' Package bump Explorer'
237290 runs-on : ubuntu-latest
238- needs : [ publish, package-bump-layer]
291+ needs : publish
239292 if : |
240293 always() &&
241294 (needs.publish.result == 'success' && needs.publish.outputs.publish_type == 'latest') ||
@@ -252,7 +305,7 @@ jobs:
252305 package-bump-trading-ui :
253306 name : ' Package bump Trading UI'
254307 runs-on : ubuntu-latest
255- needs : [ publish, package-bump-layer]
308+ needs : publish
256309 if : |
257310 always() &&
258311 (needs.publish.result == 'success' && needs.publish.outputs.publish_type == 'latest') ||
@@ -269,7 +322,7 @@ jobs:
269322 package-bump-mito :
270323 name : ' Package bump Mito'
271324 runs-on : ubuntu-latest
272- needs : [ publish, package-bump-layer]
325+ needs : publish
273326 if : |
274327 always() &&
275328 (needs.publish.result == 'success' && needs.publish.outputs.publish_type == 'latest') ||
@@ -286,7 +339,7 @@ jobs:
286339 package-bump-ui-api :
287340 name : ' Package bump UI API'
288341 runs-on : ubuntu-latest
289- needs : [ publish, package-bump-layer]
342+ needs : publish
290343 if : |
291344 always() &&
292345 (needs.publish.result == 'success' && needs.publish.outputs.publish_type == 'latest') ||
@@ -303,7 +356,7 @@ jobs:
303356 package-bump-admin-ui :
304357 name : ' Package bump Admin UI'
305358 runs-on : ubuntu-latest
306- needs : [ publish, package-bump-layer]
359+ needs : publish
307360 if : |
308361 always() &&
309362 (needs.publish.result == 'success' && needs.publish.outputs.publish_type == 'latest') ||
@@ -320,7 +373,7 @@ jobs:
320373 package-bump-do-ui :
321374 name : ' Package bump DO UI'
322375 runs-on : ubuntu-latest
323- needs : [ publish, package-bump-layer]
376+ needs : publish
324377 if : |
325378 always() &&
326379 (needs.publish.result == 'success' && needs.publish.outputs.publish_type == 'latest') ||
0 commit comments