@norskvideo/ctl-dev-kit 0.2.27 → 0.2.29
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/upgrade-latest.yml +108 -69
- package/package.json +1 -1
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# Keep the product fresh against the Norsk "nightly" channel (RFC 0001 —
|
|
2
|
-
# product version freshness).
|
|
2
|
+
# product version freshness). The {engine, studio image} pair comes from the
|
|
3
|
+
# nightly entry of norsk-studio's channel manifest -- the pair studio TESTED
|
|
4
|
+
# together -- never from the two channels separately. Version discovery of the
|
|
5
|
+
# product's current pins anchors on manifest.seed.json
|
|
3
6
|
# (the machine-writable source of truth for the launched {media, studio} image
|
|
4
7
|
# pair — every product repo has one). Any npm pins on the same version string
|
|
5
8
|
# (media build libraries, the @norskvideo/norsk-studio* family in whichever
|
|
@@ -119,22 +122,41 @@ jobs:
|
|
|
119
122
|
# product, even when nothing changed — pure dashboard noise.
|
|
120
123
|
parts=()
|
|
121
124
|
|
|
125
|
+
# ONE TESTED PAIR, NOT TWO CHANNELS. The engine and the studio image are
|
|
126
|
+
# taken together from the nightly entry of norsk-studio's channel
|
|
127
|
+
# manifest: the pair studio's publish built and tested against each
|
|
128
|
+
# other (scripts/write-channel-manifest.sh in norsk-studio). Resolving
|
|
129
|
+
# them apart -- the engine off norsk-sdk's nightly dist-tag, the image
|
|
130
|
+
# off Docker Hub's nightly tag -- produced pairs nobody had tested
|
|
131
|
+
# whenever one channel moved without the other. On 2026-10-04 studio's
|
|
132
|
+
# nightly had been held by its test gate since 09-28 while the engine
|
|
133
|
+
# walked on to 10-02, a breaking SDK change landed in between, and
|
|
134
|
+
# commentary's audio mix produced nothing on the old-studio /
|
|
135
|
+
# new-engine pair it was pinned to (norsk task 112).
|
|
136
|
+
#
|
|
137
|
+
# Consequence, deliberately: when studio's nightly stalls, the engine
|
|
138
|
+
# stalls with it (or steps BACK to the pair), rather than running ahead
|
|
139
|
+
# untested. Unblocking studio's nightly is how products move forward.
|
|
140
|
+
#
|
|
141
|
+
# Everything is resolved and checked BEFORE anything is rewritten, so a
|
|
142
|
+
# refusal never leaves the engine moved and studio not.
|
|
143
|
+
manifest_url="https://s3.eu-west-1.amazonaws.com/norsk.video/channel-manifest.json"
|
|
144
|
+
pair="$(curl -fsSL --retry 3 --retry-all-errors --retry-delay 2 "$manifest_url" | jq -c '.channels.nightly // empty')"
|
|
145
|
+
[ -n "$pair" ] || { echo "::error::no nightly pair in $manifest_url"; exit 1; }
|
|
146
|
+
tag_re='^[0-9]+\.[0-9]+\.[0-9]+-[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9a-f]+$'
|
|
147
|
+
new_media="$(jq -r '(.norsk // "") | split(":") | .[1] // ""' <<<"$pair")"
|
|
148
|
+
new_studio_img="$(jq -r '(.studio // "") | split(":") | .[1] // ""' <<<"$pair")"
|
|
149
|
+
printf '%s' "$new_media" | grep -qE "$tag_re" || { echo "::error::the manifest's nightly norsk image is not a dated nightly tag: $pair"; exit 1; }
|
|
150
|
+
printf '%s' "$new_studio_img" | grep -qE "$tag_re" || { echo "::error::the manifest's nightly studio image is not a dated nightly tag: $pair"; exit 1; }
|
|
151
|
+
echo "nightly pair: norsk $new_media + studio $new_studio_img"
|
|
152
|
+
|
|
122
153
|
# MEDIA: the npm packages and the launched image are built from the SAME
|
|
123
|
-
# commit (their hash suffixes match), so
|
|
124
|
-
# whole family
|
|
125
|
-
#
|
|
126
|
-
#
|
|
127
|
-
# version-pin test) EXCEPT the lockfile, which bun install regenerates.
|
|
154
|
+
# commit (their hash suffixes match), so the pair's engine version drives
|
|
155
|
+
# the whole family: overrides, sub-package deps, the manifest image ref,
|
|
156
|
+
# the version-pin test -- every occurrence EXCEPT the lockfile, which bun
|
|
157
|
+
# install regenerates.
|
|
128
158
|
old_media="$(jq -r '.latest.media | split(":")[1]' manifest.seed.json)"
|
|
129
|
-
|
|
130
|
-
[ -n "$new_media" ] && [ "$new_media" != "null" ] || { echo "could not resolve norsk-sdk nightly"; exit 1; }
|
|
131
|
-
echo "media: $old_media -> $new_media"
|
|
132
|
-
if [ "$old_media" != "$new_media" ]; then
|
|
133
|
-
git grep -lF "$old_media" -- . ':!bun.lock' | xargs -r sed -i "s|$old_media|$new_media|g"
|
|
134
|
-
changed=1
|
|
135
|
-
parts+=("media \`$new_media\`")
|
|
136
|
-
fi
|
|
137
|
-
# The rewrite above is a LITERAL replace of the value found in
|
|
159
|
+
# The rewrite below is a LITERAL replace of the value found in
|
|
138
160
|
# manifest.seed.json, so it only ever touches pins that already equal the
|
|
139
161
|
# seed. A pin that has drifted off it -- a hand edit, a merge, a
|
|
140
162
|
# half-finished run -- is invisible to this bump and to every later one,
|
|
@@ -148,9 +170,10 @@ jobs:
|
|
|
148
170
|
# Not auto-rewritten: a pin held back on purpose is someone's decision,
|
|
149
171
|
# and silently moving it would be the same class of surprise in the
|
|
150
172
|
# other direction. Fail, name them, and let a human fix the pin or the
|
|
151
|
-
# intent.
|
|
173
|
+
# intent. (Checked against the SEED, the family's current value: after
|
|
174
|
+
# the rewrite every seed-equal pin reads the pair's engine.)
|
|
152
175
|
stranded="$(git grep -hoE '"@norskvideo/norsk-(api|sdk|auto-manager|manager-sdk)"[[:space:]]*:[[:space:]]*"[0-9]+\.[0-9]+\.[0-9]+-[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9a-f]+"' -- '*package.json' \
|
|
153
|
-
| sed -E 's/.*"([^"]+)"$/\1/' | sort -u | grep -vxF "$new_media" || true)"
|
|
176
|
+
| sed -E 's/.*"([^"]+)"$/\1/' | sort -u | grep -vxF "$old_media" | grep -vxF "$new_media" || true)"
|
|
154
177
|
if [ -n "$stranded" ]; then
|
|
155
178
|
echo "::error::npm norsk pins are stranded off the nightly channel: $(printf '%s' "$stranded" | tr '\n' ' ')"
|
|
156
179
|
echo "The media family (api, sdk, auto-manager, manager-sdk) and the launched image are built from the same"
|
|
@@ -159,76 +182,85 @@ jobs:
|
|
|
159
182
|
exit 1
|
|
160
183
|
fi
|
|
161
184
|
|
|
162
|
-
# STUDIO:
|
|
163
|
-
#
|
|
164
|
-
#
|
|
165
|
-
#
|
|
166
|
-
#
|
|
167
|
-
#
|
|
168
|
-
#
|
|
169
|
-
#
|
|
170
|
-
#
|
|
171
|
-
#
|
|
172
|
-
# (no dependence on which files hold each — some products have no
|
|
173
|
-
# version-pin test).
|
|
185
|
+
# STUDIO: the studio npm packages and the studio image are built from
|
|
186
|
+
# DIFFERENT commits -- their hash suffixes never match -- so the image
|
|
187
|
+
# comes from the pair and the build libraries from npm's nightly. The
|
|
188
|
+
# libraries must belong to the same pair: their norsk-sdk dependency has
|
|
189
|
+
# to name the pair's engine, and their version line the image's. A
|
|
190
|
+
# mismatch means the channels are inconsistent (studio published npm
|
|
191
|
+
# without updating the manifest, or the reverse); refuse rather than pin
|
|
192
|
+
# a combination nobody tested. (Studio's publish installs the SDK it
|
|
193
|
+
# builds against as a DEV dependency -- `npm install --save-dev
|
|
194
|
+
# @norskvideo/norsk-sdk@<channel>` -- so that is where the pairing lives.)
|
|
174
195
|
#
|
|
175
196
|
# The old npm pin is discovered from the repo's REAL studio deps: any
|
|
176
197
|
# exact nightly on a @norskvideo/norsk-studio* package in a tracked
|
|
177
|
-
# package.json (deps, devDeps, or overrides
|
|
178
|
-
# repo with none skips the lib
|
|
179
|
-
#
|
|
180
|
-
# pins disagreeing across files abort rather than half-rewrite.
|
|
198
|
+
# package.json (deps, devDeps, or overrides -- wherever it lives). A
|
|
199
|
+
# repo with none skips the lib entirely. Distinct pins disagreeing
|
|
200
|
+
# across files abort rather than half-rewrite.
|
|
181
201
|
old_studio_lib="$(git grep -hoE '"@norskvideo/norsk-studio[^"]*"[[:space:]]*:[[:space:]]*"[0-9]+\.[0-9]+\.[0-9]+-[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9a-f]+"' -- '*package.json' \
|
|
182
202
|
| sed -E 's/.*"([^"]+)"$/\1/' | sort -u || true)"
|
|
183
203
|
if [ "$(printf '%s' "$old_studio_lib" | grep -c .)" -gt 1 ]; then
|
|
184
204
|
echo "studio npm pins disagree across package.json files:"; echo "$old_studio_lib"; exit 1
|
|
185
205
|
fi
|
|
186
|
-
new_studio_lib="$(curl -fsSL --retry 3 --retry-all-errors --retry-delay 2 "$reg/@norskvideo%2Fnorsk-studio" | jq -r '."dist-tags".nightly')"
|
|
187
|
-
[ -n "$new_studio_lib" ] && [ "$new_studio_lib" != "null" ] || { echo "could not resolve norsk-studio npm nightly"; exit 1; }
|
|
188
|
-
studio_line="${new_studio_lib%%-*}" # e.g. 1.28.0 — keep the image on this line
|
|
189
206
|
old_studio_img="$(jq -r '.latest.studio | split(":")[1]' manifest.seed.json)"
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
echo "Either the npm and docker version lines have diverged, or nightly has moved to a"
|
|
212
|
-
echo "different line than the npm nightly ($new_studio_lib). Not guessing — fix the channel."
|
|
213
|
-
exit 1
|
|
214
|
-
}
|
|
215
|
-
echo "studio lib: ${old_studio_lib:-<no npm pins>} -> $new_studio_lib"
|
|
207
|
+
new_studio_lib=""
|
|
208
|
+
if [ -n "$old_studio_lib" ]; then
|
|
209
|
+
studio_doc="$(curl -fsSL --retry 3 --retry-all-errors --retry-delay 2 "$reg/@norskvideo%2Fnorsk-studio")"
|
|
210
|
+
new_studio_lib="$(jq -r '."dist-tags".nightly // empty' <<<"$studio_doc")"
|
|
211
|
+
[ -n "$new_studio_lib" ] || { echo "could not resolve norsk-studio npm nightly"; exit 1; }
|
|
212
|
+
lib_sdk="$(jq -r --arg v "$new_studio_lib" \
|
|
213
|
+
'.versions[$v] | ((.devDependencies // {}) + (.peerDependencies // {}) + (.dependencies // {}))["@norskvideo/norsk-sdk"] // empty' <<<"$studio_doc")"
|
|
214
|
+
lib_sdk="${lib_sdk#^}"; lib_sdk="${lib_sdk#~}"
|
|
215
|
+
if [ "$lib_sdk" != "$new_media" ]; then
|
|
216
|
+
echo "::error::norsk-studio npm nightly $new_studio_lib was built against norsk-sdk ${lib_sdk:-<none declared>}, not the tested pair's engine $new_media."
|
|
217
|
+
echo "The npm channel and the channel manifest disagree; not pinning a combination nobody tested."
|
|
218
|
+
exit 1
|
|
219
|
+
fi
|
|
220
|
+
if [ "${new_studio_lib%%-*}" != "${new_studio_img%%-*}" ]; then
|
|
221
|
+
echo "::error::norsk-studio npm nightly $new_studio_lib is on a different version line from the pair's image $new_studio_img."
|
|
222
|
+
exit 1
|
|
223
|
+
fi
|
|
224
|
+
fi
|
|
225
|
+
|
|
226
|
+
echo "media: $old_media -> $new_media"
|
|
227
|
+
echo "studio lib: ${old_studio_lib:-<no npm pins>} -> ${new_studio_lib:-<unchanged>}"
|
|
216
228
|
echo "studio image: $old_studio_img -> $new_studio_img"
|
|
229
|
+
if [ "$old_media" != "$new_media" ]; then
|
|
230
|
+
git grep -lF "$old_media" -- . ':!bun.lock' | xargs -r sed -i "s|$old_media|$new_media|g"
|
|
231
|
+
changed=1
|
|
232
|
+
parts+=("media \`$new_media\`")
|
|
233
|
+
fi
|
|
234
|
+
# Rewrite the image ref FIRST, then the bare library version -- so even
|
|
235
|
+
# when the two coincide, the image ref has already moved and the
|
|
236
|
+
# bare-version rewrite only touches the npm pins.
|
|
217
237
|
if [ "$old_studio_img" != "$new_studio_img" ]; then
|
|
218
238
|
git grep -lF "norskvideo/norsk-studio:$old_studio_img" -- . ':!bun.lock' \
|
|
219
239
|
| xargs -r sed -i "s|norskvideo/norsk-studio:$old_studio_img|norskvideo/norsk-studio:$new_studio_img|g"
|
|
240
|
+
# And the tag on its own: a product can carry it unprefixed (onair2026's
|
|
241
|
+
# committed template input has `"studioTag": "<tag>"`), which the
|
|
242
|
+
# prefixed rewrite never reached -- the engine moved, studio did not,
|
|
243
|
+
# and the repo's own pin test went red (2026-10-04). Safe because the
|
|
244
|
+
# image tag and the npm library version are different strings; if
|
|
245
|
+
# they ever coincide, the bare rewrite would also hit the lib pins, so
|
|
246
|
+
# it is skipped and the lib rewrite below owns that string.
|
|
247
|
+
if [ "$old_studio_img" != "$old_studio_lib" ]; then
|
|
248
|
+
# `|| true`: after the prefixed rewrite most repos have no bare
|
|
249
|
+
# occurrence left, and git grep exits 1 on no match (pipefail).
|
|
250
|
+
{ git grep -lF "$old_studio_img" -- . ':!bun.lock' || true; } | xargs -r sed -i "s|$old_studio_img|$new_studio_img|g"
|
|
251
|
+
fi
|
|
220
252
|
changed=1
|
|
221
253
|
fi
|
|
222
|
-
if [ -n "$
|
|
254
|
+
if [ -n "$new_studio_lib" ] && [ "$old_studio_lib" != "$new_studio_lib" ]; then
|
|
223
255
|
git grep -lF "$old_studio_lib" -- . ':!bun.lock' | xargs -r sed -i "s|$old_studio_lib|$new_studio_lib|g"
|
|
224
256
|
changed=1
|
|
225
257
|
fi
|
|
226
|
-
# One studio entry, not two
|
|
258
|
+
# One studio entry, not two -- the launched image tag is the runtime-
|
|
227
259
|
# relevant one; only fall back to the lib tag if the image held but the
|
|
228
|
-
# library advanced
|
|
260
|
+
# library advanced.
|
|
229
261
|
if [ "$old_studio_img" != "$new_studio_img" ]; then
|
|
230
262
|
parts+=("studio \`$new_studio_img\`")
|
|
231
|
-
elif [ -n "$
|
|
263
|
+
elif [ -n "$new_studio_lib" ] && [ "$old_studio_lib" != "$new_studio_lib" ]; then
|
|
232
264
|
parts+=("studio-lib \`$new_studio_lib\`")
|
|
233
265
|
fi
|
|
234
266
|
|
|
@@ -299,6 +331,8 @@ jobs:
|
|
|
299
331
|
if: steps.bump.outputs.changed == '1' && steps.gate.outcome == 'success'
|
|
300
332
|
env:
|
|
301
333
|
API_TOKEN: ${{ secrets.CI_DISPATCH_TOKEN }}
|
|
334
|
+
# Through env, never pasted into the script (see the PR step below).
|
|
335
|
+
SUMMARY: ${{ steps.bump.outputs.summary }}
|
|
302
336
|
run: |
|
|
303
337
|
set -euo pipefail
|
|
304
338
|
# This bump is about to land, which makes any upgrade-latest/* PR an earlier
|
|
@@ -321,7 +355,7 @@ jobs:
|
|
|
321
355
|
git add -A
|
|
322
356
|
git commit -m "chore: bump Norsk nightly + ctl pins to latest channel
|
|
323
357
|
|
|
324
|
-
${
|
|
358
|
+
${SUMMARY}
|
|
325
359
|
|
|
326
360
|
Coupled Norsk pins (npm overrides + manifest.seed.json image tags +
|
|
327
361
|
version-pin guard test) moved together via a global version-string
|
|
@@ -351,6 +385,11 @@ jobs:
|
|
|
351
385
|
if: steps.bump.outputs.changed == '1' && steps.gate.outcome == 'failure'
|
|
352
386
|
env:
|
|
353
387
|
API_TOKEN: ${{ secrets.CI_DISPATCH_TOKEN }}
|
|
388
|
+
# Through env, never pasted into the script: the summary wraps each
|
|
389
|
+
# version in backticks, and inside a double-quoted shell string those
|
|
390
|
+
# ran as commands ("1.3.1-...: command not found"), dropping every
|
|
391
|
+
# version from the commit message and PR body.
|
|
392
|
+
SUMMARY: ${{ steps.bump.outputs.summary }}
|
|
354
393
|
run: |
|
|
355
394
|
set -euo pipefail
|
|
356
395
|
branch="upgrade-latest/nightly"
|
|
@@ -360,7 +399,7 @@ jobs:
|
|
|
360
399
|
git add -A
|
|
361
400
|
git commit -m "chore: bump Norsk nightly + ctl pins to latest channel (needs reconciliation)
|
|
362
401
|
|
|
363
|
-
${
|
|
402
|
+
${SUMMARY}"
|
|
364
403
|
git push -f origin "$branch"
|
|
365
404
|
title="Bump Norsk nightly + ctl pins to latest channel"
|
|
366
405
|
body="$(printf '%s\n' \
|
|
@@ -368,7 +407,7 @@ jobs:
|
|
|
368
407
|
"pins came with it -- but the product gate is **red**, so this bump needs a" \
|
|
369
408
|
"human before it reaches main." \
|
|
370
409
|
"" \
|
|
371
|
-
" ${
|
|
410
|
+
" ${SUMMARY}" \
|
|
372
411
|
"" \
|
|
373
412
|
"A red gate here usually means the new Norsk nightly is bad, or genuinely" \
|
|
374
413
|
"changed something the product depends on. Run it to see which:" \
|