@norskvideo/ctl-dev-kit 0.1.13 → 0.1.15
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/build/build-image.bootstrap.sh +18 -0
- package/build/flake.nix +17 -1
- package/conventions/CLAUDE.core.md +14 -10
- package/conventions/biome.base.json +44 -0
- package/conventions/check-drift.ts +252 -25
- package/conventions/checks.yml +77 -0
- package/conventions/dprint.base.jsonc +37 -0
- package/conventions/gitignore.core +18 -0
- package/conventions/tsconfig.base.json +14 -0
- package/conventions/upgrade-latest.yml +26 -13
- package/create-product/assets/ci-status-dispatch.yml +70 -0
- package/create-product/backend-turnkey.ts +1389 -0
- package/create-product/canon.ts +52 -0
- package/create-product/cli.ts +84 -0
- package/create-product/create-product.ts +178 -0
- package/package.json +11 -2
- package/testing/INVARIANTS.template.md +49 -0
- package/testing/byte-snapshot.ts +43 -0
- package/testing/invariants.ts +117 -0
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# Keep the product fresh against the Norsk "nightly" channel (RFC 0001 —
|
|
2
|
-
# product version freshness).
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
2
|
+
# product version freshness). Version discovery anchors on manifest.seed.json
|
|
3
|
+
# (the machine-writable source of truth for the launched {media, studio} image
|
|
4
|
+
# pair — every product repo has one). Any npm pins on the same version string
|
|
5
|
+
# (media build libraries, the @norskvideo/norsk-studio* family in whichever
|
|
6
|
+
# tracked package.json actually depends on them) move in lockstep via a global
|
|
7
|
+
# string-replace of old->new across every tracked file — which also updates the
|
|
8
|
+
# version-pin guard test, no drift. A repo with no studio npm deps needs no
|
|
9
|
+
# package.json `overrides` block at all. Also rebumps the dev flake's pinned
|
|
10
|
+
# norsk-ctl daemon to the `latest` channel (dev-only; CI downloads ctl
|
|
11
|
+
# directly, so a stale pin never affects CI or customers).
|
|
10
12
|
#
|
|
11
13
|
# Commits the bump straight to main (nightly cron + on demand). Note: a
|
|
12
14
|
# GITHUB_TOKEN push does not retrigger build-image/integration (Actions'
|
|
@@ -75,10 +77,21 @@ jobs:
|
|
|
75
77
|
# THE SAME version line (so it's pullable AND matches the libs'
|
|
76
78
|
# major.minor.patch). Rewrite the image ref FIRST, then the bare library
|
|
77
79
|
# version — so even when the two happen to coincide, the image ref is
|
|
78
|
-
# already moved and the bare-version rewrite only touches the npm
|
|
80
|
+
# already moved and the bare-version rewrite only touches the npm pins
|
|
79
81
|
# (no dependence on which files hold each — some products have no
|
|
80
82
|
# version-pin test).
|
|
81
|
-
|
|
83
|
+
#
|
|
84
|
+
# The old npm pin is discovered from the repo's REAL studio deps: any
|
|
85
|
+
# exact nightly on a @norskvideo/norsk-studio* package in a tracked
|
|
86
|
+
# package.json (deps, devDeps, or overrides — wherever it lives). A
|
|
87
|
+
# repo with none skips the lib rewrite; nothing forces phantom
|
|
88
|
+
# `overrides` entries just to give this script an anchor. Distinct
|
|
89
|
+
# pins disagreeing across files abort rather than half-rewrite.
|
|
90
|
+
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' \
|
|
91
|
+
| sed -E 's/.*"([^"]+)"$/\1/' | sort -u || true)"
|
|
92
|
+
if [ "$(printf '%s' "$old_studio_lib" | grep -c .)" -gt 1 ]; then
|
|
93
|
+
echo "studio npm pins disagree across package.json files:"; echo "$old_studio_lib"; exit 1
|
|
94
|
+
fi
|
|
82
95
|
new_studio_lib="$(curl -fsSL "$reg/@norskvideo%2Fnorsk-studio" | jq -r '."dist-tags".nightly')"
|
|
83
96
|
[ -n "$new_studio_lib" ] && [ "$new_studio_lib" != "null" ] || { echo "could not resolve norsk-studio npm nightly"; exit 1; }
|
|
84
97
|
studio_line="${new_studio_lib%%-*}" # e.g. 1.28.0 — keep the image on this line
|
|
@@ -87,14 +100,14 @@ jobs:
|
|
|
87
100
|
| jq -r '.results[].name' \
|
|
88
101
|
| grep -E "^${studio_line}-[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9a-f]+$" | head -1 || true)"
|
|
89
102
|
[ -n "$new_studio_img" ] || { echo "no published norsk-studio image on the $studio_line line — npm/docker version lines have diverged"; exit 1; }
|
|
90
|
-
echo "studio lib: $old_studio_lib -> $new_studio_lib"
|
|
103
|
+
echo "studio lib: ${old_studio_lib:-<no npm pins>} -> $new_studio_lib"
|
|
91
104
|
echo "studio image: $old_studio_img -> $new_studio_img"
|
|
92
105
|
if [ "$old_studio_img" != "$new_studio_img" ]; then
|
|
93
106
|
git grep -lF "norskvideo/norsk-studio:$old_studio_img" -- . ':!bun.lock' \
|
|
94
107
|
| xargs -r sed -i "s|norskvideo/norsk-studio:$old_studio_img|norskvideo/norsk-studio:$new_studio_img|g"
|
|
95
108
|
changed=1
|
|
96
109
|
fi
|
|
97
|
-
if [ "$old_studio_lib" != "$new_studio_lib" ]; then
|
|
110
|
+
if [ -n "$old_studio_lib" ] && [ "$old_studio_lib" != "$new_studio_lib" ]; then
|
|
98
111
|
git grep -lF "$old_studio_lib" -- . ':!bun.lock' | xargs -r sed -i "s|$old_studio_lib|$new_studio_lib|g"
|
|
99
112
|
changed=1
|
|
100
113
|
fi
|
|
@@ -103,7 +116,7 @@ jobs:
|
|
|
103
116
|
# library advanced (npm nightly moved with no new image on the line yet).
|
|
104
117
|
if [ "$old_studio_img" != "$new_studio_img" ]; then
|
|
105
118
|
parts+=("studio \`$new_studio_img\`")
|
|
106
|
-
elif [ "$old_studio_lib" != "$new_studio_lib" ]; then
|
|
119
|
+
elif [ -n "$old_studio_lib" ] && [ "$old_studio_lib" != "$new_studio_lib" ]; then
|
|
107
120
|
parts+=("studio-lib \`$new_studio_lib\`")
|
|
108
121
|
fi
|
|
109
122
|
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Report this pipeline's result to id3as/ci-workflows for the aggregated product
|
|
2
|
+
# CI dashboard (one live Discord message showing the whole product x pipeline
|
|
3
|
+
# grid). Replaces the old per-run pony post: the dashboard renders the pony now,
|
|
4
|
+
# from the payload this action dispatches.
|
|
5
|
+
#
|
|
6
|
+
# GITHUB_TOKEN can't repository_dispatch another repo, so the caller passes a
|
|
7
|
+
# CI_DISPATCH_TOKEN (a fine-grained PAT scoped to id3as/ci-workflows, Contents:
|
|
8
|
+
# write — what the dispatch API requires). If it's absent the step no-ops with a
|
|
9
|
+
# warning rather than failing the build, so a repo can adopt this before the
|
|
10
|
+
# token is provisioned.
|
|
11
|
+
name: CI status dispatch
|
|
12
|
+
description: Dispatch this pipeline's result to the id3as/ci-workflows product dashboard.
|
|
13
|
+
|
|
14
|
+
inputs:
|
|
15
|
+
token:
|
|
16
|
+
description: "PAT with Contents:write on id3as/ci-workflows. Pass secrets.CI_DISPATCH_TOKEN."
|
|
17
|
+
required: true
|
|
18
|
+
product:
|
|
19
|
+
description: "Product key: commentary | playout | probe | studio | funke | reuters."
|
|
20
|
+
required: true
|
|
21
|
+
pipeline:
|
|
22
|
+
description: "Pipeline key: build-image | integration | drift | nightly."
|
|
23
|
+
required: true
|
|
24
|
+
status:
|
|
25
|
+
description: "success or failure."
|
|
26
|
+
required: true
|
|
27
|
+
detail:
|
|
28
|
+
description: "Optional extra line shown under the cell (e.g. a nightly bump summary)."
|
|
29
|
+
required: false
|
|
30
|
+
default: ""
|
|
31
|
+
|
|
32
|
+
runs:
|
|
33
|
+
using: composite
|
|
34
|
+
steps:
|
|
35
|
+
- name: Dispatch ci-status to id3as/ci-workflows
|
|
36
|
+
shell: bash
|
|
37
|
+
env:
|
|
38
|
+
TOKEN: ${{ inputs.token }}
|
|
39
|
+
PRODUCT: ${{ inputs.product }}
|
|
40
|
+
PIPELINE: ${{ inputs.pipeline }}
|
|
41
|
+
STATUS: ${{ inputs.status }}
|
|
42
|
+
DETAIL: ${{ inputs.detail }}
|
|
43
|
+
SHA: ${{ github.sha }}
|
|
44
|
+
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
45
|
+
run: |
|
|
46
|
+
set -euo pipefail
|
|
47
|
+
if [ -z "$TOKEN" ]; then
|
|
48
|
+
echo "::warning::CI_DISPATCH_TOKEN not set — skipping product-dashboard dispatch"
|
|
49
|
+
exit 0
|
|
50
|
+
fi
|
|
51
|
+
ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
52
|
+
# jq assembles the payload so a bump summary with quotes/newlines can't
|
|
53
|
+
# break the JSON; detail is included only when non-empty.
|
|
54
|
+
payload="$(jq -cn \
|
|
55
|
+
--arg product "$PRODUCT" --arg pipeline "$PIPELINE" --arg conclusion "$STATUS" \
|
|
56
|
+
--arg sha "$SHA" --arg runUrl "$RUN_URL" --arg ts "$ts" --arg detail "$DETAIL" \
|
|
57
|
+
'{event_type: "ci-status", client_payload: (
|
|
58
|
+
{product: $product, pipeline: $pipeline, conclusion: $conclusion, sha: $sha, runUrl: $runUrl, ts: $ts}
|
|
59
|
+
+ (if $detail == "" then {} else {detail: $detail} end)
|
|
60
|
+
)}')"
|
|
61
|
+
code="$(curl -sS -o /tmp/dispatch-resp -w '%{http_code}' -X POST \
|
|
62
|
+
-H "authorization: Bearer $TOKEN" \
|
|
63
|
+
-H "accept: application/vnd.github+json" \
|
|
64
|
+
-H "x-github-api-version: 2022-11-28" \
|
|
65
|
+
"https://api.github.com/repos/id3as/ci-workflows/dispatches" \
|
|
66
|
+
-d "$payload")"
|
|
67
|
+
echo "dashboard dispatch: HTTP $code ($PRODUCT/$PIPELINE=$STATUS)"
|
|
68
|
+
if [ "$code" != "204" ]; then
|
|
69
|
+
echo "::error::dashboard dispatch failed (HTTP $code)"; cat /tmp/dispatch-resp || true; exit 1
|
|
70
|
+
fi
|