mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-01 20:29:00 +00:00
ci: a force-push runs everything — the classifier stops guessing a rewritten range (#347)
github.event.before dies with a force-push, and the merge-base fallback then guessed a diff range: on issue/333 it reported two review-doc files while the real diff touched custom_components/** — frontend and backend jobs silently skipped and the run stayed success, the exact #171/#207 class of silent pass that nearly hid a genuine backend regression from code review. The classifier now distinguishes the two fallback cases instead of merging them: a ZERO before is a genuinely new branch and keeps the merge-base range; a NON-ZERO before that no longer exists is a rewritten history, and the range is not provable — frontend/backend/integration all go true, with a loud note in the step summary. A force-push is rare and almost always follows a rebase, where the full run is what an honest signal costs. The three branches of the decision are pinned by a workflow-contract unit next to the existing performance-workflow contracts. Issue: #347 User-Visible: no
This commit is contained in:
@@ -165,10 +165,28 @@ jobs:
|
||||
zero=$(printf '%040d' 0)
|
||||
base="$BEFORE_SHA"
|
||||
if [ "$EVENT_NAME" = "pull_request" ]; then base="$BASE_SHA"; fi
|
||||
# #347: непустой before, которого больше не существует, — это
|
||||
# force-push (ребейз/аменд переписал историю ветки). Диапазон в
|
||||
# этом случае НЕ угадывается: merge-base после переписанной истории
|
||||
# уже выдавал «изменились только два doc-файла» при реальном диффе
|
||||
# в custom_components/**, и тяжёлые job тихо скипались, а общий
|
||||
# статус рана оставался success — ровно класс тихого пропуска
|
||||
# #171/#207. Force-push редок, полный прогон дешевле ложного
|
||||
# «зелёного».
|
||||
if [ -n "$base" ] && [ "$base" != "$zero" ] \
|
||||
&& ! git cat-file -e "$base" 2>/dev/null; then
|
||||
echo "force-push: before=$base переписан — полный прогон без классификации"
|
||||
{
|
||||
echo "### Классификация изменённых файлов"
|
||||
echo "\`before\` (=$base) переписан force-push'ем: диапазон недоказуем,"
|
||||
echo "все тяжёлые job запускаются без фильтра путей (#347)."
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
printf 'frontend=true\nbackend=true\nintegration=true\n' >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
# Новая ветка: before нулевой, диапазон считается от merge-base с dev,
|
||||
# иначе классифицировалась бы вся история.
|
||||
if [ -z "$base" ] || [ "$base" = "$zero" ] \
|
||||
|| ! git cat-file -e "$base" 2>/dev/null; then
|
||||
if [ -z "$base" ] || [ "$base" = "$zero" ]; then
|
||||
git fetch -q origin dev
|
||||
base=$(git merge-base origin/dev "$HEAD_SHA" || echo "$HEAD_SHA~1")
|
||||
fi
|
||||
|
||||
@@ -46,3 +46,26 @@ test('full performance is isolated to stable, scheduled and manual entry points'
|
||||
assert.ok(release.includes('if: ${{ !github.event.release.prerelease }}'));
|
||||
assert.ok(release.includes('--workflow=performance.yml --label="Полные бенчмарки производительности"'));
|
||||
});
|
||||
|
||||
test('#347: a rewritten before forces the full run instead of guessing the range', () => {
|
||||
// Force-push kills github.event.before; the merge-base fallback then
|
||||
// guessed a range that hid a real custom_components/** diff behind two doc
|
||||
// files, and the heavy jobs silently skipped while the run stayed green —
|
||||
// the #171/#207 class of silent pass. The contract: a non-zero before that
|
||||
// no longer exists switches classification to an unconditional full run
|
||||
// with a loud step-summary note, and the merge-base fallback remains ONLY
|
||||
// for the genuinely new branch (zero before).
|
||||
const workflow = readWorkflow('validate.yml');
|
||||
const classify = workflow.slice(
|
||||
workflow.indexOf('Классификация изменённых файлов'),
|
||||
workflow.indexOf('reuse:'),
|
||||
);
|
||||
assert.ok(
|
||||
/force-push[\s\S]*?frontend=true[\s\S]*?backend=true[\s\S]*?integration=true/.test(classify),
|
||||
'мёртвый before обязан включать полный прогон, не merge-base-угадывание');
|
||||
assert.ok(classify.includes('GITHUB_STEP_SUMMARY'),
|
||||
'пропуск классификации обязан быть громким в summary');
|
||||
const fallback = classify.slice(classify.indexOf('Новая ветка'));
|
||||
assert.ok(!fallback.includes('cat-file'),
|
||||
'merge-base-фолбэк остаётся только для нулевого before — без повторной проверки существования');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user