Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/domain/drivers/driver_resolution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,20 @@ export interface ResolvedDriverConfig {

/**
* Resolves the effective driver and config using precedence:
* step > job > workflow > definition > "raw"
* cli > step > job > workflow > definition > "raw"
*
* The first non-undefined `driver` value wins. Its corresponding
* `driverConfig` is used as-is (no merging across levels).
*/
export function resolveDriverConfig(
cli?: DriverSource,
step?: DriverSource,
job?: DriverSource,
workflow?: DriverSource,
definition?: DriverSource,
): ResolvedDriverConfig {
const sources: (DriverSource | undefined)[] = [
cli,
step,
job,
workflow,
Expand Down
59 changes: 51 additions & 8 deletions src/domain/drivers/driver_resolution_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,35 +20,38 @@
import { assertEquals } from "@std/assert";
import { resolveDriverConfig } from "./driver_resolution.ts";

Deno.test("resolveDriverConfig - defaults to raw when no sources", () => {
Deno.test("resolveDriverConfig: defaults to raw when no sources", () => {
const result = resolveDriverConfig();
assertEquals(result.driver, "raw");
assertEquals(result.driverConfig, undefined);
});

Deno.test("resolveDriverConfig - defaults to raw when all sources undefined", () => {
Deno.test("resolveDriverConfig: defaults to raw when all sources undefined", () => {
const result = resolveDriverConfig(
undefined,
undefined,
undefined,
undefined,
undefined,
);
assertEquals(result.driver, "raw");
});

Deno.test("resolveDriverConfig - definition driver wins over default", () => {
Deno.test("resolveDriverConfig: definition driver wins over default", () => {
const result = resolveDriverConfig(
undefined,
undefined,
undefined,
undefined,
{ driver: "docker", driverConfig: { image: "node:18" } },
);
assertEquals(result.driver, "docker");
assertEquals(result.driverConfig, { image: "node:18" });
});

Deno.test("resolveDriverConfig - workflow driver wins over definition", () => {
Deno.test("resolveDriverConfig: workflow driver wins over definition", () => {
const result = resolveDriverConfig(
undefined,
undefined,
undefined,
{ driver: "docker", driverConfig: { image: "deno:latest" } },
Expand All @@ -58,8 +61,9 @@ Deno.test("resolveDriverConfig - workflow driver wins over definition", () => {
assertEquals(result.driverConfig, { image: "deno:latest" });
});

Deno.test("resolveDriverConfig - job driver wins over workflow", () => {
Deno.test("resolveDriverConfig: job driver wins over workflow", () => {
const result = resolveDriverConfig(
undefined,
undefined,
{ driver: "raw" },
{ driver: "docker" },
Expand All @@ -68,8 +72,9 @@ Deno.test("resolveDriverConfig - job driver wins over workflow", () => {
assertEquals(result.driver, "raw");
});

Deno.test("resolveDriverConfig - step driver wins over all", () => {
Deno.test("resolveDriverConfig: step driver wins over job", () => {
const result = resolveDriverConfig(
undefined,
{ driver: "docker", driverConfig: { image: "step-image" } },
{ driver: "raw" },
{ driver: "raw" },
Expand All @@ -79,8 +84,45 @@ Deno.test("resolveDriverConfig - step driver wins over all", () => {
assertEquals(result.driverConfig, { image: "step-image" });
});

Deno.test("resolveDriverConfig - skips sources without driver field", () => {
Deno.test("resolveDriverConfig: cli driver wins over all others", () => {
const result = resolveDriverConfig(
{ driver: "raw" },
{ driver: "docker", driverConfig: { image: "step-image" } },
{ driver: "docker", driverConfig: { image: "job-image" } },
{ driver: "docker", driverConfig: { image: "wf-image" } },
{ driver: "docker", driverConfig: { image: "def-image" } },
);
assertEquals(result.driver, "raw");
assertEquals(result.driverConfig, undefined);
});

Deno.test("resolveDriverConfig: cli driver config is used when cli wins", () => {
const result = resolveDriverConfig(
{ driver: "docker", driverConfig: { image: "cli-image" } },
{ driver: "raw" },
{ driver: "raw" },
{ driver: "raw" },
{ driver: "raw" },
);
assertEquals(result.driver, "docker");
assertEquals(result.driverConfig, { image: "cli-image" });
});

Deno.test("resolveDriverConfig: step wins when cli is undefined", () => {
const result = resolveDriverConfig(
undefined,
{ driver: "docker", driverConfig: { image: "step-image" } },
{ driver: "raw" },
{ driver: "raw" },
{ driver: "raw" },
);
assertEquals(result.driver, "docker");
assertEquals(result.driverConfig, { image: "step-image" });
});

Deno.test("resolveDriverConfig: skips sources without driver field", () => {
const result = resolveDriverConfig(
undefined,
{ driverConfig: { ignore: true } },
undefined,
{ driver: "docker" },
Expand All @@ -89,8 +131,9 @@ Deno.test("resolveDriverConfig - skips sources without driver field", () => {
assertEquals(result.driver, "docker");
});

Deno.test("resolveDriverConfig - uses driverConfig from winning level only", () => {
Deno.test("resolveDriverConfig: uses driverConfig from winning level only", () => {
const result = resolveDriverConfig(
undefined,
undefined,
{ driver: "docker", driverConfig: { timeout: 30 } },
{ driver: "raw", driverConfig: { verbose: true } },
Expand Down
11 changes: 7 additions & 4 deletions src/domain/workflows/execution_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ import { reportRegistry } from "../reports/report_registry.ts";
import type { MethodReportContext } from "../reports/report_context.ts";
import { modelRegistry } from "../models/model.ts";
import { getTracer, SpanStatusCode } from "../../infrastructure/tracing/mod.ts";
import { resolveDriverConfig } from "../drivers/driver_resolution.ts";
/**
* Context for step execution.
*/
Expand Down Expand Up @@ -1460,10 +1461,12 @@ export class WorkflowExecutionService {
workflowTags: options.workflowTags,
runtimeTags: options.runtimeTags,
secretRedactor: options.secretRedactor,
driver: step.driver ?? job.driver ?? workflow.driver ??
options.driver,
driverConfig: step.driverConfig ?? job.driverConfig ??
workflow.driverConfig,
...resolveDriverConfig(
{ driver: options.driver },
{ driver: step.driver, driverConfig: step.driverConfig },
{ driver: job.driver, driverConfig: job.driverConfig },
{ driver: workflow.driver, driverConfig: workflow.driverConfig },
),
emitEvent: push,
reportFilterOptions: options.reportFilterOptions,
};
Expand Down
Loading