Files
metabase/bin/merge-kondo-ratchets
Chris Truter e4471f76d3 Split kondo ratchet budgets into separate prod and test files (#83383)
* Split kondo ratchet budgets into separate prod and test files

Prod and test kondo suppressions shared one .clj-kondo/ratchets.edn budget per
linter, so a pile of test-code ignores could mask a prod-code regression (or
vice versa) inside the same number. Adds .clj-kondo/ratchets-test.edn, tracking
:ignore-counts for anything under a `test` directory, independent of the prod
file's budget. :config-counts (.clj-kondo/config.edn suppressions) stays
combined in the prod file -- config.edn's own scoping mixes test and prod
namespaces in several groups, so it can't be reliably split per suppression.

Updates every consumer: dev.kondo-ratchet's fix!/check, bin/merge-kondo-ratchets,
the backport and release-cut disable scripts, the shrink workflow, and
file-paths.yaml/.gitignore.

* Fix test-ratchets validation and exemption-suggestion bugs from roborev

fix!/check read the test ratchets file with *ratchets-file* rebound to
*test-ratchets-file*, but validated it after that binding ended, so an
unknown linter there was reported against the prod path instead. Validation
now runs inside the binding, and both now reject a nonempty :config-counts
on the test file instead of letting fix! silently drop it.

kondo-insert-ignores also only ever suggested adding a new linter's
:comment-exempt to the prod file, even when every unjustified occurrence
was test-only. It now checks prod and test occurrences against each file's
own exemptions independently and names whichever file(s) actually need it.

* Dedupe test-ratchets read+validate, simplify test-occurrence?

fix! and check each rebuilt the same read-validate-test-file sequence
inline; extracted into read-validated-test-ratchets. test-occurrence?
no longer builds a throwaway set just to check one membership.

* Note what splitting :config-counts later would actually cost

* Fix Eastwood reflection warning in new test helper

empty-test-ratchets-file! returned an untyped value, so .getPath on it
needed reflection at each call site. Hinting the return type as
java.io.File fixes it -- CI's changed-tests Eastwood run caught this.

* Move return type hint onto the arg vector

Clj-Kondo prefers the hint on the arg vector to the one on the fn name.

* Move shrink PR body file reading into dev.kondo-ratchet

The bb task only parses its arguments now; reading and combining the
ratchet files lives next to shrink-pr-body, with a test.

* Give the test ratchets file its own header and drop its :config-counts

The test file was rendered with the prod header, whose last lines point
readers at ratchets-test.edn and say :config-counts "stays here" -- both
wrong inside the test file. It also carried an empty :config-counts that
the check rejects whenever it's nonempty.

render-test writes the test file with its own header and no
:config-counts, and throws on a nonempty one rather than dropping it.
fix!, the normalization check, and the three-way merge (a new "test"
kind) all use it.
2026-10-01 19:26:37 +00:00

65 lines
2.0 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# Resolve and stage conflicts in either ratchet file.
# This script only reads index stages; Mage validates and merges the maps.
set -euo pipefail
# Find mage through this script's path: the cd below can land in a different repository.
bin_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
cd -- "$(git rev-parse --show-toplevel)"
ratchet_files=(
.clj-kondo/ratchets.edn
.clj-kondo/ratchets-test.edn
.clj-kondo/config/modules/ratchets.edn
)
conflicted_files=()
# One "<mode> <sha> <stage>\t<path>" line per unmerged stage: 1 = base, 2 = ours, 3 = theirs.
for ratchets_file in "${ratchet_files[@]}"; do
stages=$(git ls-files -u -- "$ratchets_file" | awk '{ print $3 }')
if [ -n "$stages" ]; then
conflicted_files+=("$ratchets_file")
if ! grep -qx -- 2 <<< "$stages" || ! grep -qx -- 3 <<< "$stages"; then
echo "$ratchets_file was deleted on one side and changed on the other; resolve it by hand" >&2
exit 1
fi
fi
done
if [ "${#conflicted_files[@]}" -eq 0 ]; then
echo "no ratchet file is conflicted" >&2
exit 1
fi
tmp_dir=$(mktemp -d)
trap 'rm -rf -- "$tmp_dir"' EXIT
for i in "${!conflicted_files[@]}"; do
ratchets_file=${conflicted_files[$i]}
stages=$(git ls-files -u -- "$ratchets_file" | awk '{ print $3 }')
git show ":2:$ratchets_file" > "$tmp_dir/ours-$i"
git show ":3:$ratchets_file" > "$tmp_dir/theirs-$i"
if grep -qx -- 1 <<< "$stages"; then
git show ":1:$ratchets_file" > "$tmp_dir/base-$i"
else
# Both sides added the file, so every policy is a one-sided change against an empty base.
printf '{}\n' > "$tmp_dir/base-$i"
fi
case $ratchets_file in
.clj-kondo/config/modules/ratchets.edn) kind=modules ;;
.clj-kondo/ratchets-test.edn) kind=test ;;
*) kind=kondo ;;
esac
"$bin_dir/mage" -ratchets-merge "$kind" \
"$tmp_dir/base-$i" \
"$tmp_dir/ours-$i" \
"$tmp_dir/theirs-$i" \
"$PWD/$ratchets_file"
done
git add -- "${conflicted_files[@]}"
printf 'staged merged %s\n' "${conflicted_files[@]}"