@norskvideo/ctl-dev-kit 0.1.76 → 0.1.78
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.
- package/conventions/build-docs.yml +20 -2
- package/conventions/build-image.yml +76 -8
- package/conventions/checks.yml +67 -25
- package/conventions/publish-docs.yml +20 -2
- package/conventions/smoke.yml +13 -2
- package/conventions/sync-ctl-packages.yml +19 -7
- package/conventions/sync-dev-kit.yml +38 -15
- package/conventions/upgrade-latest.yml +115 -21
- package/package.json +1 -1
|
@@ -56,9 +56,27 @@ jobs:
|
|
|
56
56
|
docker run --rm --user 0:0 -v "$tt":/t alpine sh \
|
|
57
57
|
-c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
|
|
58
58
|
|
|
59
|
+
# Root-owned leftovers under test-temp/ are what `clean: false` used to route
|
|
60
|
+
# around: the integration suite bind-mounts host dirs into containers, and a
|
|
61
|
+
# non-root git clean then EACCESes on what they wrote -- taking down whatever
|
|
62
|
+
# innocent job checked out next. Skipping the clean cured that symptom and
|
|
63
|
+
# caused another: every gitignored artifact survived between runs, so a test
|
|
64
|
+
# could pass on build output an earlier job left behind and go red the first
|
|
65
|
+
# time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
|
|
66
|
+
# from a root container FIRST, and the checkout can clean properly again.
|
|
67
|
+
# Best-effort by construction: no docker, no test-temp, or a failed run all
|
|
68
|
+
# fall through without failing the job.
|
|
69
|
+
- name: Clear stale root-owned test-temp (pre-checkout)
|
|
70
|
+
run: |
|
|
71
|
+
set -uo pipefail
|
|
72
|
+
tt="$GITHUB_WORKSPACE/test-temp"
|
|
73
|
+
[ -d "$tt" ] || exit 0
|
|
74
|
+
docker run --rm --user 0:0 -v "$tt":/t alpine sh \
|
|
75
|
+
-c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
|
|
76
|
+
|
|
59
77
|
- uses: actions/checkout@v5
|
|
60
78
|
with:
|
|
61
|
-
clean:
|
|
79
|
+
clean: true
|
|
62
80
|
|
|
63
81
|
- name: Write the Norsk license (from the org secret)
|
|
64
82
|
env:
|
|
@@ -113,7 +131,7 @@ jobs:
|
|
|
113
131
|
run: |
|
|
114
132
|
nix develop .#build --command bash -c '
|
|
115
133
|
set -euo pipefail
|
|
116
|
-
#
|
|
134
|
+
# Belt-and-braces now that the checkout cleans: a persisted node_modules
|
|
117
135
|
# workspace dep whose version moved leaves stale copies that
|
|
118
136
|
# --frozen-lockfile does not reliably relink, so a new export is "not
|
|
119
137
|
# found". Nuke EVERY node_modules — including nested per-workspace ones
|
|
@@ -66,9 +66,27 @@ jobs:
|
|
|
66
66
|
# publish job gates on this output instead of on PUBLISH_IMAGE directly.
|
|
67
67
|
publish: ${{ steps.gen.outputs.publish }}
|
|
68
68
|
steps:
|
|
69
|
+
# Root-owned leftovers under test-temp/ are what `clean: false` used to route
|
|
70
|
+
# around: the integration suite bind-mounts host dirs into containers, and a
|
|
71
|
+
# non-root git clean then EACCESes on what they wrote -- taking down whatever
|
|
72
|
+
# innocent job checked out next. Skipping the clean cured that symptom and
|
|
73
|
+
# caused another: every gitignored artifact survived between runs, so a test
|
|
74
|
+
# could pass on build output an earlier job left behind and go red the first
|
|
75
|
+
# time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
|
|
76
|
+
# from a root container FIRST, and the checkout can clean properly again.
|
|
77
|
+
# Best-effort by construction: no docker, no test-temp, or a failed run all
|
|
78
|
+
# fall through without failing the job.
|
|
79
|
+
- name: Clear stale root-owned test-temp (pre-checkout)
|
|
80
|
+
run: |
|
|
81
|
+
set -uo pipefail
|
|
82
|
+
tt="$GITHUB_WORKSPACE/test-temp"
|
|
83
|
+
[ -d "$tt" ] || exit 0
|
|
84
|
+
docker run --rm --user 0:0 -v "$tt":/t alpine sh \
|
|
85
|
+
-c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
|
|
86
|
+
|
|
69
87
|
- uses: actions/checkout@v5
|
|
70
88
|
with:
|
|
71
|
-
clean:
|
|
89
|
+
clean: true
|
|
72
90
|
- id: gen
|
|
73
91
|
run: |
|
|
74
92
|
label="$(date -u +%Y-%m-%d)-$(git rev-parse --short=8 HEAD)"
|
|
@@ -91,13 +109,27 @@ jobs:
|
|
|
91
109
|
arch: arm64
|
|
92
110
|
runs-on: ${{ matrix.runner }}
|
|
93
111
|
steps:
|
|
94
|
-
#
|
|
95
|
-
#
|
|
96
|
-
#
|
|
97
|
-
#
|
|
112
|
+
# Root-owned leftovers under test-temp/ are what `clean: false` used to route
|
|
113
|
+
# around: the integration suite bind-mounts host dirs into containers, and a
|
|
114
|
+
# non-root git clean then EACCESes on what they wrote -- taking down whatever
|
|
115
|
+
# innocent job checked out next. Skipping the clean cured that symptom and
|
|
116
|
+
# caused another: every gitignored artifact survived between runs, so a test
|
|
117
|
+
# could pass on build output an earlier job left behind and go red the first
|
|
118
|
+
# time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
|
|
119
|
+
# from a root container FIRST, and the checkout can clean properly again.
|
|
120
|
+
# Best-effort by construction: no docker, no test-temp, or a failed run all
|
|
121
|
+
# fall through without failing the job.
|
|
122
|
+
- name: Clear stale root-owned test-temp (pre-checkout)
|
|
123
|
+
run: |
|
|
124
|
+
set -uo pipefail
|
|
125
|
+
tt="$GITHUB_WORKSPACE/test-temp"
|
|
126
|
+
[ -d "$tt" ] || exit 0
|
|
127
|
+
docker run --rm --user 0:0 -v "$tt":/t alpine sh \
|
|
128
|
+
-c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
|
|
129
|
+
|
|
98
130
|
- uses: actions/checkout@v5
|
|
99
131
|
with:
|
|
100
|
-
clean:
|
|
132
|
+
clean: true
|
|
101
133
|
|
|
102
134
|
- name: Build product image (copy-only, via the dev-kit driver, native ${{ matrix.arch }})
|
|
103
135
|
run: |
|
|
@@ -133,9 +165,27 @@ jobs:
|
|
|
133
165
|
if: ${{ needs.label.outputs.publish == 'true' && !inputs.dry_run }}
|
|
134
166
|
runs-on: x64
|
|
135
167
|
steps:
|
|
168
|
+
# Root-owned leftovers under test-temp/ are what `clean: false` used to route
|
|
169
|
+
# around: the integration suite bind-mounts host dirs into containers, and a
|
|
170
|
+
# non-root git clean then EACCESes on what they wrote -- taking down whatever
|
|
171
|
+
# innocent job checked out next. Skipping the clean cured that symptom and
|
|
172
|
+
# caused another: every gitignored artifact survived between runs, so a test
|
|
173
|
+
# could pass on build output an earlier job left behind and go red the first
|
|
174
|
+
# time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
|
|
175
|
+
# from a root container FIRST, and the checkout can clean properly again.
|
|
176
|
+
# Best-effort by construction: no docker, no test-temp, or a failed run all
|
|
177
|
+
# fall through without failing the job.
|
|
178
|
+
- name: Clear stale root-owned test-temp (pre-checkout)
|
|
179
|
+
run: |
|
|
180
|
+
set -uo pipefail
|
|
181
|
+
tt="$GITHUB_WORKSPACE/test-temp"
|
|
182
|
+
[ -d "$tt" ] || exit 0
|
|
183
|
+
docker run --rm --user 0:0 -v "$tt":/t alpine sh \
|
|
184
|
+
-c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
|
|
185
|
+
|
|
136
186
|
- uses: actions/checkout@v5
|
|
137
187
|
with:
|
|
138
|
-
clean:
|
|
188
|
+
clean: true
|
|
139
189
|
|
|
140
190
|
- name: Log in to Docker Hub
|
|
141
191
|
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
|
|
@@ -166,9 +216,27 @@ jobs:
|
|
|
166
216
|
if: ${{ !cancelled() }}
|
|
167
217
|
runs-on: x64
|
|
168
218
|
steps:
|
|
219
|
+
# Root-owned leftovers under test-temp/ are what `clean: false` used to route
|
|
220
|
+
# around: the integration suite bind-mounts host dirs into containers, and a
|
|
221
|
+
# non-root git clean then EACCESes on what they wrote -- taking down whatever
|
|
222
|
+
# innocent job checked out next. Skipping the clean cured that symptom and
|
|
223
|
+
# caused another: every gitignored artifact survived between runs, so a test
|
|
224
|
+
# could pass on build output an earlier job left behind and go red the first
|
|
225
|
+
# time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
|
|
226
|
+
# from a root container FIRST, and the checkout can clean properly again.
|
|
227
|
+
# Best-effort by construction: no docker, no test-temp, or a failed run all
|
|
228
|
+
# fall through without failing the job.
|
|
229
|
+
- name: Clear stale root-owned test-temp (pre-checkout)
|
|
230
|
+
run: |
|
|
231
|
+
set -uo pipefail
|
|
232
|
+
tt="$GITHUB_WORKSPACE/test-temp"
|
|
233
|
+
[ -d "$tt" ] || exit 0
|
|
234
|
+
docker run --rm --user 0:0 -v "$tt":/t alpine sh \
|
|
235
|
+
-c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
|
|
236
|
+
|
|
169
237
|
- uses: actions/checkout@v5
|
|
170
238
|
with:
|
|
171
|
-
clean:
|
|
239
|
+
clean: true
|
|
172
240
|
- id: meta
|
|
173
241
|
run: |
|
|
174
242
|
if [ "${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}" = "true" ]; then
|
package/conventions/checks.yml
CHANGED
|
@@ -30,22 +30,36 @@ jobs:
|
|
|
30
30
|
drift:
|
|
31
31
|
runs-on: x64
|
|
32
32
|
steps:
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
33
|
+
# Root-owned leftovers under test-temp/ are what `clean: false` used to route
|
|
34
|
+
# around: the integration suite bind-mounts host dirs into containers, and a
|
|
35
|
+
# non-root git clean then EACCESes on what they wrote -- taking down whatever
|
|
36
|
+
# innocent job checked out next. Skipping the clean cured that symptom and
|
|
37
|
+
# caused another: every gitignored artifact survived between runs, so a test
|
|
38
|
+
# could pass on build output an earlier job left behind and go red the first
|
|
39
|
+
# time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
|
|
40
|
+
# from a root container FIRST, and the checkout can clean properly again.
|
|
41
|
+
# Best-effort by construction: no docker, no test-temp, or a failed run all
|
|
42
|
+
# fall through without failing the job.
|
|
43
|
+
- name: Clear stale root-owned test-temp (pre-checkout)
|
|
44
|
+
run: |
|
|
45
|
+
set -uo pipefail
|
|
46
|
+
tt="$GITHUB_WORKSPACE/test-temp"
|
|
47
|
+
[ -d "$tt" ] || exit 0
|
|
48
|
+
docker run --rm --user 0:0 -v "$tt":/t alpine sh \
|
|
49
|
+
-c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
|
|
50
|
+
|
|
37
51
|
- uses: actions/checkout@v5
|
|
38
52
|
with:
|
|
39
|
-
clean:
|
|
53
|
+
clean: true
|
|
40
54
|
- name: Shared-conventions drift-check (Workstream I)
|
|
41
55
|
run: |
|
|
42
56
|
nix develop .#build --command bash -c '
|
|
43
57
|
set -euo pipefail
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
# dev-kit bump leaves a stale
|
|
47
|
-
# check:drift would run the
|
|
48
|
-
#
|
|
58
|
+
# Belt-and-braces now that the checkout cleans: a persisted
|
|
59
|
+
# node_modules would defeat a frozen install, which does NOT relink a
|
|
60
|
+
# dep whose pinned version moved (a dev-kit bump leaves a stale
|
|
61
|
+
# node_modules/@norskvideo/ctl-dev-kit, so check:drift would run the
|
|
62
|
+
# OLD checker against the new canonical). Cheap when already gone.
|
|
49
63
|
find . -name node_modules -type d -prune -exec rm -rf {} + 2>/dev/null || true
|
|
50
64
|
bun install --frozen-lockfile
|
|
51
65
|
bun run check:drift
|
|
@@ -54,22 +68,36 @@ jobs:
|
|
|
54
68
|
quality:
|
|
55
69
|
runs-on: x64
|
|
56
70
|
steps:
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
71
|
+
# Root-owned leftovers under test-temp/ are what `clean: false` used to route
|
|
72
|
+
# around: the integration suite bind-mounts host dirs into containers, and a
|
|
73
|
+
# non-root git clean then EACCESes on what they wrote -- taking down whatever
|
|
74
|
+
# innocent job checked out next. Skipping the clean cured that symptom and
|
|
75
|
+
# caused another: every gitignored artifact survived between runs, so a test
|
|
76
|
+
# could pass on build output an earlier job left behind and go red the first
|
|
77
|
+
# time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
|
|
78
|
+
# from a root container FIRST, and the checkout can clean properly again.
|
|
79
|
+
# Best-effort by construction: no docker, no test-temp, or a failed run all
|
|
80
|
+
# fall through without failing the job.
|
|
81
|
+
- name: Clear stale root-owned test-temp (pre-checkout)
|
|
82
|
+
run: |
|
|
83
|
+
set -uo pipefail
|
|
84
|
+
tt="$GITHUB_WORKSPACE/test-temp"
|
|
85
|
+
[ -d "$tt" ] || exit 0
|
|
86
|
+
docker run --rm --user 0:0 -v "$tt":/t alpine sh \
|
|
87
|
+
-c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
|
|
88
|
+
|
|
61
89
|
- uses: actions/checkout@v5
|
|
62
90
|
with:
|
|
63
|
-
clean:
|
|
91
|
+
clean: true
|
|
64
92
|
- name: Lint + typecheck + unit tests
|
|
65
93
|
run: |
|
|
66
94
|
nix develop .#build --command bash -c '
|
|
67
95
|
set -euo pipefail
|
|
68
|
-
#
|
|
69
|
-
#
|
|
70
|
-
# dev-kit bump leaves a stale
|
|
71
|
-
# check:drift would run the
|
|
72
|
-
#
|
|
96
|
+
# Belt-and-braces now that the checkout cleans: a persisted
|
|
97
|
+
# node_modules would defeat a frozen install, which does NOT relink a
|
|
98
|
+
# dep whose pinned version moved (a dev-kit bump leaves a stale
|
|
99
|
+
# node_modules/@norskvideo/ctl-dev-kit, so check:drift would run the
|
|
100
|
+
# OLD checker against the new canonical). Cheap when already gone.
|
|
73
101
|
find . -name node_modules -type d -prune -exec rm -rf {} + 2>/dev/null || true
|
|
74
102
|
bun install --frozen-lockfile
|
|
75
103
|
bun run lint
|
|
@@ -132,13 +160,27 @@ jobs:
|
|
|
132
160
|
if: ${{ !cancelled() && github.event_name == 'push' }}
|
|
133
161
|
runs-on: x64
|
|
134
162
|
steps:
|
|
135
|
-
#
|
|
136
|
-
#
|
|
137
|
-
#
|
|
138
|
-
#
|
|
163
|
+
# Root-owned leftovers under test-temp/ are what `clean: false` used to route
|
|
164
|
+
# around: the integration suite bind-mounts host dirs into containers, and a
|
|
165
|
+
# non-root git clean then EACCESes on what they wrote -- taking down whatever
|
|
166
|
+
# innocent job checked out next. Skipping the clean cured that symptom and
|
|
167
|
+
# caused another: every gitignored artifact survived between runs, so a test
|
|
168
|
+
# could pass on build output an earlier job left behind and go red the first
|
|
169
|
+
# time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
|
|
170
|
+
# from a root container FIRST, and the checkout can clean properly again.
|
|
171
|
+
# Best-effort by construction: no docker, no test-temp, or a failed run all
|
|
172
|
+
# fall through without failing the job.
|
|
173
|
+
- name: Clear stale root-owned test-temp (pre-checkout)
|
|
174
|
+
run: |
|
|
175
|
+
set -uo pipefail
|
|
176
|
+
tt="$GITHUB_WORKSPACE/test-temp"
|
|
177
|
+
[ -d "$tt" ] || exit 0
|
|
178
|
+
docker run --rm --user 0:0 -v "$tt":/t alpine sh \
|
|
179
|
+
-c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
|
|
180
|
+
|
|
139
181
|
- uses: actions/checkout@v5
|
|
140
182
|
with:
|
|
141
|
-
clean:
|
|
183
|
+
clean: true
|
|
142
184
|
- id: meta
|
|
143
185
|
run: |
|
|
144
186
|
if [ "${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}" = "true" ]; then
|
|
@@ -55,9 +55,27 @@ jobs:
|
|
|
55
55
|
docker run --rm --user 0:0 -v "$tt":/t alpine sh \
|
|
56
56
|
-c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
|
|
57
57
|
|
|
58
|
+
# Root-owned leftovers under test-temp/ are what `clean: false` used to route
|
|
59
|
+
# around: the integration suite bind-mounts host dirs into containers, and a
|
|
60
|
+
# non-root git clean then EACCESes on what they wrote -- taking down whatever
|
|
61
|
+
# innocent job checked out next. Skipping the clean cured that symptom and
|
|
62
|
+
# caused another: every gitignored artifact survived between runs, so a test
|
|
63
|
+
# could pass on build output an earlier job left behind and go red the first
|
|
64
|
+
# time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
|
|
65
|
+
# from a root container FIRST, and the checkout can clean properly again.
|
|
66
|
+
# Best-effort by construction: no docker, no test-temp, or a failed run all
|
|
67
|
+
# fall through without failing the job.
|
|
68
|
+
- name: Clear stale root-owned test-temp (pre-checkout)
|
|
69
|
+
run: |
|
|
70
|
+
set -uo pipefail
|
|
71
|
+
tt="$GITHUB_WORKSPACE/test-temp"
|
|
72
|
+
[ -d "$tt" ] || exit 0
|
|
73
|
+
docker run --rm --user 0:0 -v "$tt":/t alpine sh \
|
|
74
|
+
-c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
|
|
75
|
+
|
|
58
76
|
- uses: actions/checkout@v5
|
|
59
77
|
with:
|
|
60
|
-
clean:
|
|
78
|
+
clean: true
|
|
61
79
|
|
|
62
80
|
- name: Write the Norsk license (from the org secret)
|
|
63
81
|
env:
|
|
@@ -112,7 +130,7 @@ jobs:
|
|
|
112
130
|
run: |
|
|
113
131
|
nix develop .#build --command bash -c '
|
|
114
132
|
set -euo pipefail
|
|
115
|
-
#
|
|
133
|
+
# Belt-and-braces now that the checkout cleans: a persisted node_modules
|
|
116
134
|
# workspace dep whose version moved leaves stale copies that
|
|
117
135
|
# --frozen-lockfile does not reliably relink, so a new export is "not
|
|
118
136
|
# found". Nuke EVERY node_modules — including nested per-workspace ones
|
package/conventions/smoke.yml
CHANGED
|
@@ -66,7 +66,7 @@ jobs:
|
|
|
66
66
|
|
|
67
67
|
- uses: actions/checkout@v5
|
|
68
68
|
with:
|
|
69
|
-
clean:
|
|
69
|
+
clean: true
|
|
70
70
|
|
|
71
71
|
# A containerised runner (docker-outside-of-docker) reaches host-published
|
|
72
72
|
# ports via the host-gateway alias and can join norsk-net for direct reach;
|
|
@@ -238,9 +238,20 @@ jobs:
|
|
|
238
238
|
if: ${{ !cancelled() && github.event_name != 'repository_dispatch' }}
|
|
239
239
|
runs-on: x64
|
|
240
240
|
steps:
|
|
241
|
+
# Same reason as the first checkout in this file: clear root-owned leftovers
|
|
242
|
+
# from a root container so the checkout below can clean properly. Best-effort
|
|
243
|
+
# by construction -- no docker, no test-temp, or a failed run all fall through.
|
|
244
|
+
- name: Clear stale root-owned test-temp (pre-checkout)
|
|
245
|
+
run: |
|
|
246
|
+
set -uo pipefail
|
|
247
|
+
tt="$GITHUB_WORKSPACE/test-temp"
|
|
248
|
+
[ -d "$tt" ] || exit 0
|
|
249
|
+
docker run --rm --user 0:0 -v "$tt":/t alpine sh \
|
|
250
|
+
-c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
|
|
251
|
+
|
|
241
252
|
- uses: actions/checkout@v5
|
|
242
253
|
with:
|
|
243
|
-
clean:
|
|
254
|
+
clean: true
|
|
244
255
|
- id: meta
|
|
245
256
|
run: |
|
|
246
257
|
if [ "${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}" = "true" ]; then
|
|
@@ -41,16 +41,28 @@ jobs:
|
|
|
41
41
|
sync:
|
|
42
42
|
runs-on: x64
|
|
43
43
|
steps:
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
44
|
+
# Root-owned leftovers under test-temp/ are what `clean: false` used to route
|
|
45
|
+
# around: the integration suite bind-mounts host dirs into containers, and a
|
|
46
|
+
# non-root git clean then EACCESes on what they wrote -- taking down whatever
|
|
47
|
+
# innocent job checked out next. Skipping the clean cured that symptom and
|
|
48
|
+
# caused another: every gitignored artifact survived between runs, so a test
|
|
49
|
+
# could pass on build output an earlier job left behind and go red the first
|
|
50
|
+
# time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
|
|
51
|
+
# from a root container FIRST, and the checkout can clean properly again.
|
|
52
|
+
# Best-effort by construction: no docker, no test-temp, or a failed run all
|
|
53
|
+
# fall through without failing the job.
|
|
54
|
+
- name: Clear stale root-owned test-temp (pre-checkout)
|
|
55
|
+
run: |
|
|
56
|
+
set -uo pipefail
|
|
57
|
+
tt="$GITHUB_WORKSPACE/test-temp"
|
|
58
|
+
[ -d "$tt" ] || exit 0
|
|
59
|
+
docker run --rm --user 0:0 -v "$tt":/t alpine sh \
|
|
60
|
+
-c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
|
|
61
|
+
|
|
50
62
|
- uses: actions/checkout@v5
|
|
51
63
|
with:
|
|
52
64
|
token: ${{ secrets.CI_DISPATCH_TOKEN }}
|
|
53
|
-
clean:
|
|
65
|
+
clean: true
|
|
54
66
|
|
|
55
67
|
- name: Resolve the newest published ctl-* packages and rewrite the pins
|
|
56
68
|
id: bump
|
|
@@ -43,21 +43,28 @@ jobs:
|
|
|
43
43
|
sync:
|
|
44
44
|
runs-on: x64
|
|
45
45
|
steps:
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
|
|
46
|
+
# Root-owned leftovers under test-temp/ are what `clean: false` used to route
|
|
47
|
+
# around: the integration suite bind-mounts host dirs into containers, and a
|
|
48
|
+
# non-root git clean then EACCESes on what they wrote -- taking down whatever
|
|
49
|
+
# innocent job checked out next. Skipping the clean cured that symptom and
|
|
50
|
+
# caused another: every gitignored artifact survived between runs, so a test
|
|
51
|
+
# could pass on build output an earlier job left behind and go red the first
|
|
52
|
+
# time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
|
|
53
|
+
# from a root container FIRST, and the checkout can clean properly again.
|
|
54
|
+
# Best-effort by construction: no docker, no test-temp, or a failed run all
|
|
55
|
+
# fall through without failing the job.
|
|
56
|
+
- name: Clear stale root-owned test-temp (pre-checkout)
|
|
57
|
+
run: |
|
|
58
|
+
set -uo pipefail
|
|
59
|
+
tt="$GITHUB_WORKSPACE/test-temp"
|
|
60
|
+
[ -d "$tt" ] || exit 0
|
|
61
|
+
docker run --rm --user 0:0 -v "$tt":/t alpine sh \
|
|
62
|
+
-c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
|
|
63
|
+
|
|
57
64
|
- uses: actions/checkout@v5
|
|
58
65
|
with:
|
|
59
66
|
token: ${{ secrets.CI_DISPATCH_TOKEN }}
|
|
60
|
-
clean:
|
|
67
|
+
clean: true
|
|
61
68
|
|
|
62
69
|
- name: Resolve the newest published dev-kit and bump the pin
|
|
63
70
|
id: sync
|
|
@@ -194,11 +201,27 @@ jobs:
|
|
|
194
201
|
if: ${{ !cancelled() }}
|
|
195
202
|
runs-on: x64
|
|
196
203
|
steps:
|
|
197
|
-
#
|
|
198
|
-
#
|
|
204
|
+
# Root-owned leftovers under test-temp/ are what `clean: false` used to route
|
|
205
|
+
# around: the integration suite bind-mounts host dirs into containers, and a
|
|
206
|
+
# non-root git clean then EACCESes on what they wrote -- taking down whatever
|
|
207
|
+
# innocent job checked out next. Skipping the clean cured that symptom and
|
|
208
|
+
# caused another: every gitignored artifact survived between runs, so a test
|
|
209
|
+
# could pass on build output an earlier job left behind and go red the first
|
|
210
|
+
# time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
|
|
211
|
+
# from a root container FIRST, and the checkout can clean properly again.
|
|
212
|
+
# Best-effort by construction: no docker, no test-temp, or a failed run all
|
|
213
|
+
# fall through without failing the job.
|
|
214
|
+
- name: Clear stale root-owned test-temp (pre-checkout)
|
|
215
|
+
run: |
|
|
216
|
+
set -uo pipefail
|
|
217
|
+
tt="$GITHUB_WORKSPACE/test-temp"
|
|
218
|
+
[ -d "$tt" ] || exit 0
|
|
219
|
+
docker run --rm --user 0:0 -v "$tt":/t alpine sh \
|
|
220
|
+
-c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
|
|
221
|
+
|
|
199
222
|
- uses: actions/checkout@v5
|
|
200
223
|
with:
|
|
201
|
-
clean:
|
|
224
|
+
clean: true
|
|
202
225
|
- id: meta
|
|
203
226
|
run: |
|
|
204
227
|
if [ "${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}" = "true" ]; then
|
|
@@ -10,12 +10,18 @@
|
|
|
10
10
|
# norsk-ctl daemon to the `latest` channel (dev-only; CI downloads ctl
|
|
11
11
|
# directly, so a stale pin never affects CI or customers).
|
|
12
12
|
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
13
|
+
# Nightly cron + on demand. The bump runs the product's own gate (lint,
|
|
14
|
+
# typecheck, unit tests) BEFORE it lands, exactly as sync-dev-kit does: green
|
|
15
|
+
# lands on main, red opens a reconciliation PR and main stays green.
|
|
16
|
+
#
|
|
17
|
+
# It used to commit straight to main and rely on the push-triggered run for its
|
|
18
|
+
# verdict. The push is made with CI_DISPATCH_TOKEN (a PAT), so that run really
|
|
19
|
+
# does happen -- a GITHUB_TOKEN push would fire nothing (Actions' recursion
|
|
20
|
+
# guard) -- but it makes a RED `main` the alarm, and nobody watches a product
|
|
21
|
+
# repo's own `main`: playout sat red ~12h, then funke, then probe, inside three
|
|
22
|
+
# days (fleet review 04c, class 8). Gating first turns "a bad Norsk nightly reds
|
|
23
|
+
# six repos overnight" into "a bad Norsk nightly opens a PR that says so".
|
|
24
|
+
# Pinned for the class by conventions/gate-before-main.test.ts.
|
|
19
25
|
#
|
|
20
26
|
# Single-sourced in @norskvideo/ctl-dev-kit (conventions/upgrade-latest.yml) and
|
|
21
27
|
# copied verbatim into each product repo; the check:drift gate fails CI if a copy
|
|
@@ -39,18 +45,28 @@ jobs:
|
|
|
39
45
|
changed: ${{ steps.bump.outputs.changed }}
|
|
40
46
|
summary: ${{ steps.bump.outputs.summary }}
|
|
41
47
|
steps:
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
48
|
+
# Root-owned leftovers under test-temp/ are what `clean: false` used to route
|
|
49
|
+
# around: the integration suite bind-mounts host dirs into containers, and a
|
|
50
|
+
# non-root git clean then EACCESes on what they wrote -- taking down whatever
|
|
51
|
+
# innocent job checked out next. Skipping the clean cured that symptom and
|
|
52
|
+
# caused another: every gitignored artifact survived between runs, so a test
|
|
53
|
+
# could pass on build output an earlier job left behind and go red the first
|
|
54
|
+
# time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
|
|
55
|
+
# from a root container FIRST, and the checkout can clean properly again.
|
|
56
|
+
# Best-effort by construction: no docker, no test-temp, or a failed run all
|
|
57
|
+
# fall through without failing the job.
|
|
58
|
+
- name: Clear stale root-owned test-temp (pre-checkout)
|
|
59
|
+
run: |
|
|
60
|
+
set -uo pipefail
|
|
61
|
+
tt="$GITHUB_WORKSPACE/test-temp"
|
|
62
|
+
[ -d "$tt" ] || exit 0
|
|
63
|
+
docker run --rm --user 0:0 -v "$tt":/t alpine sh \
|
|
64
|
+
-c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
|
|
65
|
+
|
|
50
66
|
- uses: actions/checkout@v5
|
|
51
67
|
with:
|
|
52
68
|
token: ${{ secrets.CI_DISPATCH_TOKEN }}
|
|
53
|
-
clean:
|
|
69
|
+
clean: true
|
|
54
70
|
|
|
55
71
|
- name: Resolve the nightly channel and rewrite the coupled pins
|
|
56
72
|
id: bump
|
|
@@ -202,8 +218,23 @@ jobs:
|
|
|
202
218
|
done
|
|
203
219
|
'
|
|
204
220
|
|
|
205
|
-
- name:
|
|
221
|
+
- name: Run the product gate against the bumped pins
|
|
222
|
+
id: gate
|
|
206
223
|
if: steps.bump.outputs.changed == '1'
|
|
224
|
+
# continue-on-error so a red gate can open a PR below instead of failing
|
|
225
|
+
# the workflow -- which is why the steps after it read `outcome` and not
|
|
226
|
+
# `conclusion` (continue-on-error rewrites conclusion to success).
|
|
227
|
+
continue-on-error: true
|
|
228
|
+
run: |
|
|
229
|
+
nix develop .#build --command bash -c '
|
|
230
|
+
set -euo pipefail
|
|
231
|
+
bun run lint
|
|
232
|
+
bun run typecheck
|
|
233
|
+
bun run test:unit
|
|
234
|
+
'
|
|
235
|
+
|
|
236
|
+
- name: Land the bump on main (gate green)
|
|
237
|
+
if: steps.bump.outputs.changed == '1' && steps.gate.outcome == 'success'
|
|
207
238
|
run: |
|
|
208
239
|
set -euo pipefail
|
|
209
240
|
git config user.name "github-actions[bot]"
|
|
@@ -230,6 +261,55 @@ jobs:
|
|
|
230
261
|
done
|
|
231
262
|
echo "push still failing after 5 rebase attempts"; exit 1
|
|
232
263
|
|
|
264
|
+
- name: Open a reconciliation PR (gate red)
|
|
265
|
+
if: steps.bump.outputs.changed == '1' && steps.gate.outcome == 'failure'
|
|
266
|
+
env:
|
|
267
|
+
API_TOKEN: ${{ secrets.CI_DISPATCH_TOKEN }}
|
|
268
|
+
run: |
|
|
269
|
+
set -euo pipefail
|
|
270
|
+
branch="upgrade-latest/nightly"
|
|
271
|
+
git config user.name "github-actions[bot]"
|
|
272
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
273
|
+
git checkout -b "$branch"
|
|
274
|
+
git add -A
|
|
275
|
+
git commit -m "chore: bump Norsk nightly + ctl pins to latest channel (needs reconciliation)
|
|
276
|
+
|
|
277
|
+
${{ steps.bump.outputs.summary }}"
|
|
278
|
+
git push -f origin "$branch"
|
|
279
|
+
title="Bump Norsk nightly + ctl pins to latest channel"
|
|
280
|
+
body="$(printf '%s\n' \
|
|
281
|
+
"Automated nightly pin bump: the Norsk nightly channel moved and the coupled" \
|
|
282
|
+
"pins came with it -- but the product gate is **red**, so this bump needs a" \
|
|
283
|
+
"human before it reaches main." \
|
|
284
|
+
"" \
|
|
285
|
+
" ${{ steps.bump.outputs.summary }}" \
|
|
286
|
+
"" \
|
|
287
|
+
"A red gate here usually means the new Norsk nightly is bad, or genuinely" \
|
|
288
|
+
"changed something the product depends on. Run it to see which:" \
|
|
289
|
+
"" \
|
|
290
|
+
" bun run lint && bun run typecheck && bun run test:unit" \
|
|
291
|
+
"" \
|
|
292
|
+
"Fix it on this branch and merge, or close this PR to skip the bump -- the" \
|
|
293
|
+
"next nightly run reopens it against whatever the channel holds then.")"
|
|
294
|
+
# gh is not on the self-hosted runner PATH (it lives only inside
|
|
295
|
+
# `nix develop`, and this step runs outside it), so create/update the PR
|
|
296
|
+
# straight against the REST API with the same PAT that pushed the branch.
|
|
297
|
+
# The PAT (not GITHUB_TOKEN) is what lets the PR's own checks run, which
|
|
298
|
+
# is the whole point: the bump is judged before it lands, not after.
|
|
299
|
+
repo="${{ github.repository }}"; owner="${repo%%/*}"
|
|
300
|
+
api="https://api.github.com/repos/$repo/pulls"
|
|
301
|
+
curl_api=(--fail-with-body -sS -H "Authorization: Bearer $API_TOKEN" -H "Accept: application/vnd.github+json")
|
|
302
|
+
existing="$(curl "${curl_api[@]}" "$api?head=$owner:$branch&state=open" | jq -r '.[0].number // empty')"
|
|
303
|
+
if [ -n "$existing" ]; then
|
|
304
|
+
curl "${curl_api[@]}" -X PATCH "$api/$existing" \
|
|
305
|
+
--data "$(jq -nc --arg t "$title" --arg b "$body" '{title:$t, body:$b}')" > /dev/null
|
|
306
|
+
echo "updated PR #$existing"
|
|
307
|
+
else
|
|
308
|
+
curl "${curl_api[@]}" -X POST "$api" \
|
|
309
|
+
--data "$(jq -nc --arg t "$title" --arg b "$body" --arg h "$branch" \
|
|
310
|
+
'{title:$t, body:$b, head:$h, base:"main"}')" | jq -r '"opened PR #\(.number)"'
|
|
311
|
+
fi
|
|
312
|
+
|
|
233
313
|
- name: Report "already fresh"
|
|
234
314
|
if: steps.bump.outputs.changed != '1'
|
|
235
315
|
run: echo "Nightly pins already current — nothing to bump."
|
|
@@ -243,13 +323,27 @@ jobs:
|
|
|
243
323
|
if: ${{ !cancelled() }}
|
|
244
324
|
runs-on: x64
|
|
245
325
|
steps:
|
|
246
|
-
#
|
|
247
|
-
#
|
|
248
|
-
#
|
|
249
|
-
#
|
|
326
|
+
# Root-owned leftovers under test-temp/ are what `clean: false` used to route
|
|
327
|
+
# around: the integration suite bind-mounts host dirs into containers, and a
|
|
328
|
+
# non-root git clean then EACCESes on what they wrote -- taking down whatever
|
|
329
|
+
# innocent job checked out next. Skipping the clean cured that symptom and
|
|
330
|
+
# caused another: every gitignored artifact survived between runs, so a test
|
|
331
|
+
# could pass on build output an earlier job left behind and go red the first
|
|
332
|
+
# time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
|
|
333
|
+
# from a root container FIRST, and the checkout can clean properly again.
|
|
334
|
+
# Best-effort by construction: no docker, no test-temp, or a failed run all
|
|
335
|
+
# fall through without failing the job.
|
|
336
|
+
- name: Clear stale root-owned test-temp (pre-checkout)
|
|
337
|
+
run: |
|
|
338
|
+
set -uo pipefail
|
|
339
|
+
tt="$GITHUB_WORKSPACE/test-temp"
|
|
340
|
+
[ -d "$tt" ] || exit 0
|
|
341
|
+
docker run --rm --user 0:0 -v "$tt":/t alpine sh \
|
|
342
|
+
-c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
|
|
343
|
+
|
|
250
344
|
- uses: actions/checkout@v5
|
|
251
345
|
with:
|
|
252
|
-
clean:
|
|
346
|
+
clean: true
|
|
253
347
|
- id: meta
|
|
254
348
|
run: |
|
|
255
349
|
if [ "${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}" = "true" ]; then
|