Files
修雨 474ce88d47 fix(ci): harden CLI smoke and Schema compatibility gates (#629)
* fix(ci): harden PR gate enforcement

* fix(schema): allow compatible positional evolution
2026-07-16 09:59:21 +08:00

124 lines
3.7 KiB
Bash
Executable File

#!/bin/sh
set -eu
# Verify that the shipped binary can render help for every public top-level
# command without login state or network access. Interface Integrity checks
# the complete tree; this smoke test checks the actual compiled artifact.
ROOT="$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)"
BIN="${DWS_BIN:-$ROOT/dws}"
BASELINE="$ROOT/test/fixtures/cli-interface-baseline.txt"
if [ ! -x "$BIN" ]; then
printf 'error: dws binary not found at %s (run make build first)\n' "$BIN" >&2
exit 1
fi
if [ ! -f "$BASELINE" ]; then
printf 'error: interface baseline missing at %s\n' "$BASELINE" >&2
exit 1
fi
SNAPSHOT_HOME="$(mktemp -d)"
SNAPSHOT_BIN="$(mktemp)"
CURRENT="$(mktemp)"
trap 'rm -rf "$CURRENT" "$SNAPSHOT_HOME" "$SNAPSHOT_BIN"' EXIT
cd "$ROOT"
go build -o "$SNAPSHOT_BIN" ./scripts/policy/interface-baseline
HOME="$SNAPSHOT_HOME" DWS_DISABLE_KEYCHAIN=1 DWS_LANG=zh "$SNAPSHOT_BIN" >"$CURRENT"
root_commands() {
awk '
/^\[root\]$/ {
in_root = 1
next
}
/^\[/ {
if (in_root) {
exit
}
next
}
in_root {
line = $0
sub(/^[[:space:]]*/, "", line)
if (line ~ /^commands:[[:space:]]*/) {
sub(/^commands:[[:space:]]*/, "", line)
gsub(/,[[:space:]]*/, " ", line)
print line
found = 1
exit
}
}
END {
if (!found) {
exit 1
}
}
' "$1"
}
baseline_commands="$(root_commands "$BASELINE")" || {
printf 'error: no root commands found in interface baseline\n' >&2
exit 1
}
current_commands="$(root_commands "$CURRENT")" || {
printf 'error: no root commands found in current interface contract\n' >&2
exit 1
}
if [ "$baseline_commands" != "$current_commands" ]; then
printf 'error: interface baseline root commands are stale (run make update-interface-baseline)\n' >&2
printf ' baseline: %s\n current: %s\n' "$baseline_commands" "$current_commands" >&2
exit 1
fi
# DWS_DISABLE_KEYCHAIN=1 routes the DEK to a file (the Linux scheme) instead of
# the macOS system Keychain. Without it, running the binary under this fresh
# HOME triggers a GUI Keychain authorization prompt that blocks the
# non-interactive smoke test indefinitely. Linux CI already uses the file DEK.
capture_help() {
HOME="$SNAPSHOT_HOME" DWS_DISABLE_KEYCHAIN=1 DWS_LANG=zh "$BIN" "$@" --help 2>&1
}
root_help="$(capture_help)" || {
printf 'error: dws --help exited non-zero\n%s\n' "$root_help" >&2
exit 1
}
run_command_help() {
output="$(HOME="$SNAPSHOT_HOME" DWS_DISABLE_KEYCHAIN=1 DWS_LANG=zh "$BIN" "$@" --help 2>&1)" || {
printf 'error: dws %s --help exited non-zero\n%s\n' "$*" "$output" >&2
return 1
}
if [ "$output" = "$root_help" ]; then
printf 'error: dws %s --help resolved to root help instead of command-specific help\n' "$*" >&2
return 1
fi
usage_line="$(printf '%s\n' "$output" | awk '/^Usage:$/ { getline; print; exit }')"
expected_usage=" dws $*"
case "$usage_line" in
"$expected_usage"|"$expected_usage "*) ;;
*)
printf 'error: dws %s --help reported unexpected usage identity: %s\n' "$*" "$usage_line" >&2
return 1
;;
esac
}
# Cobra currently treats an unknown command followed by --help as root help
# with exit status 0. Keep a negative case here so exit status alone can never
# make the smoke check pass for a command that did not resolve.
unknown_command="__dws_cli_smoke_unknown_command__"
if run_command_help "$unknown_command" >/dev/null 2>&1; then
printf 'error: unknown command %s unexpectedly produced command-specific help\n' "$unknown_command" >&2
exit 1
fi
count=0
for command in $current_commands; do
run_command_help "$command"
count=$((count + 1))
done
printf 'CLI smoke check: ok (root + %s public top-level commands)\n' "$count"