fix: judge the branch rule only by the branch's own commits

Check 2 compared the Issue trailers against whatever branch the working tree
happened to be on, over whatever range it was given. Those two are not the same
set. After a rebase the CI range widens — `before` points at a discarded commit,
the merge-base slides back, and commits that belong to dev arrive carrying other
issue numbers. Every one of them then looks like a violation.

Running the gate over real history from issue/89 with a dev range produced 26
false refusals out of 26 commits, which would have reddened Validate on the next
force-push of any task branch.

The rule now reads origin/dev..HEAD for its own verdict and leaves the event
range to the other checks. A commit that genuinely carries the wrong trailer for
its branch is still caught; the integration test covers both directions.

Issue: #105
User-Visible: no
This commit is contained in:
Matysh
2026-08-13 14:30:13 +03:00
parent 5aa8771dc3
commit 8cecaf2c5e
2 changed files with 53 additions and 2 deletions
+21 -2
View File
@@ -189,7 +189,13 @@ export function evaluateCommit(c) {
return out;
}
// 2. имя ветки issue/NN-slug соответствует трейлерам
// 2. имя ветки issue/NN-slug соответствует трейлерам.
//
// Судить можно только коммиты САМОЙ ветки. Диапазон, который приходит из события
// CI, шире: после ребейза `before` указывает на снесённый коммит, merge-base
// уезжает назад, и в диапазон попадают коммиты `dev` с чужими номерами issue —
// каждый из них выглядел бы нарушением. Проверено на реальной истории: сидя на
// issue/89 с диапазоном по dev, гейт дал 26 ложных отказов из 26 коммитов.
export function checkBranchRule(branch, commits) {
const m = (branch ?? '').match(/^issue\/(\d+)-/);
if (!m) return [];
@@ -397,7 +403,20 @@ function main(argv) {
const findings = [];
for (const c of commits) findings.push(...evaluateCommit(c));
findings.push(...checkBranchRule(branch, commits));
// Проверке 2 отдаются только коммиты самой ветки: origin/dev..HEAD, а не
// диапазон события. См. комментарий у checkBranchRule.
const ownCommits = /^issue\/\d+-/.test(branch)
? (() => {
const hasDev = spawnSync('git', ['-C', repo, 'rev-parse', '--verify', 'origin/dev'],
{ encoding: 'utf8' }).status === 0;
if (!hasDev) return commits;
return parseRecords(
git(['log', '--reverse', `--pretty=format:${LOG_FORMAT}`, 'origin/dev..HEAD'], repo),
);
})()
: commits;
findings.push(...checkBranchRule(branch, ownCommits));
// Метки читаются один раз и используются дважды: проверкой 8 и escalation
// проверки 3. Второй запрос по тому же issue — лишний сетевой вызов.