@norskvideo/ctl-dev-kit 0.1.27 → 0.1.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,21 +1,43 @@
1
- # Build the product image on every push to main (and on demand), on the org's
2
- # self-hosted x64 pool inside `nix develop` (bun + cargo/rustc from flake.nix).
3
- # Proves the repo builds standalone against the published @norskvideo/ctl-* +
4
- # @norskvideo/norsk-* packages. A deployed product sets PUBLISH_IMAGE to its
5
- # Docker Hub repo (norskvideo org) and the built image is pushed there; a product
6
- # with an empty PUBLISH_IMAGE builds as a standalone-build proof only and
7
- # publishes nothing. Single-sourced in @norskvideo/ctl-dev-kit
8
- # (conventions/build-image.yml) and drift-gated edit the dev-kit source, never
9
- # the copy. Only the PUBLISH_IMAGE env and the notify job's product: key are
10
- # per-repo. Single-arch (amd64) to start; multi-arch is a follow-up. Repo-local
11
- # for now; to be hoisted into id3as/ci-workflows as a reusable workflow
12
- # (RFC 0001 Workstream E).
1
+ # Build + publish a PRODUCT container image, multi-arch (linux/amd64 +
2
+ # linux/arm64), to Docker Hub. Single-sourced in @norskvideo/ctl-dev-kit
3
+ # (conventions/build-image.yml) and drift-gated -- edit the dev-kit source, never
4
+ # the copy.
5
+ #
6
+ # Multi-arch house style: native build per arch (no QEMU), each arch pushes its
7
+ # own `:<label>-<arch>` tag to Docker Hub, then a publish job combines them with
8
+ # `docker buildx imagetools create` into the multi-arch manifest. Each publish
9
+ # writes two tags:
10
+ # <repo>:<label> immutable, label = YYYY-MM-DD-<sha8> (what deployments pin)
11
+ # <repo>:<channel> moving (latest | rc | nightly)
12
+ #
13
+ # The one per-repo value is the masked PUBLISH_IMAGE env: set to a product's
14
+ # Docker Hub repo (norskvideo org) it builds + publishes both arches; left empty
15
+ # the build runs as a standalone-build proof (both arches) and publishes nothing
16
+ # -- for a product that is not deployed yet.
17
+ #
18
+ # CHANNEL: push-to-main publishes `latest` (matches the retired in-monorepo
19
+ # pipeline, so :latest + the dated tags stay fresh for installers/deployments).
20
+ # workflow_dispatch can publish any channel. When the product channel model
21
+ # (rc -> latest promotion) lands, flip the push default to `nightly` and let the
22
+ # promotion gate move `latest`.
23
+ #
24
+ # Repo-local for now; to be hoisted into id3as/ci-workflows as a reusable
25
+ # workflow (RFC 0001 Workstream E).
13
26
  name: build-image
14
27
 
15
28
  on:
16
29
  push:
17
30
  branches: [main]
18
31
  workflow_dispatch:
32
+ inputs:
33
+ channel:
34
+ description: "Moving channel tag to publish (latest | rc | nightly)."
35
+ type: string
36
+ default: latest
37
+ dry_run:
38
+ description: "Build + stage both arches, skip the Docker Hub publish."
39
+ type: boolean
40
+ default: false
19
41
 
20
42
  permissions:
21
43
  contents: read
@@ -32,10 +54,44 @@ env:
32
54
  PUBLISH_IMAGE: ""
33
55
 
34
56
  jobs:
35
- build:
57
+ # Compute the immutable label ONCE, so both arch builds and the manifest share
58
+ # it (a per-job `date` could straddle midnight and disagree).
59
+ label:
36
60
  runs-on: x64
61
+ outputs:
62
+ label: ${{ steps.gen.outputs.label }}
63
+ channel: ${{ steps.gen.outputs.channel }}
64
+ # `publish` is derived here (in a step, where the env context is readable)
65
+ # because the env context is NOT available in a job-level `if:` -- the
66
+ # publish job gates on this output instead of on PUBLISH_IMAGE directly.
67
+ publish: ${{ steps.gen.outputs.publish }}
68
+ steps:
69
+ - uses: actions/checkout@v5
70
+ with:
71
+ clean: false
72
+ - id: gen
73
+ run: |
74
+ label="$(date -u +%Y-%m-%d)-$(git rev-parse --short=8 HEAD)"
75
+ channel="${{ github.event.inputs.channel || 'latest' }}"
76
+ if [ -n "${PUBLISH_IMAGE}" ]; then publish=true; else publish=false; fi
77
+ echo "label=${label}" >> "$GITHUB_OUTPUT"
78
+ echo "channel=${channel}" >> "$GITHUB_OUTPUT"
79
+ echo "publish=${publish}" >> "$GITHUB_OUTPUT"
80
+ echo "label=${label} channel=${channel} publish=${publish}"
81
+
82
+ build:
83
+ needs: label
84
+ strategy:
85
+ fail-fast: false
86
+ matrix:
87
+ include:
88
+ - runner: x64
89
+ arch: amd64
90
+ - runner: ar-arm-vm
91
+ arch: arm64
92
+ runs-on: ${{ matrix.runner }}
37
93
  steps:
