Skip to content

Commit 70185f1

Browse files
authored
feat(job): Support strategy (#45)
* chore: Implement matrixJSON * chore: Implement strategyJSON * chore: Export types * chore: Install node@22 * feat(job): Support strategy
1 parent 1b02a90 commit 70185f1

File tree

10 files changed

+137
-1
lines changed

10 files changed

+137
-1
lines changed

lib/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
export * from "ghats/../.ghats/action.js";
22
export * from "./package/concurrency";
33
export * from "./package/defaults";
4+
export * from "./package/env";
5+
export * from "./package/environment";
46
export * from "./package/expression";
57
export * from "./package/job";
8+
export * from "./package/matrix";
69
export * from "./package/on";
710
export * from "./package/permissions";
811
export * from "./package/shell";
912
export * from "./package/step";
13+
export * from "./package/strategy";
1014
export * from "./package/workflow";

lib/internal/matrix.spec.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { describe, expect, test } from "bun:test";
2+
import type { Matrix } from "../package/matrix";
3+
import { matrixJSON } from "./matrix";
4+
5+
describe("matrixJSON", () => {
6+
test.each<[Matrix, ReturnType<typeof matrixJSON>]>([
7+
["${{ foo }}", "${{ foo }}"],
8+
[
9+
{ foo: "${{ foo }}", bar: "${{ bar }}" },
10+
{ foo: "${{ foo }}", bar: "${{ bar }}" },
11+
],
12+
[
13+
{ foo: [1, 2, 3], bar: [4, "5", true, false, "${{ bar }}"] },
14+
{ foo: [1, 2, 3], bar: [4, "5", true, false, "${{ bar }}"] },
15+
],
16+
17+
[{ include: "${{ foo }}" }, { include: "${{ foo }}" }],
18+
[
19+
{ include: [{ foo: "${{ foo }}", bar: "${{ bar }}" }] },
20+
{ include: [{ foo: "${{ foo }}", bar: "${{ bar }}" }] },
21+
],
22+
[
23+
{
24+
include: [{ foo: [1, 2, 3], bar: [4, "5", true, false, "${{ bar }}"] }],
25+
},
26+
{
27+
include: [{ foo: [1, 2, 3], bar: [4, "5", true, false, "${{ bar }}"] }],
28+
},
29+
],
30+
[
31+
{
32+
exclude: [{ foo: [1, 2, 3], bar: [4, "5", true, false, "${{ bar }}"] }],
33+
},
34+
{
35+
exclude: [{ foo: [1, 2, 3], bar: [4, "5", true, false, "${{ bar }}"] }],
36+
},
37+
],
38+
])("matrixJSON(%j) -> %j", (matrix, expected) => {
39+
expect(matrixJSON(matrix)).toEqual(expected);
40+
});
41+
});

lib/internal/matrix.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import type { Matrix } from "../package/matrix";
2+
3+
export function matrixJSON(matrix: Matrix): Record<string, unknown> | string {
4+
return matrix;
5+
}

lib/internal/strategy.spec.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { describe, expect, test } from "bun:test";
2+
import type { Strategy } from "../package/strategy";
3+
import { strategyJSON } from "./strategy";
4+
5+
describe("strategyJSON", () => {
6+
test.each<[Strategy, Record<string, unknown>]>([
7+
[{ matrix: { foo: ["bar", "baz"] } }, { matrix: { foo: ["bar", "baz"] } }],
8+
[
9+
{ matrix: { foo: ["bar", "baz"] }, failFast: true },
10+
{ matrix: { foo: ["bar", "baz"] }, "fail-fast": true },
11+
],
12+
[
13+
{ matrix: { foo: ["bar", "baz"] }, maxParallel: 10 },
14+
{ matrix: { foo: ["bar", "baz"] }, "max-parallel": 10 },
15+
],
16+
[
17+
{
18+
matrix: { foo: ["bar", "baz"] },
19+
failFast: true,
20+
maxParallel: 10,
21+
},
22+
{
23+
matrix: { foo: ["bar", "baz"] },
24+
"fail-fast": true,
25+
"max-parallel": 10,
26+
},
27+
],
28+
])("strategyJSON(%j) -> %j", (strategy, expected) => {
29+
expect(strategyJSON(strategy)).toEqual(expected);
30+
});
31+
});

lib/internal/strategy.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { Strategy } from "../package/strategy";
2+
import { matrixJSON } from "./matrix";
3+
4+
export function strategyJSON(strategy: Strategy): Record<string, unknown> {
5+
return {
6+
matrix: matrixJSON(strategy.matrix),
7+
...(strategy.failFast != null && { "fail-fast": strategy.failFast }),
8+
...(strategy.maxParallel != null && {
9+
"max-parallel": strategy.maxParallel,
10+
}),
11+
};
12+
}

lib/package/job.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,17 @@ describe("Job", () => {
141141
steps: [{ run: "echo 'Hello, world!'" }],
142142
},
143143
],
144+
[
145+
new Job("with-strategy", {
146+
runsOn: "ubuntu-latest",
147+
strategy: { matrix: { foo: ["bar", "baz"] } },
148+
}).run("echo 'Hello, world!'"),
149+
{
150+
"runs-on": "ubuntu-latest",
151+
strategy: { matrix: { foo: ["bar", "baz"] } },
152+
steps: [{ run: "echo 'Hello, world!'" }],
153+
},
154+
],
144155
[
145156
new Job("with-continue-on-error", {
146157
runsOn: "ubuntu-latest",

lib/package/job.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ import { envJSON } from "../internal/env";
44
import { environmentJSON } from "../internal/environment";
55
import { permissionsJSON } from "../internal/permissions";
66
import { stepJSON } from "../internal/step";
7+
import { strategyJSON } from "../internal/strategy";
78
import { type Concurrency } from "./concurrency";
89
import type { Defaults } from "./defaults";
910
import type { Env } from "./env";
1011
import type { Environment } from "./environment";
1112
import type { Expression } from "./expression";
1213
import { type Permissions } from "./permissions";
1314
import { type RunStep, type Step, type UsesStep } from "./step";
15+
import type { Strategy } from "./strategy";
1416

1517
export type JobConfig = {
1618
runsOn: string;
@@ -23,7 +25,7 @@ export type JobConfig = {
2325
concurrency?: Concurrency;
2426
env?: Env;
2527
defaults?: Defaults;
26-
// TODO: strategy
28+
strategy?: Strategy;
2729
continueOnError?: boolean | Expression;
2830
// TODO: container
2931
// TODO: services
@@ -102,6 +104,10 @@ export class Job {
102104
defaults: defaultsJSON(this._config.defaults),
103105
}),
104106

107+
...(this._config.strategy != null && {
108+
strategy: strategyJSON(this._config.strategy),
109+
}),
110+
105111
...(this._config.continueOnError != null && {
106112
"continue-on-error": this._config.continueOnError,
107113
}),

lib/package/matrix.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { Expression } from "./expression";
2+
3+
export type Matrix =
4+
| Expression
5+
| { [key: string]: Expression | Configuration[] }
6+
| {
7+
include?: Expression | { [key: string]: Expression | Configuration[] }[];
8+
exclude?: Expression | { [key: string]: Expression | Configuration[] }[];
9+
};
10+
11+
type Configuration =
12+
| string
13+
| number
14+
| boolean
15+
| {
16+
[key: string]: Configuration;
17+
}
18+
| Configuration[];

lib/package/strategy.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import type { Matrix } from "./matrix";
2+
3+
export type Strategy = {
4+
matrix: Matrix;
5+
failFast?: string | boolean;
6+
maxParallel?: string | number;
7+
};

mise.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
[tools]
22
bun = "1.2.8"
3+
node = "22.14.0"

0 commit comments

Comments
 (0)