chore(ci): skip heavy validation jobs on draft pull requests

This commit is contained in:
t8y2
2026-10-10 13:57:46 +08:00
parent 2540c5211c
commit 8f418c59a5
3 changed files with 54 additions and 19 deletions
+11 -6
View File
@@ -11,6 +11,11 @@ export function gateFailures(needs, mode) {
const routedJobs = { frontend: "frontend", packages: "packages", "github-scripts": "github_scripts",
"windows-standard-check": "windows_win7_bundle", "windows-win7-bundle": "windows_win7_bundle",
"duckdb-windows-driver": "duckdb_windows", jdbc: "jdbc", "offline-jdbc-release": "offline_jdbc", "nix-packaging": "nix" };
// Draft PRs intentionally skip the heavy validation jobs; the gate may only
// demand them once ready_for_review re-triggers the workflow without draft.
const draft = needs.changes.outputs.draft === "true";
const draftSkippable = new Set(["rust-test", "frontend-test", "agent-java", "agent-go", "agent-rust", "agent-integration",
"packages", "windows-standard-check", "windows-win7-bundle", "duckdb-windows-driver", "jdbc", "offline-jdbc-release", "nix-packaging"]);
if (mode === "all" && !Object.values(routedJobs).every((output) => ["true", "false"].includes(needs.changes.outputs[output]))) {
return ["missing or invalid job selection outputs"];
}
@@ -18,18 +23,18 @@ export function gateFailures(needs, mode) {
return ["missing or invalid frontend selection output"];
}
const expected = mode === "rust" ? {
"fast-checks": plan.fast, "rust-fmt-clippy": plan.rust, "rust-test": plan.rust,
"fast-checks": plan.fast, "rust-fmt-clippy": plan.rust, "rust-test": plan.rust && !draft,
} : mode === "agents" ? {
"fast-checks": plan.fast, "agent-checks": plan.agents, "agent-java": plan.agent_java, "agent-go": plan.agent_go_changed,
"agent-rust": plan.agent_rust_changed, "agent-integration": plan.agent_integration_changed,
"fast-checks": plan.fast, "agent-checks": plan.agents, "agent-java": plan.agent_java && !draft, "agent-go": plan.agent_go_changed && !draft,
"agent-rust": plan.agent_rust_changed && !draft, "agent-integration": plan.agent_integration_changed && !draft,
} : mode === "frontend" ? {
"frontend-checks": needs.changes.outputs.frontend === "true",
"frontend-typecheck": needs.changes.outputs.frontend === "true",
"frontend-test": needs.changes.outputs.frontend === "true",
"frontend-test": needs.changes.outputs.frontend === "true" && !draft,
} : mode === "all" ? {
rust: true, agents: true, "fast-checks": plan.fast,
...Object.fromEntries(Object.entries(routedJobs)
.map(([job, output]) => [job, needs.changes.outputs[output] === "true"])),
.map(([job, output]) => [job, needs.changes.outputs[output] === "true" && !(draft && draftSkippable.has(job))])),
} : null;
if (!expected) return [`unknown gate: ${mode}`];
return Object.entries(expected).flatMap(([job, required]) => {
@@ -43,5 +48,5 @@ if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.ar
if (failures.length) {
console.error(failures.join("\n"));
process.exitCode = 1;
} else console.log("All selected CI jobs succeeded; only unselected jobs may be skipped.");
} else console.log("All selected CI jobs succeeded; only unselected or draft-skipped jobs may be skipped.");
}
+24
View File
@@ -338,6 +338,30 @@ test("the frontend gate checks every selected frontend job", () => {
assert.deepEqual(gateFailures(needs, "frontend"), []);
});
test("draft runs may skip heavy validation jobs without failing gates", () => {
const needs = results(["Cargo.lock"]);
needs.changes.outputs.draft = "true";
for (const job of ["rust-test", "agent-java", "agent-go", "agent-rust", "agent-integration"]) {
needs[job] = { result: "skipped" };
}
assert.deepEqual(gateFailures(needs, "rust"), []);
assert.deepEqual(gateFailures(needs, "agents"), []);
needs.changes.outputs.frontend = "true";
needs["frontend-checks"] = { result: "success" };
needs["frontend-typecheck"] = { result: "success" };
needs["frontend-test"] = { result: "skipped" };
assert.deepEqual(gateFailures(needs, "frontend"), []);
// Draft only relaxes the skippable set: a real failure is still a failure,
// and jobs the draft policy keeps (clippy, fast-checks) stay required.
needs["frontend-test"].result = "failure";
assert.ok(gateFailures(needs, "frontend").length);
needs["rust-fmt-clippy"].result = "skipped";
assert.ok(gateFailures(needs, "rust").length);
// Without the draft output the heavy jobs are required again.
delete needs.changes.outputs.draft;
assert.ok(gateFailures(needs, "rust").length);
});
test("git diff routing includes both sides of renames, deleted files, and unusual filenames", () => {
const directory = mkdtempSync(path.join(tmpdir(), "dbx-ci-plan-"));
const git = (...args) => execFileSync("git", args, { cwd: directory, encoding: "utf8", stdio: "pipe" }).trim();
+19 -13
View File
@@ -5,6 +5,9 @@ on:
branches: [ main ]
pull_request:
branches: [ main ]
# ready_for_review is required: heavy jobs are skipped while a PR is a
# draft, so flipping to ready must re-trigger the full CI.
types: [opened, synchronize, reopened, ready_for_review]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -92,7 +95,7 @@ jobs:
frontend-test:
needs: changes
if: needs.changes.outputs.frontend == 'true'
if: needs.changes.outputs.frontend == 'true' && needs.changes.outputs.draft != 'true'
runs-on: ubuntu-24.04
env:
NPM_CONFIG_LOGLEVEL: error
@@ -164,7 +167,7 @@ jobs:
packages:
needs: changes
if: needs.changes.outputs.packages == 'true'
if: needs.changes.outputs.packages == 'true' && needs.changes.outputs.draft != 'true'
runs-on: ubuntu-24.04
env:
# Unsupported-platform package warnings are expected while validating cross-platform package metadata.
@@ -287,7 +290,7 @@ jobs:
windows-standard-check:
needs: changes
if: needs.changes.outputs.windows_win7_bundle == 'true'
if: needs.changes.outputs.windows_win7_bundle == 'true' && needs.changes.outputs.draft != 'true'
runs-on: windows-2022
timeout-minutes: 45
env:
@@ -316,7 +319,7 @@ jobs:
windows-win7-bundle:
needs: changes
if: needs.changes.outputs.windows_win7_bundle == 'true'
if: needs.changes.outputs.windows_win7_bundle == 'true' && needs.changes.outputs.draft != 'true'
runs-on: windows-2022
timeout-minutes: 120
env:
@@ -706,7 +709,7 @@ jobs:
duckdb-windows-driver:
needs: changes
if: needs.changes.outputs.duckdb_windows == 'true'
if: needs.changes.outputs.duckdb_windows == 'true' && needs.changes.outputs.draft != 'true'
runs-on: windows-2022
timeout-minutes: 60
env:
@@ -855,7 +858,7 @@ jobs:
needs:
- changes
- fast-checks
if: needs.changes.outputs.rust == 'true'
if: needs.changes.outputs.rust == 'true' && needs.changes.outputs.draft != 'true'
runs-on: ubuntu-24.04
env:
# sccache cannot reuse Cargo incremental artifacts, so avoid generating them in CI.
@@ -994,7 +997,7 @@ jobs:
jdbc:
needs: changes
if: needs.changes.outputs.jdbc == 'true'
if: needs.changes.outputs.jdbc == 'true' && needs.changes.outputs.draft != 'true'
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
@@ -1022,7 +1025,7 @@ jobs:
offline-jdbc-release:
needs: changes
if: needs.changes.outputs.offline_jdbc == 'true'
if: needs.changes.outputs.offline_jdbc == 'true' && needs.changes.outputs.draft != 'true'
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
@@ -1062,7 +1065,7 @@ jobs:
nix-packaging:
needs: changes
if: needs.changes.outputs.nix == 'true'
if: needs.changes.outputs.nix == 'true' && needs.changes.outputs.draft != 'true'
runs-on: ubuntu-24.04
continue-on-error: true
steps:
@@ -1102,6 +1105,9 @@ jobs:
agent_rust_changed: ${{ steps.plan.outputs.agent_rust_changed }}
agent_integration_changed: ${{ steps.plan.outputs.agent_integration_changed }}
plan: ${{ steps.plan.outputs.plan }}
# True only for pull_request events on draft PRs; heavy jobs skip and
# ci-gate.mjs must not demand them until ready_for_review re-triggers.
draft: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == true }}
steps:
- uses: actions/checkout@v7
with:
@@ -1332,7 +1338,7 @@ jobs:
run: python3 scripts/validate_agents.py
agent-java:
needs: [changes, fast-checks, agent-checks]
if: needs.changes.outputs.agent_java == 'true'
if: needs.changes.outputs.agent_java == 'true' && needs.changes.outputs.draft != 'true'
runs-on: ubuntu-24.04
defaults:
run:
@@ -1360,7 +1366,7 @@ jobs:
run: python3 scripts/validate_agent_jars.py
agent-rust:
needs: [changes, fast-checks, agent-checks]
if: needs.changes.outputs.agent_rust_changed == 'true'
if: needs.changes.outputs.agent_rust_changed == 'true' && needs.changes.outputs.draft != 'true'
runs-on: ubuntu-24.04
env:
# sccache cannot reuse Cargo incremental artifacts, so avoid generating them in CI.
@@ -1472,7 +1478,7 @@ jobs:
matrix: ${{ fromJSON(needs.changes.outputs.agent_rust) }}
agent-go:
needs: [changes, fast-checks, agent-checks]
if: needs.changes.outputs.agent_go_changed == 'true'
if: needs.changes.outputs.agent_go_changed == 'true' && needs.changes.outputs.draft != 'true'
runs-on: ubuntu-24.04
defaults:
run:
@@ -1496,7 +1502,7 @@ jobs:
matrix: ${{ fromJSON(needs.changes.outputs.agent_go) }}
agent-integration:
needs: [changes, fast-checks, agent-checks]
if: needs.changes.outputs.agent_integration_changed == 'true'
if: needs.changes.outputs.agent_integration_changed == 'true' && needs.changes.outputs.draft != 'true'
runs-on: ubuntu-24.04
defaults:
run: