From 6b89cc9a48c98f9d9cff715b8aaec6dbae41ed8a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 19 Sep 2026 21:42:43 +0000 Subject: [PATCH] chore(sync): synced file(s) with cplieger/ci --- cliff.toml | 18 ++++++++++++++++++ scripts/collect-licenses.sh | 12 ++++++++++-- tests/image-smoke.sh | 29 +++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) mode change 100644 => 100755 scripts/collect-licenses.sh diff --git a/cliff.toml b/cliff.toml index ee4fa17..bb5ad68 100644 --- a/cliff.toml +++ b/cliff.toml @@ -135,6 +135,24 @@ exclude_paths = [ # form would miss it (measured on the pinned cliff v2.13.1 — bare excludes the # root file only, `**/` excludes both, and a real code commit still bumps). "**/.punused-ignore", + # knip suppressions and enrolment: the TS twin of .punused-ignore, read by + # ts-ci's unused-deps/exports gate. Dev-only, never in an artifact, and a + # suppression-only commit ships nothing — but `refactor:` is a RELEASING type, + # so a config-only commit was minting a version and a changelog line. + # release.yaml's EXCLUDE_PATTERNS already dropped it from the BUILD gate; this + # is the RELEASE gate catching up. All eight forms knip itself loads + # (KNIP_CONFIG_LOCATIONS in knip/dist/constants.js), since only knip.json is + # in use today and the others must not reopen the gap. `**/` not bare: every + # enrolled config lives beside its package.json, which in a hybrid repo is a + # subdirectory (static-src/, web/, internal/server/static-src/). + "**/knip.json", + "**/knip.jsonc", + "**/.knip.json", + "**/.knip.jsonc", + "**/knip.ts", + "**/knip.js", + "**/knip.config.ts", + "**/knip.config.js", ] commit_parsers = [ diff --git a/scripts/collect-licenses.sh b/scripts/collect-licenses.sh old mode 100644 new mode 100755 index 362af98..7b2ac6f --- a/scripts/collect-licenses.sh +++ b/scripts/collect-licenses.sh @@ -1,6 +1,6 @@ #!/bin/sh # Copy every linked Go module's license files into the /usr/share/licenses tree of -# attribution.md section 4. usage: collect-licenses.sh --name IMAGE [--out DIR] [PACKAGE ...] +# attribution.md section 4. usage: collect-licenses.sh --name IMAGE [--out DIR] [--src DIR] [PACKAGE ...] # CANONICAL COPY in cplieger/ci (configs/collect-licenses.sh), synced to each # root-Dockerfile repo's scripts/collect-licenses.sh: edit it there, never here. # A module with no license file fails the build rather than being skipped, because a @@ -9,12 +9,17 @@ set -eu OUT=/out/usr/share/licenses NAME="" +SRC=. while [ $# -gt 0 ]; do case "$1" in --out) OUT="${2:?--out needs a directory}" shift 2 ;; + --src) + SRC="${2:?--src needs a module directory}" + shift 2 + ;; --name) NAME="${2:?--name needs an image name}" shift 2 @@ -42,6 +47,8 @@ case "$NAME" in esac [ $# -gt 0 ] || set -- ./... export GOWORK=off +case "$OUT" in /*) ;; *) OUT="$PWD/$OUT" ;; esac +cd "$SRC" || exit 2 modules=0 files=0 @@ -54,7 +61,8 @@ copy_files() { for f in "$1"/*; do [ -f "$f" ] || continue if [ "$3" = licenses ]; then - case "${f##*/}" in + case "$(printf '%s' "${f##*/}" | tr '[:lower:]' '[:upper:]')" in + *.GO) continue ;; LICENSE* | LICENCE* | COPYING* | NOTICE*) ;; *) continue ;; esac diff --git a/tests/image-smoke.sh b/tests/image-smoke.sh index 42dbb0c..ff67486 100644 --- a/tests/image-smoke.sh +++ b/tests/image-smoke.sh @@ -20,6 +20,7 @@ SMOKE_APP_NAME="" SMOKE_TIMEOUT="" SMOKE_RUN_ARGS="" SMOKE_LOG_PATTERN="" +SMOKE_LICENSE_TREE="" # A .conf that creates host state overrides this. Defined BEFORE the source so the # EXIT trap can always call it. # shellcheck disable=SC2329 # invoked indirectly via the EXIT trap's cleanup() @@ -46,6 +47,13 @@ case "$TIMEOUT" in exit 1 ;; esac +case "$SMOKE_LICENSE_TREE" in + '' | 0 | 1) ;; + *) + printf 'FAIL: SMOKE_LICENSE_TREE must be 1, 0 or unset, got "%s"\n' "$SMOKE_LICENSE_TREE" >&2 + exit 1 + ;; +esac NAME="smoke-${APP}-$$" # shellcheck disable=SC2317,SC2329 # invoked indirectly via trap @@ -95,6 +103,27 @@ while [ "$(date +%s)" -lt "$deadline" ]; do sleep 1 continue fi + # Read through `docker cp`, since a distroless image has no shell to exec. + if [ "$SMOKE_LICENSE_TREE" = 1 ]; then + tree=$(mktemp -d) + if ! docker cp "$NAME:/usr/share/licenses" "$tree/" >/dev/null 2>&1; then + rm -rf "$tree" + printf 'FAIL: %s image has no /usr/share/licenses tree\n' "$APP" >&2 + exit 1 + fi + if [ ! -f "$tree/licenses/$APP/LICENSE" ]; then + rm -rf "$tree" + printf 'FAIL: %s image lacks /usr/share/licenses/%s/LICENSE\n' "$APP" "$APP" >&2 + exit 1 + fi + components=$(find "$tree/licenses" -mindepth 1 -maxdepth 1 -type d ! -name "$APP" | wc -l) + rm -rf "$tree" + if [ "$components" -lt 1 ]; then + printf 'FAIL: %s license tree holds only the image'\''s own files; no bundled component\n' "$APP" >&2 + exit 1 + fi + printf '%s license tree: own LICENSE plus %s bundled component(s)\n' "$APP" "$components" + fi # A failure here is a verdict, not a retry: health said up, so anything # smoke_verify finds missing is missing from the image. # shellcheck disable=SC2034 # consumed by the sourced .conf's smoke_verify