update-policy: stop on a .golangci.yml line the canonical file lacks
check / check (push) Successful in 20s

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
This commit is contained in:
sneak committed 2026-11-09 09:03:40 +00:00
1 parent c103168d03
commit 97da381318
3 files changed
+49 -8

No files matched your search

+3 -1
View File
@@ -216,7 +216,9 @@ with your task.
entries in `.gitignore`, `.editorconfig` and `.dockerignore` go below the entries in `.gitignore`, `.editorconfig` and `.dockerignore` go below the
comment that ends each canonical file. An entry above that comment which comment that ends each canonical file. An entry above that comment which
the canonical file lacks makes the script stop before it writes anything, 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/` - [ ] README has an **Entrypoints** section documenting the `script/`
entrypoints and linking the standard entrypoints and linking the standard
- [ ] `script/lint` and `script/test` each run - [ ] `script/lint` and `script/test` each run
+20 -6
View File
@@ -13,7 +13,8 @@
# canonical file's last line. An entry above that line which the # canonical file's last line. An entry above that line which the
# canonical file lacks stops the script. # canonical file lacks stops the script.
# - .golangci.yml: the entries the repo added to the deny list of the # - .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 set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
@@ -56,6 +57,16 @@ local_path() {
fi fi
} }
# local_only_lines <fetched> <local> [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 <fetched> <local>: append to the fetched file # keep_lines_below_last <fetched> <local>: append to the fetched file
# whatever follows its last line in the local file. Stop if a line above # 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 # 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 if [ -z "$last" ] || [ -z "$number" ]; then
die "$2 lacks this line; add it and put the repo's own entries below it: $last" die "$2 lacks this line; add it and put the repo's own entries below it: $last"
fi fi
own="$(awk -v end="$number" ' own="$(local_only_lines "$1" "$2" "$number")"
NR == FNR { fetched[$0]; next }
FNR < end && !/^#|^[ \t]*$/ && !($0 in fetched)
' "$1" "$2")"
if [ -n "$own" ]; then 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: 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" $own"
@@ -80,7 +88,8 @@ $own"
# keep_deny_entries <fetched> <local>: add to the deny list of the # keep_deny_entries <fetched> <local>: add to the deny list of the
# test-support rule in the fetched file the entries only the local file # 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 # 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() { keep_deny_entries() {
awk ' awk '
function indent(line) { return match(line, /[^ ]/) - 1 } function indent(line) { return match(line, /[^ ]/) - 1 }
@@ -132,6 +141,11 @@ keep_deny_entries() {
' "$2" "$1" > "$1.merged" || ' "$2" "$1" > "$1.merged" ||
die "the fetched $2 has no deny list in its test-support rule" die "the fetched $2 has no deny list in its test-support rule"
mv "$1.merged" "$1" 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() { main() {
+26 -1
View File
@@ -21,8 +21,10 @@ write_stub_curl() {
cat > "$dir/bin/curl" << 'EOF' cat > "$dir/bin/curl" << 'EOF'
#!/bin/sh #!/bin/sh
previous="" previous=""
fail_flag=""
for argument in "$@"; do for argument in "$@"; do
[ "$previous" = "--output" ] && output="$argument" [ "$previous" = "--output" ] && output="$argument"
[ "$argument" = "--fail" ] && fail_flag=yes
previous="$argument" previous="$argument"
done done
url="$previous" url="$previous"
@@ -30,7 +32,9 @@ base="https://git.eeqj.de/sneak/prompts/raw/commit/$HASH/"
path="${url#"$base"}" path="${url#"$base"}"
source="$(dirname "$0")/../canonical/$path" source="$(dirname "$0")/../canonical/$path"
if [ "$path" = "$url" ] || [ ! -f "$source" ]; then if [ "$path" = "$url" ] || [ ! -f "$source" ]; then
exit 22 [ -n "$fail_flag" ] && exit 22
echo "404 page not found" > "$output"
exit 0
fi fi
cp "$source" "$output" cp "$source" "$output"
EOF EOF
@@ -322,6 +326,8 @@ test_bad_commit_hash() {
expect_failure expect_failure
expect_nothing_written expect_nothing_written
done done
# The last hash has the right form, so it is the one that reaches curl.
expect_output "cannot fetch"
} }
test_push_failure() { test_push_failure() {
@@ -420,6 +426,24 @@ EOF
expect_nothing_written 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() { test_source_repo_stops() {
start_scenario "the repo the policy files come from stops" start_scenario "the repo the policy files come from stops"
printf '#!/bin/sh\necho prompts\n' > "$dir/repo/script/projectname" printf '#!/bin/sh\necho prompts\n' > "$dir/repo/script/projectname"
@@ -484,6 +508,7 @@ main() {
test_uncommitted_change_stops test_uncommitted_change_stops
test_gitignore_lacks_canonical_last_line test_gitignore_lacks_canonical_last_line
test_fetched_golangci_without_deny_list test_fetched_golangci_without_deny_list
test_own_golangci_setting_stops
test_source_repo_stops test_source_repo_stops
test_staged_file_stays_out_of_commit test_staged_file_stays_out_of_commit
test_short_commit_hash_refused test_short_commit_hash_refused