From 97da381318498417947cf3099c825098907c7dda Mon Sep 17 00:00:00 2001 From: sneak Date: Mon, 9 Nov 2026 09:03:40 +0000 Subject: [PATCH] update-policy: stop on a .golangci.yml line the canonical file lacks A repo's own lint setting outside the test-support deny list was deleted, and the deletion pushed with exit 0. The script now stops and names each such line. The check is one function that both merge steps call. An indented # line now counts as a comment, as YAML needs. Without --fail the stub curl now writes an error page and exits 0, and the bad-hash scenario checks for the fetch error. Model: opus-5-5 --- prompts/EXISTING_REPO_CHECKLIST.md | 4 +++- script/update-policy | 26 ++++++++++++++++++++------ test/update-policy.sh | 27 ++++++++++++++++++++++++++- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/prompts/EXISTING_REPO_CHECKLIST.md b/prompts/EXISTING_REPO_CHECKLIST.md index 6557c14..87197ab 100644 --- a/prompts/EXISTING_REPO_CHECKLIST.md +++ b/prompts/EXISTING_REPO_CHECKLIST.md @@ -216,7 +216,9 @@ with your task. entries in `.gitignore`, `.editorconfig` and `.dockerignore` go below the comment that ends each canonical file. An entry above that comment which the canonical file lacks makes the script stop before it writes anything, - naming the file and the entry. + naming the file and the entry. It stops the same way on a line in + `.golangci.yml` that the canonical file lacks, apart from comments and the + repo's entries in the `deny` list of the `test-support` rule. - [ ] README has an **Entrypoints** section documenting the `script/` entrypoints and linking the standard - [ ] `script/lint` and `script/test` each run diff --git a/script/update-policy b/script/update-policy index 6984511..021ff4b 100755 --- a/script/update-policy +++ b/script/update-policy @@ -13,7 +13,8 @@ # canonical file's last line. An entry above that line which the # canonical file lacks stops the script. # - .golangci.yml: the entries the repo added to the deny list of the -# test-support rule +# test-support rule. Any other line the canonical file lacks stops +# the script, unless it is blank or a comment. set -eu ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" @@ -56,6 +57,16 @@ local_path() { fi } +# local_only_lines [end]: print each line of the local +# file, above line end if given, that the fetched file lacks. Blank +# lines and comments do not count. +local_only_lines() { + awk -v end="${3:-}" ' + NR == FNR { fetched[$0]; next } + (end == "" || FNR < end) && !/^[ \t]*(#|$)/ && !($0 in fetched) + ' "$1" "$2" +} + # keep_lines_below_last : append to the fetched file # whatever follows its last line in the local file. Stop if a line above # that one is missing from the fetched file, unless it is blank or a @@ -66,10 +77,7 @@ keep_lines_below_last() { if [ -z "$last" ] || [ -z "$number" ]; then die "$2 lacks this line; add it and put the repo's own entries below it: $last" fi - own="$(awk -v end="$number" ' - NR == FNR { fetched[$0]; next } - FNR < end && !/^#|^[ \t]*$/ && !($0 in fetched) - ' "$1" "$2")" + own="$(local_only_lines "$1" "$2" "$number")" if [ -n "$own" ]; then die "$2 has entries above its last canonical line that the canonical file lacks; move each below that line to keep it, or delete it: $own" @@ -80,7 +88,8 @@ $own" # keep_deny_entries : add to the deny list of the # test-support rule in the fetched file the entries only the local file # has. An entry is a "- pkg:" line, the lines under it and any comment -# above it. +# above it. Stop if the local file still has a line the result lacks, +# unless it is blank or a comment: replacing the file would delete it. keep_deny_entries() { awk ' function indent(line) { return match(line, /[^ ]/) - 1 } @@ -132,6 +141,11 @@ keep_deny_entries() { ' "$2" "$1" > "$1.merged" || die "the fetched $2 has no deny list in its test-support rule" mv "$1.merged" "$1" + own="$(local_only_lines "$1" "$2")" + if [ -n "$own" ]; then + die "$2 has lines the canonical file lacks; add each to the canonical file to keep it, or delete it: +$own" + fi } main() { diff --git a/test/update-policy.sh b/test/update-policy.sh index 489eb57..3573319 100755 --- a/test/update-policy.sh +++ b/test/update-policy.sh @@ -21,8 +21,10 @@ write_stub_curl() { cat > "$dir/bin/curl" << 'EOF' #!/bin/sh previous="" +fail_flag="" for argument in "$@"; do [ "$previous" = "--output" ] && output="$argument" + [ "$argument" = "--fail" ] && fail_flag=yes previous="$argument" done url="$previous" @@ -30,7 +32,9 @@ base="https://git.eeqj.de/sneak/prompts/raw/commit/$HASH/" path="${url#"$base"}" source="$(dirname "$0")/../canonical/$path" if [ "$path" = "$url" ] || [ ! -f "$source" ]; then - exit 22 + [ -n "$fail_flag" ] && exit 22 + echo "404 page not found" > "$output" + exit 0 fi cp "$source" "$output" EOF @@ -322,6 +326,8 @@ test_bad_commit_hash() { expect_failure expect_nothing_written done + # The last hash has the right form, so it is the one that reaches curl. + expect_output "cannot fetch" } test_push_failure() { @@ -420,6 +426,24 @@ EOF expect_nothing_written } +test_own_golangci_setting_stops() { + start_scenario "a .golangci.yml setting the canonical file lacks stops" + cat >> "$dir/repo/.golangci.yml" << 'EOF' + # A comment of our own. + forbidigo: + forbid: + - pattern: model.Operator +EOF + commit_and_push_fixture .golangci.yml .prettierrc + run_update_policy "$HASH" + expect_failure + expect_output ".golangci.yml has lines" + expect_output "forbidigo:" + expect_output "- pattern: model.Operator" + expect_output_without "A comment of our own." + expect_nothing_written +} + test_source_repo_stops() { start_scenario "the repo the policy files come from stops" printf '#!/bin/sh\necho prompts\n' > "$dir/repo/script/projectname" @@ -484,6 +508,7 @@ main() { test_uncommitted_change_stops test_gitignore_lacks_canonical_last_line test_fetched_golangci_without_deny_list + test_own_golangci_setting_stops test_source_repo_stops test_staged_file_stays_out_of_commit test_short_commit_hash_refused