Skip to content

Commit 5c46067

Browse files
committed
Emit build manifest.json as release asset and artifact
Each build job writes a manifest part (version, variant, platforms, tags, digest) and uploads it as an artifact. New publish-manifest job merges parts and creates a GitHub Release with manifest.json so consumers can fetch the latest build map at a stable URL.
1 parent 961adb0 commit 5c46067

1 file changed

Lines changed: 170 additions & 1 deletion

File tree

‎.github/workflows/buildAndPub.yml‎

Lines changed: 170 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ on:
99
branches:
1010
- "main"
1111

12+
permissions:
13+
contents: write
14+
1215
jobs:
1316
prepare-matrix:
1417
runs-on: blacksmith-2vcpu-ubuntu-2404
@@ -36,7 +39,7 @@ jobs:
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

Comments
 (0)