mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-11 21:57:14 +03:00
cursor[bot] findings on #433: - Nightly schedule no longer enables the paid opt-in suites: a schedule event has no diff base, so the change-detection fallback flagged every file-triggered suite, which would have billed the skill-behavior, accept-cleanup, and deepseek LLM suites nightly. The plan now pins the schedule event to deterministic suites plus the full live-e2e matrix, with a regression test. - Dismissing the mount-error card no longer strands the session: while the bar is hidden in GENERATING the card is the only recovery surface, so dismiss now returns the state machine to PICKING (session and server truth survive for a later republish). This work was produced with AI assistance (Claude Code). Co-Authored-By: Claude Code <noreply@anthropic.com>
110 lines
3.8 KiB
JavaScript
110 lines
3.8 KiB
JavaScript
#!/usr/bin/env node
|
|
import fs from 'node:fs';
|
|
import { execFileSync } from 'node:child_process';
|
|
import { DEFAULT_SUITES, matchesSuiteTriggers } from './test-suites.mjs';
|
|
|
|
const eventName = process.env.GITHUB_EVENT_NAME || '';
|
|
const localNoChanges = !eventName && !process.env.CI_CHANGED_FILES;
|
|
// The nightly schedule exists for exactly one thing: the full live-e2e
|
|
// matrix. A schedule event has no diff base, so the change-detection path
|
|
// degenerates to "everything changed"; without this guard that would flip on
|
|
// every file-triggered opt-in suite, including the ones that bill LLM APIs
|
|
// (skill-behavior, accept-cleanup, deepseek), every single night.
|
|
const isSchedule = eventName === 'schedule';
|
|
const changedFiles = localNoChanges || isSchedule ? [] : getChangedFiles();
|
|
const forceDeterministic = localNoChanges || eventName === 'push' || eventName === 'workflow_dispatch';
|
|
const forceOptIn = eventName === 'workflow_dispatch';
|
|
|
|
const plan = isSchedule
|
|
? {
|
|
core: true,
|
|
detector: true,
|
|
live: true,
|
|
framework: true,
|
|
cli_remote_e2e: false,
|
|
live_e2e: true,
|
|
live_e2e_accept_cleanup: false,
|
|
skill_behavior: false,
|
|
live_svelte_adapter_deepseek: false,
|
|
}
|
|
: {
|
|
core: true,
|
|
detector: forceDeterministic || matchesSuiteTriggers('detector', changedFiles),
|
|
live: forceDeterministic || matchesSuiteTriggers('live', changedFiles),
|
|
framework: forceDeterministic || matchesSuiteTriggers('framework', changedFiles),
|
|
cli_remote_e2e: forceOptIn,
|
|
live_e2e: forceOptIn || matchesSuiteTriggers('live-e2e', changedFiles),
|
|
live_e2e_accept_cleanup: forceOptIn || matchesSuiteTriggers('live-e2e-accept-cleanup', changedFiles),
|
|
skill_behavior: forceOptIn || matchesSuiteTriggers('skill-behavior', changedFiles),
|
|
live_svelte_adapter_deepseek: forceOptIn || matchesSuiteTriggers('live-svelte-adapter-deepseek', changedFiles),
|
|
};
|
|
|
|
writeGithubOutputs(plan);
|
|
printSummary(plan, changedFiles);
|
|
|
|
function getChangedFiles() {
|
|
if (process.env.CI_CHANGED_FILES) {
|
|
return process.env.CI_CHANGED_FILES
|
|
.split(/\r?\n/)
|
|
.map((file) => file.trim())
|
|
.filter(Boolean);
|
|
}
|
|
|
|
const event = process.env.GITHUB_EVENT_NAME || '';
|
|
const sha = process.env.GITHUB_SHA || 'HEAD';
|
|
|
|
if (event === 'pull_request' && process.env.GITHUB_BASE_REF) {
|
|
const base = `origin/${process.env.GITHUB_BASE_REF}`;
|
|
return gitDiffNames(`${base}...${sha}`) || gitDiffNames(`${base}...HEAD`) || allChanged();
|
|
}
|
|
|
|
const before = process.env.GITHUB_EVENT_BEFORE;
|
|
if (before && !/^0+$/.test(before)) {
|
|
return gitDiffNames(`${before}..${sha}`) || allChanged();
|
|
}
|
|
|
|
return allChanged();
|
|
}
|
|
|
|
function allChanged() {
|
|
return git(['ls-files']).split(/\r?\n/).filter(Boolean);
|
|
}
|
|
|
|
function gitDiffNames(range) {
|
|
try {
|
|
return git(['diff', '--name-only', range]).split(/\r?\n/).filter(Boolean);
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function git(args) {
|
|
return execFileSync('git', args, { encoding: 'utf-8' });
|
|
}
|
|
|
|
function writeGithubOutputs(outputs) {
|
|
const outputPath = process.env.GITHUB_OUTPUT;
|
|
if (!outputPath) return;
|
|
const lines = [];
|
|
for (const [key, value] of Object.entries(outputs)) {
|
|
lines.push(`${key}=${value ? 'true' : 'false'}`);
|
|
}
|
|
fs.appendFileSync(outputPath, lines.join('\n') + '\n');
|
|
}
|
|
|
|
function printSummary(outputs, files) {
|
|
const deterministic = DEFAULT_SUITES.map((name) => `${name}=${outputs[name]}`).join(' ');
|
|
console.log(`Event: ${eventName || 'local'}`);
|
|
console.log(`Changed files: ${files.length}`);
|
|
console.log(`Deterministic suites: ${deterministic}`);
|
|
console.log(
|
|
[
|
|
`cli_remote_e2e=${outputs.cli_remote_e2e}`,
|
|
`live_e2e=${outputs.live_e2e}`,
|
|
`live_e2e_accept_cleanup=${outputs.live_e2e_accept_cleanup}`,
|
|
`skill_behavior=${outputs.skill_behavior}`,
|
|
`deepseek=${outputs.live_svelte_adapter_deepseek}`,
|
|
].join(' '),
|
|
);
|
|
}
|