99 branches :
1010 - " main"
1111
12+ permissions :
13+ contents : write
14+
1215jobs :
1316 prepare-matrix :
1417 runs-on : blacksmith-2vcpu-ubuntu-2404
3639 # Get platforms from manifest
3740 if manifest=$(docker manifest inspect "node:$version-alpine" 2>/dev/null); then
3841 # Extract all valid platforms (excluding unknown)
39- platforms=$(echo "$manifest" | jq -r '.manifests[] |
42+ platforms=$(echo "$manifest" | jq -r '.manifests[] |
4043 select(.platform.os != "unknown" and .platform.architecture != "unknown") |
4144 if .platform.variant then
4245 "linux/" + .platform.architecture + "/" + .platform.variant
@@ -155,6 +158,7 @@ jobs:
155158 fi
156159
157160 - name : Build
161+ id : build_image
158162 uses : docker/build-push-action@v7
159163 with :
160164 build-args : |
@@ -168,6 +172,31 @@ jobs:
168172 betterweb/node:${{matrix.tag.major}}
169173 ${{ steps.is_latest.outputs.IS_LATEST == 'true' && 'betterweb/node:latest' || '' }}
170174
175+ - name : Write manifest part
176+ run : |
177+ TAGS=$(jq -nc \
178+ --arg v "${{ steps.parse_version.outputs.PARSED_VERSION }}" \
179+ --arg m "${{ matrix.tag.major }}" \
180+ --arg latest "${{ steps.is_latest.outputs.IS_LATEST }}" \
181+ '[("betterweb/node:" + $v), ("betterweb/node:" + $m)] + (if $latest == "true" then ["betterweb/node:latest"] else [] end)')
182+ PLATFORMS=$(echo "${{ matrix.tag.platforms }}" | jq -Rc 'split(",")')
183+ jq -n \
184+ --arg version "${{ steps.parse_version.outputs.PARSED_VERSION }}" \
185+ --argjson major ${{ matrix.tag.major }} \
186+ --arg variant "base" \
187+ --argjson platforms "$PLATFORMS" \
188+ --argjson tags "$TAGS" \
189+ --arg digest "${{ steps.build_image.outputs.digest }}" \
190+ --argjson is_latest ${{ steps.is_latest.outputs.IS_LATEST }} \
191+ '{version:$version, major:$major, variant:$variant, platforms:$platforms, tags:$tags, digest:$digest, is_latest:$is_latest}' \
192+ > part.json
193+ cat part.json
194+
195+ - uses : actions/upload-artifact@v4
196+ with :
197+ name : manifest-part-base-${{ matrix.tag.major }}
198+ path : part.json
199+
171200 build-dev :
172201 needs : [prepare-matrix, build]
173202 runs-on : blacksmith-2vcpu-ubuntu-2404
@@ -206,6 +235,7 @@ jobs:
206235 fi
207236
208237 - name : Build and push dev image
238+ id : build_image
209239 uses : docker/build-push-action@v7
210240 with :
211241 context : .
@@ -219,6 +249,30 @@ jobs:
219249 betterweb/node:dev-${{matrix.tag.major}}
220250 ${{ steps.is_latest.outputs.IS_LATEST == 'true' && 'betterweb/node:dev' || '' }}
221251
252+ - name : Write manifest part
253+ run : |
254+ TAGS=$(jq -nc \
255+ --arg v "${{ steps.parse_version.outputs.PARSED_VERSION }}" \
256+ --arg m "${{ matrix.tag.major }}" \
257+ --arg latest "${{ steps.is_latest.outputs.IS_LATEST }}" \
258+ '[("betterweb/node:dev-" + $v), ("betterweb/node:dev-" + $m)] + (if $latest == "true" then ["betterweb/node:dev"] else [] end)')
259+ jq -n \
260+ --arg version "${{ steps.parse_version.outputs.PARSED_VERSION }}" \
261+ --argjson major ${{ matrix.tag.major }} \
262+ --arg variant "dev" \
263+ --argjson platforms '["linux/amd64"]' \
264+ --argjson tags "$TAGS" \
265+ --arg digest "${{ steps.build_image.outputs.digest }}" \
266+ --argjson is_latest ${{ steps.is_latest.outputs.IS_LATEST }} \
267+ '{version:$version, major:$major, variant:$variant, platforms:$platforms, tags:$tags, digest:$digest, is_latest:$is_latest}' \
268+ > part.json
269+ cat part.json
270+
271+ - uses : actions/upload-artifact@v4
272+ with :
273+ name : manifest-part-dev-${{ matrix.tag.major }}
274+ path : part.json
275+
222276 build-devcontainers :
223277 needs : prepare-matrix
224278 runs-on : blacksmith-2vcpu-ubuntu-2404
@@ -257,6 +311,7 @@ jobs:
257311 fi
258312
259313 - name : Build and push devcontainer image
314+ id : build_image
260315 uses : docker/build-push-action@v7
261316 with :
262317 context : .
@@ -270,6 +325,30 @@ jobs:
270325 betterweb/node:devcontainer-${{matrix.tag.major}}
271326 ${{ steps.is_latest.outputs.IS_LATEST == 'true' && 'betterweb/node:devcontainer-latest' || '' }}
272327
328+ - name : Write manifest part
329+ run : |
330+ TAGS=$(jq -nc \
331+ --arg v "${{ steps.parse_version.outputs.PARSED_VERSION }}" \
332+ --arg m "${{ matrix.tag.major }}" \
333+ --arg latest "${{ steps.is_latest.outputs.IS_LATEST }}" \
334+ '[("betterweb/node:devcontainer-" + $v), ("betterweb/node:devcontainer-" + $m)] + (if $latest == "true" then ["betterweb/node:devcontainer-latest"] else [] end)')
335+ jq -n \
336+ --arg version "${{ steps.parse_version.outputs.PARSED_VERSION }}" \
337+ --argjson major ${{ matrix.tag.major }} \
338+ --arg variant "devcontainer" \
339+ --argjson platforms '["linux/amd64"]' \
340+ --argjson tags "$TAGS" \
341+ --arg digest "${{ steps.build_image.outputs.digest }}" \
342+ --argjson is_latest ${{ steps.is_latest.outputs.IS_LATEST }} \
343+ '{version:$version, major:$major, variant:$variant, platforms:$platforms, tags:$tags, digest:$digest, is_latest:$is_latest}' \
344+ > part.json
345+ cat part.json
346+
347+ - uses : actions/upload-artifact@v4
348+ with :
349+ name : manifest-part-devcontainer-${{ matrix.tag.major }}
350+ path : part.json
351+
273352 build-dind :
274353 needs : [prepare-matrix, build]
275354 runs-on : blacksmith-2vcpu-ubuntu-2404
@@ -308,6 +387,7 @@ jobs:
308387 fi
309388
310389 - name : Build and push dind image
390+ id : build_image
311391 uses : docker/build-push-action@v7
312392 with :
313393 context : .
@@ -320,3 +400,92 @@ jobs:
320400 betterweb/node:dind-${{steps.parse_version.outputs.PARSED_VERSION}}
321401 betterweb/node:dind-${{matrix.tag.major}}
322402 ${{ steps.is_latest.outputs.IS_LATEST == 'true' && 'betterweb/node:dind-latest' || '' }}
403+
404+ - name : Write manifest part
405+ run : |
406+ TAGS=$(jq -nc \
407+ --arg v "${{ steps.parse_version.outputs.PARSED_VERSION }}" \
408+ --arg m "${{ matrix.tag.major }}" \
409+ --arg latest "${{ steps.is_latest.outputs.IS_LATEST }}" \
410+ '[("betterweb/node:dind-" + $v), ("betterweb/node:dind-" + $m)] + (if $latest == "true" then ["betterweb/node:dind-latest"] else [] end)')
411+ jq -n \
412+ --arg version "${{ steps.parse_version.outputs.PARSED_VERSION }}" \
413+ --argjson major ${{ matrix.tag.major }} \
414+ --arg variant "dind" \
415+ --argjson platforms '["linux/amd64"]' \
416+ --argjson tags "$TAGS" \
417+ --arg digest "${{ steps.build_image.outputs.digest }}" \
418+ --argjson is_latest ${{ steps.is_latest.outputs.IS_LATEST }} \
419+ '{version:$version, major:$major, variant:$variant, platforms:$platforms, tags:$tags, digest:$digest, is_latest:$is_latest}' \
420+ > part.json
421+ cat part.json
422+
423+ - uses : actions/upload-artifact@v4
424+ with :
425+ name : manifest-part-dind-${{ matrix.tag.major }}
426+ path : part.json
427+
428+ publish-manifest :
429+ needs : [prepare-matrix, build, build-dev, build-devcontainers, build-dind]
430+ runs-on : blacksmith-2vcpu-ubuntu-2404
431+ steps :
432+ - uses : actions/download-artifact@v4
433+ with :
434+ pattern : manifest-part-*
435+ merge-multiple : true
436+ path : parts/
437+
438+ - name : Merge manifest parts
439+ run : |
440+ TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
441+ LATEST_VERSION="${{ needs.prepare-matrix.outputs.latest }}"
442+ LATEST_VERSION_STRIPPED="${LATEST_VERSION#v}"
443+
444+ jq -s \
445+ --arg ts "$TIMESTAMP" \
446+ --arg latest "$LATEST_VERSION_STRIPPED" \
447+ --arg run_id "${{ github.run_id }}" \
448+ --arg run_number "${{ github.run_number }}" \
449+ --arg sha "${{ github.sha }}" \
450+ '{
451+ build: {
452+ run_id: ($run_id | tonumber),
453+ run_number: ($run_number | tonumber),
454+ sha: $sha,
455+ timestamp: $ts
456+ },
457+ latest: $latest,
458+ builds: (
459+ group_by(.version)
460+ | map({
461+ version: .[0].version,
462+ major: .[0].major,
463+ is_latest: .[0].is_latest,
464+ platforms: (map(.platforms) | add | unique),
465+ variants: (
466+ map({(.variant): {tags: .tags, platforms: .platforms, digest: .digest}}) | add
467+ )
468+ })
469+ | sort_by(.major) | reverse
470+ )
471+ }' parts/*.json > manifest.json
472+ cat manifest.json
473+
474+ - uses : actions/upload-artifact@v4
475+ with :
476+ name : manifest
477+ path : manifest.json
478+
479+ - name : Create release
480+ env :
481+ GH_TOKEN : ${{ github.token }}
482+ run : |
483+ TAG="build-${{ github.run_number }}"
484+ TITLE="Build #${{ github.run_number }} — node ${{ needs.prepare-matrix.outputs.latest }}"
485+ # Drop existing release+tag if re-running the same workflow.
486+ gh release delete "$TAG" -y --cleanup-tag 2>/dev/null || true
487+ gh release create "$TAG" \
488+ --title "$TITLE" \
489+ --notes "Auto-generated manifest of betterweb/node multi-arch builds. Fetch latest via: https://github.com/${{ github.repository }}/releases/latest/download/manifest.json" \
490+ --latest \
491+ manifest.json
0 commit comments