38
- # clean: false -- the integration suite (shared x64 pool) leaves root-owned
94
+ # clean: false -- the integration suite (shared pool) leaves root-owned
39
95
  # bind-mount dirs under test-temp/ that a non-root git clean can't remove
40
96
  # (EACCES). This job never needs them; skip the clean so it doesn't choke on
41
97
  # another workflow's leftovers.
@@ -43,12 +99,12 @@ jobs:
43
99
  with:
44
100
  clean: false
45
101
 
46
- - name: Build product image (copy-only, via the dev-kit driver)
102
+ - name: Build product image (copy-only, via the dev-kit driver, native ${{ matrix.arch }})
47
103
  run: |
48
104
  if [ -n "${PUBLISH_IMAGE}" ]; then
49
- IMAGE_TAG="${PUBLISH_IMAGE}:${{ github.sha }}"
105
+ IMAGE_TAG="${PUBLISH_IMAGE}:${{ needs.label.outputs.label }}-${{ matrix.arch }}"
50
106
  else
51
- IMAGE_TAG="norsk-ctl-product:${{ github.sha }}"
107
+ IMAGE_TAG="norsk-ctl-product:${{ needs.label.outputs.label }}-${{ matrix.arch }}"
52
108
  fi
53
109
  echo "IMAGE_TAG=${IMAGE_TAG}" >> "$GITHUB_ENV"
54
110
  export IMAGE_TAG
@@ -65,26 +121,51 @@ jobs:
65
121
  username: norskvideo
66
122
  password: ${{ secrets.DOCKER_PAT }}
67
123
 
68
- - name: Push image to Docker Hub
124
+ - name: Push the per-arch image to Docker Hub
69
125
  if: ${{ env.PUBLISH_IMAGE != '' }}
126
+ run: docker push "$IMAGE_TAG"
127
+
128
+ # Combine the per-arch images into a multi-arch manifest and write the two
129
+ # published tags. Skipped for a build-only product (empty PUBLISH_IMAGE) and on
130
+ # a dry run.
131
+ publish:
132
+ needs: [label, build]
133
+ if: ${{ needs.label.outputs.publish == 'true' && !inputs.dry_run }}
134
+ runs-on: x64
135
+ steps:
136
+ - uses: actions/checkout@v5
137
+ with:
138
+ clean: false
139
+
140
+ - name: Log in to Docker Hub
141
+ uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
142
+ with:
143
+ username: norskvideo
144
+ password: ${{ secrets.DOCKER_PAT }}
145
+
146
+ - name: Create + push the multi-arch manifest (dated label + channel)
70
147
  run: |
71
- docker tag "$IMAGE_TAG" "${PUBLISH_IMAGE}:main"
72
- docker push "$IMAGE_TAG"
73
- docker push "${PUBLISH_IMAGE}:main"
148
+ label="${{ needs.label.outputs.label }}"
149
+ channel="${{ needs.label.outputs.channel }}"
150
+ # buildx imagetools create, not `docker manifest create`: the arm64
151
+ # runner's containerd image store pushes single-arch images wrapped in
152
+ # an OCI index, which `docker manifest create` refuses to nest. imagetools
153
+ # accepts index sources and writes every -t tag in one push.
154
+ docker buildx imagetools create \
155
+ -t "${PUBLISH_IMAGE}:${label}" \
156
+ -t "${PUBLISH_IMAGE}:${channel}" \
157
+ "${PUBLISH_IMAGE}:${label}-amd64" \
158
+ "${PUBLISH_IMAGE}:${label}-arm64"
74
159
 
75
160
  # Report this pipeline's result to the aggregated product CI dashboard
76
- # (id3as/ci-workflows) instead of posting its own pony the dashboard renders
161
+ # (id3as/ci-workflows) instead of posting its own pony -- the dashboard renders
77
162
  # the pony/emoji from the dispatched result. always() so a red or manual run
78
163
  # still reports.
79
164
  notify:
80
- needs: build
165
+ needs: [build, publish]
81
166
  if: ${{ !cancelled() }}
82
167
  runs-on: x64
83
168
  steps:
84
- # clean: false -- the integration suite (shared x64 pool) leaves root-owned
85
- # bind-mount dirs under test-temp/ that a non-root git clean can't remove
86
- # (EACCES). This job never needs them; skip the clean so it doesn't choke on
87
- # another workflow's leftovers.
88
169
  - uses: actions/checkout@v5
89
170
  with:
90
171
  clean: false
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@norskvideo/ctl-dev-kit",
3
- "version": "0.1.27",
3
+ "version": "0.1.28",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./package.json": "./package.json",