navidrome/.github/workflows/detect-changes_test.sh
Deluan 27abc83ac8 ci: add the detect-changes test suite
Thirty assertions over the change shapes the filters have to get right,
including the ones that only appeared under review: a large diff that used to
lose flags to SIGPIPE, renames that hide their source path, and an unresolvable
base ref that must fail closed rather than emit every flag as false.

It builds a throwaway repo per case, so it needs no fixtures and leaves nothing
behind. Nothing runs it in CI yet; it is a development tool for whoever changes
a regex next.
2026-09-06 23:49:42 -04:00

110 lines
5.5 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# Tests detect-changes.sh against a throwaway repo: builds a synthetic PR for
# each change shape and asserts the four emitted flags.
#
# ./.github/workflows/detect-changes_test.sh # tests the sibling script
# ./.github/workflows/detect-changes_test.sh <path> # tests another copy
#
# To confirm a case still bites, edit a pattern out of detect-changes.sh and
# re-run: exactly the case that covers it should fail.
set -uo pipefail
SCRIPT="${1:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/detect-changes.sh}"
T=$(mktemp -d); O=$(mktemp -d)
cd "$T"
git init -q -b master .
git config user.email t@t; git config user.name t
mkdir -p ui/src/i18n resources/i18n .github/workflows db/migrations
echo x > README.md; echo x > main.go; echo x > ui/src/a.js
echo x > resources/i18n/pt.json; echo x > ui/src/i18n/en.json; echo x > go.mod
git add -A; git commit -qm base
git clone -q --bare . "$O/origin.git"
git remote add origin "$O/origin.git"
git fetch -q origin
fails=0
run() { # $1=label $2=expected "go js i18n build" ; rest=files
label="$1"; want="$2"; shift 2
git checkout -q -B test master
for f in "$@"; do mkdir -p "$(dirname "$f")"; echo change >> "$f"; done
git add -A >/dev/null; git commit -qm "$label"
got=$(GITHUB_EVENT_NAME=pull_request BASE_REF=master bash "$SCRIPT" 2>&1 \
| grep -E '^(go|js|i18n|build)=' | cut -d= -f2 | tr '\n' ' ' | sed 's/ $//')
if [ "$got" = "$want" ]; then printf 'ok %-32s %s\n' "$label" "$got"
else printf 'FAIL %-32s got[%s] want[%s]\n' "$label" "$got" "$want"; fails=$((fails+1)); fi
}
# go js i18n build
run "docs only" "false false false false" README.md
run "gitignore only" "false false false false" .gitignore
run "go only" "true false false true" core/thing.go
run "ui only" "false true false true" ui/src/b.js
run "i18n resources" "true false true true" resources/i18n/fr.json
run "ui en.json" "false true true true" ui/src/i18n/en.json
run "ui other i18n" "false true false true" ui/src/i18n/provider.js
run "db migration sql" "true false false true" db/migrations/20260101000000_x.sql
run "tests fixture" "true false false true" tests/fixtures/playlist.m3u
run "tests toml" "true false false true" tests/navidrome-test.toml
run "conf testdata" "false false false true" conf/testdata/cfg.toml
run "manifest schema" "true false false true" plugins/manifest-schema.json
run "other plugin json" "false false false true" plugins/testdata/fake/manifest-schema.json
run "nested go.mod" "true false false true" plugins/testdata/x/go.mod
run "Dockerfile only" "false false false true" Dockerfile
run "pipeline.yml" "true true true true" .github/workflows/pipeline.yml
run "detect-changes.sh" "true true true true" .github/workflows/detect-changes.sh
run "other workflow" "false false false true" .github/workflows/stale.yml
run "validate-trans.sh" "false false true true" .github/workflows/validate-translations.sh
echo "--- large diff must not lose flags to SIGPIPE ---"
git checkout -q -B test master
mkdir -p big/pkg
python3 -c "
import os
os.makedirs('big/pkg', exist_ok=True)
open('big/pkg/aaa_first.go','w').write('x')
for i in range(2500): open('big/pkg/filler_%04d.txt' % i,'w').write('x')
"
git add -A >/dev/null; git commit -qm big
nfiles=$(git diff --no-renames --name-only master...HEAD | wc -l | tr -d ' ')
for i in 1 2 3 4 5; do
got=$(GITHUB_EVENT_NAME=pull_request BASE_REF=master bash "$SCRIPT" 2>&1 \
| grep -E '^(go|js|i18n|build)=' | cut -d= -f2 | tr '\n' ' ' | sed 's/ $//')
if [ "$got" = "true false false true" ]; then printf 'ok %-32s %s (%s files)\n' "large diff run $i" "$got" "$nfiles"
else printf 'FAIL %-32s got[%s] want[true false false true] (%s files)\n' "large diff run $i" "$got" "$nfiles"; fails=$((fails+1)); fi
done
echo "--- renames must count the source path ---"
rn() { # $1=label $2=expected $3=from $4=to
git checkout -q -B test master
mkdir -p "$(dirname "$4")"; git mv "$3" "$4"
git add -A >/dev/null; git commit -qm "$1"
got=$(GITHUB_EVENT_NAME=pull_request BASE_REF=master bash "$SCRIPT" 2>&1 \
| grep -E '^(go|js|i18n|build)=' | cut -d= -f2 | tr '\n' ' ' | sed 's/ $//')
if [ "$got" = "$2" ]; then printf 'ok %-32s %s\n' "$1" "$got"
else printf 'FAIL %-32s got[%s] want[%s]\n' "$1" "$got" "$2"; fails=$((fails+1)); fi
}
# go js i18n build
rn "ui .js -> docs .md" "false true false true" ui/src/a.js docs/a.js.md
rn "go -> docs .md" "true false false true" main.go docs/main.go.md
echo "--- non-PR events ---"
git checkout -q master
for ev in push workflow_dispatch; do
got=$(GITHUB_EVENT_NAME=$ev bash "$SCRIPT" 2>&1 | grep -E '^(go|js|i18n|build)=' | cut -d= -f2 | tr '\n' ' ' | sed 's/ $//')
if [ "$got" = "true true true true" ]; then printf 'ok %-32s %s\n' "$ev" "$got"
else printf 'FAIL %-32s got[%s]\n' "$ev" "$got"; fails=$((fails+1)); fi
done
echo "--- unresolvable base ref must fail closed ---"
git checkout -q -B test master; echo x >> main.go; git add -A >/dev/null; git commit -qm x
out=$(GITHUB_EVENT_NAME=pull_request BASE_REF=does-not-exist bash "$SCRIPT" 2>&1); rc=$?
if [ "$rc" != "0" ] && ! grep -qE '^(go|js|i18n|build)=' <<<"$out"; then
printf 'ok %-32s exit=%s, no flags emitted\n' "bad base ref" "$rc"
else
printf 'FAIL %-32s exit=%s out[%s]\n' "bad base ref" "$rc" "$out"; fails=$((fails+1))
fi
echo
echo "failures: $fails"
cd /; rm -rf "$T" "$O"
exit "$fails"