A line an earlier canonical commit held counted as the repo's own, so the script stopped on the outdated lines a re-vendor exists to replace. It now clones prompts and also treats every line removed from the file in its history as canonical. The .golangci.yml stop message no longer tells anyone to delete a line. The tests use a local git repository in place of prompts and gain one scenario each for .golangci.yml and .gitignore. Model: opus-5-5
This commit is contained in:
1 parent
97da381318
commit
44e8a601aa
3 files changed
+87
-31
No files matched your search
@@ -215,10 +215,11 @@ with your task.
|
|||||||
`make update-policy` shims to it. Before its first use, the repo's own
|
`make update-policy` shims to it. Before its first use, the repo's own
|
||||||
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 has never held makes the script stop before it writes
|
||||||
naming the file and the entry. It stops the same way on a line in
|
anything, naming the file and the entry. It stops the same way on a line
|
||||||
`.golangci.yml` that the canonical file lacks, apart from comments and the
|
in `.golangci.yml` that the canonical file has never held, apart from
|
||||||
repo's entries in the `deny` list of the `test-support` rule.
|
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
|
||||||
|
|||||||
+21
-14
@@ -11,10 +11,10 @@
|
|||||||
# merged. A repo's own entries are kept:
|
# merged. A repo's own entries are kept:
|
||||||
# - .gitignore, .editorconfig, .dockerignore: the lines below the
|
# - .gitignore, .editorconfig, .dockerignore: the lines below the
|
||||||
# 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 has never held 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. Any other line the canonical file lacks stops
|
# test-support rule. Any other line the canonical file has never
|
||||||
# the script, unless it is blank or a comment.
|
# held 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)"
|
||||||
@@ -58,18 +58,19 @@ local_path() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# local_only_lines <fetched> <local> [end]: print each line of the local
|
# local_only_lines <fetched> <local> [end]: print each line of the local
|
||||||
# file, above line end if given, that the fetched file lacks. Blank
|
# file, above line end if given, that the canonical file has never held:
|
||||||
# lines and comments do not count.
|
# not in the fetched file or in <fetched>.former, the lines earlier
|
||||||
|
# commits removed from it. Blank lines and comments do not count.
|
||||||
local_only_lines() {
|
local_only_lines() {
|
||||||
awk -v end="${3:-}" '
|
cat "$1" "$1.former" | awk -v end="${3:-}" '
|
||||||
NR == FNR { fetched[$0]; next }
|
NR == FNR { held[$0]; next }
|
||||||
(end == "" || FNR < end) && !/^[ \t]*(#|$)/ && !($0 in fetched)
|
(end == "" || FNR < end) && !/^[ \t]*(#|$)/ && !($0 in held)
|
||||||
' "$1" "$2"
|
' - "$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 the canonical
|
||||||
# that one is missing from the fetched file, unless it is blank or a
|
# file has never held a line above that one, unless it is blank or a
|
||||||
# comment: replacing the file would delete it.
|
# comment: replacing the file would delete it.
|
||||||
keep_lines_below_last() {
|
keep_lines_below_last() {
|
||||||
last="$(tail -n 1 "$1")"
|
last="$(tail -n 1 "$1")"
|
||||||
@@ -88,8 +89,9 @@ $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. Stop if the local file still has a line the result lacks,
|
# above it. Stop if the local file still has a line that neither the
|
||||||
# unless it is blank or a comment: replacing the file would delete it.
|
# result nor the canonical file has ever held, 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 }
|
||||||
@@ -143,7 +145,7 @@ keep_deny_entries() {
|
|||||||
mv "$1.merged" "$1"
|
mv "$1.merged" "$1"
|
||||||
own="$(local_only_lines "$1" "$2")"
|
own="$(local_only_lines "$1" "$2")"
|
||||||
if [ -n "$own" ]; then
|
if [ -n "$own" ]; then
|
||||||
die "$2 has lines the canonical file lacks; add each to the canonical file to keep it, or delete it:
|
die "$2 has lines the canonical file has never held; only the deny list of the test-support rule may differ from canonical:
|
||||||
$own"
|
$own"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -169,6 +171,9 @@ main() {
|
|||||||
tmp="$(mktemp -d)"
|
tmp="$(mktemp -d)"
|
||||||
trap 'rm -rf "$tmp"' EXIT
|
trap 'rm -rf "$tmp"' EXIT
|
||||||
|
|
||||||
|
git clone --quiet --bare "$PROMPTS_URL.git" "$tmp/prompts.git" ||
|
||||||
|
die "cannot clone $PROMPTS_URL.git"
|
||||||
|
|
||||||
carried=""
|
carried=""
|
||||||
for file in $VENDORED_FILES; do
|
for file in $VENDORED_FILES; do
|
||||||
path="$(local_path "$file")"
|
path="$(local_path "$file")"
|
||||||
@@ -181,6 +186,8 @@ main() {
|
|||||||
--output "$tmp/$path" \
|
--output "$tmp/$path" \
|
||||||
"$PROMPTS_URL/raw/commit/$commit/$file" ||
|
"$PROMPTS_URL/raw/commit/$commit/$file" ||
|
||||||
die "cannot fetch $file at $commit"
|
die "cannot fetch $file at $commit"
|
||||||
|
git -C "$tmp/prompts.git" log -p --format= "$commit" -- "$file" |
|
||||||
|
sed -n 's/^-//p' > "$tmp/$path.former"
|
||||||
carried="$carried $path"
|
carried="$carried $path"
|
||||||
done
|
done
|
||||||
[ -n "$carried" ] || die "this repo carries none of the vendored files"
|
[ -n "$carried" ] || die "this repo carries none of the vendored files"
|
||||||
|
|||||||
+61
-13
@@ -1,8 +1,9 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# test/update-policy.sh: test script/update-policy on throwaway repos.
|
# test/update-policy.sh: test script/update-policy on throwaway repos.
|
||||||
# Each scenario gets one temp directory holding a repo, its local bare
|
# Each scenario gets one temp directory holding a repo, its local bare
|
||||||
# origin, the canonical files and a stub curl that serves them, so
|
# origin, a local git repository of the canonical files in place of
|
||||||
# nothing touches the network.
|
# prompts, and a stub curl that serves them, so nothing touches the
|
||||||
|
# network.
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
UPDATE_POLICY="$(cd "$(dirname "$0")/.." && pwd -P)/script/update-policy"
|
UPDATE_POLICY="$(cd "$(dirname "$0")/.." && pwd -P)/script/update-policy"
|
||||||
@@ -82,6 +83,15 @@ EOF
|
|||||||
echo "new api policy" > "$dir/canonical/prompts/API_POLICIES.md"
|
echo "new api policy" > "$dir/canonical/prompts/API_POLICIES.md"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# commit_canonical: commit the canonical files as they stand. The stub
|
||||||
|
# curl serves only the newest commit; every other commit gets a 404.
|
||||||
|
commit_canonical() {
|
||||||
|
git -C "$dir/canonical" add .gitignore .dockerignore .editorconfig \
|
||||||
|
.golangci.yml .prettierrc prompts
|
||||||
|
git -C "$dir/canonical" commit -q -m "Canonical"
|
||||||
|
HASH="$(git -C "$dir/canonical" rev-parse HEAD)"
|
||||||
|
}
|
||||||
|
|
||||||
# write_outdated_files: this repo's files, one canonical version behind,
|
# write_outdated_files: this repo's files, one canonical version behind,
|
||||||
# with the repo's own entries in the places the script keeps them. The
|
# with the repo's own entries in the places the script keeps them. The
|
||||||
# comment above the closing comment in .gitignore is replaced, not kept.
|
# comment above the closing comment in .gitignore is replaced, not kept.
|
||||||
@@ -131,18 +141,26 @@ EOF
|
|||||||
# the outdated files, not yet committed, and an empty origin.
|
# the outdated files, not yet committed, and an empty origin.
|
||||||
start_scenario() {
|
start_scenario() {
|
||||||
scenario="$1"
|
scenario="$1"
|
||||||
# The one commit the stub curl serves; every other commit gets a 404.
|
|
||||||
export HASH=1111111111111111111111111111111111111111
|
|
||||||
rm -rf "$dir"
|
rm -rf "$dir"
|
||||||
dir="$(mktemp -d)"
|
dir="$(mktemp -d)"
|
||||||
: > "$dir/output"
|
: > "$dir/output"
|
||||||
write_stub_curl
|
write_stub_curl
|
||||||
write_canonical_files
|
write_canonical_files
|
||||||
|
|
||||||
|
# git clone reads no repo's own config, so the setting that points
|
||||||
|
# git at the local canonical repository has to be in this file.
|
||||||
|
export GIT_CONFIG_GLOBAL="$dir/gitconfig"
|
||||||
|
git config --global user.name "Test"
|
||||||
|
git config --global user.email "test@example.com"
|
||||||
|
git config --global "url.$dir/canonical.insteadOf" \
|
||||||
|
"https://git.eeqj.de/sneak/prompts.git"
|
||||||
|
|
||||||
|
git init -q -b main "$dir/canonical"
|
||||||
|
export HASH
|
||||||
|
commit_canonical
|
||||||
|
|
||||||
git init -q --bare -b main "$dir/origin.git"
|
git init -q --bare -b main "$dir/origin.git"
|
||||||
git init -q -b main "$dir/repo"
|
git init -q -b main "$dir/repo"
|
||||||
git -C "$dir/repo" config user.name "Test"
|
|
||||||
git -C "$dir/repo" config user.email "test@example.com"
|
|
||||||
git -C "$dir/repo" remote add origin "$dir/origin.git"
|
git -C "$dir/repo" remote add origin "$dir/origin.git"
|
||||||
|
|
||||||
mkdir "$dir/repo/script"
|
mkdir "$dir/repo/script"
|
||||||
@@ -476,16 +494,11 @@ test_short_commit_hash_refused() {
|
|||||||
expect_nothing_written
|
expect_nothing_written
|
||||||
}
|
}
|
||||||
|
|
||||||
# git is pointed at a local repository in place of the prompts remote,
|
# git asks the local canonical repository for the head of main, and the
|
||||||
# and the stub curl serves the head of that repository's main.
|
# stub curl serves only that commit.
|
||||||
test_no_hash_uses_head_of_main() {
|
test_no_hash_uses_head_of_main() {
|
||||||
start_scenario "with no hash the script uses the head of main"
|
start_scenario "with no hash the script uses the head of main"
|
||||||
commit_and_push_fixture .prettierrc
|
commit_and_push_fixture .prettierrc
|
||||||
git init -q --bare -b main "$dir/prompts.git"
|
|
||||||
git -C "$dir/repo" push -q "$dir/prompts.git" HEAD:refs/heads/main
|
|
||||||
git -C "$dir/repo" config "url.$dir/prompts.git.insteadOf" \
|
|
||||||
"https://git.eeqj.de/sneak/prompts.git"
|
|
||||||
HASH="$before"
|
|
||||||
run_update_policy
|
run_update_policy
|
||||||
expect_success
|
expect_success
|
||||||
expect_file .prettierrc << 'EOF'
|
expect_file .prettierrc << 'EOF'
|
||||||
@@ -497,6 +510,39 @@ EOF
|
|||||||
fail "the commit was not pushed"
|
fail "the commit was not pushed"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# expect_former_canonical_line_replaced <file> <line>: an earlier
|
||||||
|
# canonical commit held the line and the newest does not. This repo's
|
||||||
|
# file still has it, and the script replaces it and pushes.
|
||||||
|
expect_former_canonical_line_replaced() {
|
||||||
|
cp "$dir/canonical/$1" "$dir/newest"
|
||||||
|
{ echo "$2"; cat "$dir/newest"; } > "$dir/canonical/$1"
|
||||||
|
commit_canonical
|
||||||
|
cp "$dir/newest" "$dir/canonical/$1"
|
||||||
|
commit_canonical
|
||||||
|
{ echo "$2"; cat "$dir/repo/$1"; } > "$dir/merged"
|
||||||
|
mv "$dir/merged" "$dir/repo/$1"
|
||||||
|
commit_and_push_fixture "$1" .prettierrc
|
||||||
|
|
||||||
|
run_update_policy "$HASH"
|
||||||
|
expect_success
|
||||||
|
if grep -q -F -x -e "$2" "$dir/repo/$1"; then
|
||||||
|
fail "$1 still has: $2"
|
||||||
|
fi
|
||||||
|
[ "$(head_of_repo)" != "$before" ] || fail "no commit was made"
|
||||||
|
[ "$(head_of_origin)" = "$(head_of_repo)" ] ||
|
||||||
|
fail "the commit was not pushed"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_former_canonical_golangci_line_replaced() {
|
||||||
|
start_scenario "a .golangci.yml line an earlier canonical commit held is replaced"
|
||||||
|
expect_former_canonical_line_replaced .golangci.yml "version: 1"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_former_canonical_gitignore_line_replaced() {
|
||||||
|
start_scenario "a .gitignore line above the closing comment that an earlier canonical commit held is replaced"
|
||||||
|
expect_former_canonical_line_replaced .gitignore "*.old"
|
||||||
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
test_own_entries_kept
|
test_own_entries_kept
|
||||||
test_files_not_carried_are_skipped
|
test_files_not_carried_are_skipped
|
||||||
@@ -513,6 +559,8 @@ main() {
|
|||||||
test_staged_file_stays_out_of_commit
|
test_staged_file_stays_out_of_commit
|
||||||
test_short_commit_hash_refused
|
test_short_commit_hash_refused
|
||||||
test_no_hash_uses_head_of_main
|
test_no_hash_uses_head_of_main
|
||||||
|
test_former_canonical_golangci_line_replaced
|
||||||
|
test_former_canonical_gitignore_line_replaced
|
||||||
echo "update-policy tests passed"
|
echo "update-policy tests passed"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user