@norskvideo/ctl-dev-kit 0.2.34 → 0.2.36
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.
|
@@ -208,6 +208,31 @@ jobs:
|
|
|
208
208
|
# in here and breaks a schema handed across the instance boundary.
|
|
209
209
|
bun node_modules/@norskvideo/ctl-dev-kit/conventions/zod-singleton.ts
|
|
210
210
|
'
|
|
211
|
+
# licenseTemplate.json records the entry a licence is minted from: this
|
|
212
|
+
# product at the image CI builds. One naming another image mints a licence
|
|
213
|
+
# that entitles nothing, first seen as a refused launch at the customer.
|
|
214
|
+
# The Studio checks pair this with check-product-name (the compose asks
|
|
215
|
+
# for what is recorded); an sdk-app names itself in its own handshake, so
|
|
216
|
+
# there is no Studio declaration to lint. Cheap, no secrets, every PR.
|
|
217
|
+
#
|
|
218
|
+
# The image name is CI's own rule: PUBLISH_IMAGE when set, else the build
|
|
219
|
+
# script's IMAGE_TAG default, tag stripped -- a licence matches the repo
|
|
220
|
+
# part alone, never the tag.
|
|
221
|
+
- name: Check this repo records its own licence
|
|
222
|
+
run: |
|
|
223
|
+
set -euo pipefail
|
|
224
|
+
product="$(sed -nE 's/.*PRODUCT_NAME[[:space:]]*=[[:space:]]*"([^"]+)".*/\1/p' src/product/version.ts | head -1)"
|
|
225
|
+
[ -n "$product" ] || { echo "::error::could not read PRODUCT_NAME from src/product/version.ts"; exit 1; }
|
|
226
|
+
pub="$(sed -nE 's/^[[:space:]]*PUBLISH_IMAGE:[[:space:]]*"?([^" ]*)"?[[:space:]]*$/\1/p' .github/workflows/build-image.yml | head -1)"
|
|
227
|
+
def="$(sed -nE 's/.*IMAGE_TAG:-([^}]+)\}.*/\1/p' deployment/build-image.sh | head -1)"
|
|
228
|
+
ref="${pub:-$def}"
|
|
229
|
+
# A colon is a tag only after the last slash (a registry host may carry a port).
|
|
230
|
+
image="${ref%:*}"
|
|
231
|
+
case "${ref##*/}" in *:*) ;; *) image="$ref" ;; esac
|
|
232
|
+
[ -n "$image" ] || { echo "::error::could not determine the image this repo builds"; exit 1; }
|
|
233
|
+
nix develop .#build --command bun \
|
|
234
|
+
node_modules/@norskvideo/ctl-dev-kit/licence/check-template.ts \
|
|
235
|
+
licenseTemplate.json "$product" "$image"
|
|
211
236
|
- name: Reap the containers this job launched
|
|
212
237
|
# Whatever the tests did. A teardown cut short by a test timeout leaves
|
|
213
238
|
# its instance running on the shared Docker daemon (see JOB_REAP_STEP in
|
|
@@ -30,6 +30,11 @@ on:
|
|
|
30
30
|
schedule:
|
|
31
31
|
- cron: "30 1 * * *" # 01:30 UTC — ahead of ctl's nightly docs build
|
|
32
32
|
workflow_dispatch:
|
|
33
|
+
inputs:
|
|
34
|
+
publish:
|
|
35
|
+
description: "Publish the regenerated manual. Off runs every guide tier and reports the result without touching the docs-latest release (a branch dry run)."
|
|
36
|
+
type: boolean
|
|
37
|
+
default: true
|
|
33
38
|
|
|
34
39
|
permissions:
|
|
35
40
|
contents: write # move the docs-latest release + clobber its asset
|
|
@@ -226,6 +231,7 @@ jobs:
|
|
|
226
231
|
# gh is on PATH inside the nix shell; `upload --clobber` replaces the
|
|
227
232
|
# same-named asset in place, so the release stays latest-only.
|
|
228
233
|
- name: Publish manual.html to the moving docs-latest release
|
|
234
|
+
if: ${{ github.event_name != 'workflow_dispatch' || inputs.publish }}
|
|
229
235
|
env:
|
|
230
236
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
231
237
|
run: |
|
|
@@ -274,6 +280,7 @@ jobs:
|
|
|
274
280
|
# exports map, so this works whether ctl-dev-kit is the published package or
|
|
275
281
|
# a workspace link (scripts/set-ctl-source.ts local mode).
|
|
276
282
|
- name: Publish the versioned docs bundle and move the pointer
|
|
283
|
+
if: ${{ github.event_name != 'workflow_dispatch' || inputs.publish }}
|
|
277
284
|
env:
|
|
278
285
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
279
286
|
# How many bundles to keep on the release, the current one included.
|
|
@@ -308,6 +315,7 @@ jobs:
|
|
|
308
315
|
# key through ci-workflows' registry, so a new product needs no new mapping
|
|
309
316
|
# here. Not wrapped in nix -- plain curl, and the quoting stays readable.
|
|
310
317
|
- name: Tell norsk-ctl a new bundle is published
|
|
318
|
+
if: ${{ github.event_name != 'workflow_dispatch' || inputs.publish }}
|
|
311
319
|
env:
|
|
312
320
|
DISPATCH_TOKEN: ${{ secrets.CI_DISPATCH_TOKEN }}
|
|
313
321
|
run: |
|
|
@@ -337,3 +345,103 @@ jobs:
|
|
|
337
345
|
echo "::warning::removing containers this job left running:$s"
|
|
338
346
|
docker rm -f $s
|
|
339
347
|
fi
|
|
348
|
+
|
|
349
|
+
# Report the result to the aggregated product CI dashboard (id3as/ci-workflows)
|
|
350
|
+
# as the `docs` cell. Red as well as green: the guides failed every night for a
|
|
351
|
+
# month while the board showed nothing, because this workflow never reported.
|
|
352
|
+
# A dry run (publish off) stays off the board -- it may be a branch.
|
|
353
|
+
notify:
|
|
354
|
+
needs: [publish]
|
|
355
|
+
if: ${{ !cancelled() && (github.event_name != 'workflow_dispatch' || inputs.publish) }}
|
|
356
|
+
runs-on: x64
|
|
357
|
+
steps:
|
|
358
|
+
# Runs BEFORE checkout, and does two things: points the harness's temp base
|
|
359
|
+
# out of the workspace for every later step in this job, and clears whatever
|
|
360
|
+
# the old repo-local default left behind on this runner. The body carries the
|
|
361
|
+
# why. It fails the job only when legacy litter survives -- which would take
|
|
362
|
+
# the checkout down a step later anyway, but report nothing useful.
|
|
363
|
+
- name: Route test-temp out of the workspace (pre-checkout)
|
|
364
|
+
run: |
|
|
365
|
+
set -uo pipefail
|
|
366
|
+
# These runners are docker-OUTSIDE-of-docker, so a bind-mount source the
|
|
367
|
+
# HOST daemon has not seen before is created by dockerd, as ROOT, on the
|
|
368
|
+
# host -- even when the launch passes --container-user (reproduced
|
|
369
|
+
# 2026-09-04). The harness's default base is repo-local for an OrbStack
|
|
370
|
+
# inotify constraint that binds macOS dev and nothing here, so every run
|
|
371
|
+
# seeded the CHECKOUT with root-owned dirs a non-root `git clean -ffdx`
|
|
372
|
+
# cannot remove. That took commentary's checks AND integration red on
|
|
373
|
+
# 2026-09-03. Use the sanctioned override, per-run and outside the
|
|
374
|
+
# checkout -- as 8ff17a8d did in June for one debug workflow, and stopped.
|
|
375
|
+
base="$RUNNER_TEMP/nctt-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
|
|
376
|
+
mkdir -p "$base"
|
|
377
|
+
echo "NORSK_CTL_TEST_TMP=$base" >> "$GITHUB_ENV"
|
|
378
|
+
# Yesterday's bases hold dockerd-created root dirs, so a non-root rm
|
|
379
|
+
# EACCESes. They cannot wedge a checkout, but they do fill the disk.
|
|
380
|
+
for old in $(find "$RUNNER_TEMP" -maxdepth 1 -name 'nctt-*' -mtime +0 -printf '%f\n' 2>/dev/null || true); do
|
|
381
|
+
docker run --rm --user 0:0 -v "$RUNNER_TEMP":/t alpine sh -c 'rm -rf -- "/t/$1"' sh "$old" >/dev/null 2>&1 || true
|
|
382
|
+
done
|
|
383
|
+
# LEGACY: a runner that ran the old default still carries a workspace
|
|
384
|
+
# test-temp, and a checkout with clean:true dies on it. Reap the holders
|
|
385
|
+
# first -- rm cannot unlink a live mountpoint even as root (EBUSY), and a
|
|
386
|
+
# RESTARTING leaked container re-creates the path as root seconds after
|
|
387
|
+
# any clean. Match on mount SOURCE, not a label: the holders are untracked
|
|
388
|
+
# by construction, because a killed run labels nothing.
|
|
389
|
+
tt="$GITHUB_WORKSPACE/test-temp"
|
|
390
|
+
[ -d "$tt" ] || exit 0
|
|
391
|
+
stuck=""
|
|
392
|
+
for c in $(docker ps -aq 2>/dev/null || true); do
|
|
393
|
+
if docker inspect -f '{{range .Mounts}}{{println .Source}}{{end}}' "$c" 2>/dev/null | grep -q "^$tt/"; then
|
|
394
|
+
stuck="$stuck $c"
|
|
395
|
+
fi
|
|
396
|
+
done
|
|
397
|
+
if [ -n "$stuck" ]; then
|
|
398
|
+
echo "reaping containers holding mounts under $tt:$stuck"
|
|
399
|
+
docker rm -f $stuck || true
|
|
400
|
+
fi
|
|
401
|
+
# The DIRECTORY, not just its contents: an empty but root-owned base
|
|
402
|
+
# still EACCESes a later mkdtemp. Mounting the PARENT is what lets a root
|
|
403
|
+
# container unlink the leaf.
|
|
404
|
+
docker run --rm --user 0:0 -v "$GITHUB_WORKSPACE":/w alpine \
|
|
405
|
+
sh -c 'rm -rf /w/test-temp' || rm -rf "$tt" || true
|
|
406
|
+
# Fail HERE if it survived. The checkout fails on it either way, but
|
|
407
|
+
# reports only an EACCES rmdir with no clue what was holding the path.
|
|
408
|
+
if [ -e "$tt" ]; then
|
|
409
|
+
echo "::error::$tt survived the pre-checkout clean"
|
|
410
|
+
ls -lan "$tt" || true
|
|
411
|
+
exit 1
|
|
412
|
+
fi
|
|
413
|
+
|
|
414
|
+
- uses: actions/checkout@v5
|
|
415
|
+
with:
|
|
416
|
+
clean: true
|
|
417
|
+
- id: meta
|
|
418
|
+
run: |
|
|
419
|
+
if [ "${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}" = "true" ]; then
|
|
420
|
+
echo "state=failure" >> "$GITHUB_OUTPUT"
|
|
421
|
+
else
|
|
422
|
+
echo "state=success" >> "$GITHUB_OUTPUT"
|
|
423
|
+
fi
|
|
424
|
+
- uses: ./.github/actions/ci-status-dispatch
|
|
425
|
+
with:
|
|
426
|
+
token: ${{ secrets.CI_DISPATCH_TOKEN }}
|
|
427
|
+
product: __PRODUCT__
|
|
428
|
+
pipeline: docs
|
|
429
|
+
status: ${{ steps.meta.outputs.state }}
|
|
430
|
+
- name: Reap the containers this job launched
|
|
431
|
+
# Whatever the tests did. A teardown cut short by a test timeout leaves
|
|
432
|
+
# its instance running on the shared Docker daemon (see JOB_REAP_STEP in
|
|
433
|
+
# conventions/workflow-shell.ts); everything this job launched mounts its
|
|
434
|
+
# own test-temp, so that is what goes.
|
|
435
|
+
if: always()
|
|
436
|
+
run: |
|
|
437
|
+
base="${NORSK_CTL_TEST_TMP:-}"
|
|
438
|
+
tt="$GITHUB_WORKSPACE/test-temp"
|
|
439
|
+
s=""
|
|
440
|
+
for c in $(docker ps -aq); do
|
|
441
|
+
src="$(docker inspect -f '{{range .Mounts}}{{println .Source}}{{end}}' "$c" 2>/dev/null)" || continue
|
|
442
|
+
if { [ -n "$base" ] && grep -q "^$base/" <<<"$src"; } || grep -q "^$tt/" <<<"$src"; then s="$s $c"; fi
|
|
443
|
+
done
|
|
444
|
+
if [ -n "$s" ]; then
|
|
445
|
+
echo "::warning::removing containers this job left running:$s"
|
|
446
|
+
docker rm -f $s
|
|
447
|
+
fi
|