Skip to content

Commit ae061f8

Browse files
committed
feat(workflow-result): enable use of a custom runner for the workflow-result job
1 parent 643ff69 commit ae061f8

8 files changed

Lines changed: 81 additions & 38 deletions

File tree

src/job/scaffolder.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
export default function ({steps, strategy, runner = 'ubuntu-latest'}) {
1+
export default function ({steps, strategy, needs, if: conditional, runner = 'ubuntu-latest'}) {
22
return {
33
'runs-on': runner,
44
...strategy && {strategy},
5+
...needs && {needs},
6+
...conditional && {if: conditional},
57
steps
68
};
79
}

src/job/scaffolder.test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,16 @@ describe('job scaffolder', () => {
2121

2222
expect(scaffoldJob({steps, strategy})).toEqual({'runs-on': 'ubuntu-latest', strategy, steps});
2323
});
24+
25+
it('should define the `needs` dependencies if any are provided', () => {
26+
const dependencies = any.listOf(any.word);
27+
28+
expect(scaffoldJob({steps, needs: dependencies})).toEqual({'runs-on': 'ubuntu-latest', needs: dependencies, steps});
29+
});
30+
31+
it('should define the `if` conditional if provided', () => {
32+
const conditional = any.string();
33+
34+
expect(scaffoldJob({steps, if: conditional})).toEqual({'runs-on': 'ubuntu-latest', if: conditional, steps});
35+
});
2436
});

src/jobs/missing-job-inserter.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export default function ({versions: matrixOfNodeVersions, jobs, runner}) {
1414
return [['verify-matrix', matrixVerification({versions: matrixOfNodeVersions, runner})], ...jobs];
1515
}
1616

17-
if (!resultJobAlreadyExists(jobs)) return [...jobs, ['workflow-result', scaffoldWorkflowResultJob()]];
17+
if (!resultJobAlreadyExists(jobs)) return [...jobs, ['workflow-result', scaffoldWorkflowResultJob({runner})]];
1818

1919
return jobs;
2020
}

src/jobs/missing-job-inserter.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ describe('missing job inserter', () => {
6969
it('should insert a `workflow-result` job when one doesnt already exist', async () => {
7070
const jobs = any.listOf(() => ([any.word(), any.simpleObject()]));
7171
const resultJob = any.simpleObject();
72-
when(scaffoldWorkflowResultJob).calledWith().mockReturnValue(resultJob);
72+
when(scaffoldWorkflowResultJob).calledWith({runner}).mockReturnValue(resultJob);
7373

74-
expect(insertMissingJobs({jobs}))
74+
expect(insertMissingJobs({jobs, runner}))
7575
.toEqual([...jobs, ['workflow-result', resultJob]]);
7676
});
7777
});

src/jobs/workflow-result/scaffolder.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
export default function () {
2-
return {
3-
'runs-on': 'ubuntu-latest',
1+
import {scaffold as scaffoldJob} from '../../job/index.js';
2+
3+
export default function ({runner}) {
4+
return scaffoldJob({
5+
runner,
46
needs: ['verify'],
57
// eslint-disable-next-line no-template-curly-in-string
68
if: '${{ !cancelled() }}',
@@ -18,5 +20,5 @@ export default function () {
1820
run: 'exit 1'
1921
}
2022
]
21-
};
23+
});
2224
}
Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,38 @@
1-
import {it, expect, describe} from 'vitest';
1+
import {it, expect, describe, vi} from 'vitest';
2+
import {when} from 'jest-when';
3+
import any from '@travi/any';
24

5+
import {scaffold as scaffoldJob} from '../../job/index.js';
36
import scaffoldWorkflowResultJob from './scaffolder.js';
47

8+
vi.mock('../../job/index.js');
59
describe('workflow-result job scaffolder', () => {
610
it('should determine exit code based on previous job results', () => {
7-
expect(scaffoldWorkflowResultJob()).toEqual({
8-
'runs-on': 'ubuntu-latest',
9-
needs: ['verify'],
10-
// eslint-disable-next-line no-template-curly-in-string
11-
if: '${{ !cancelled() }}',
12-
steps: [
13-
{
14-
name: 'All matrix versions passed',
15-
// eslint-disable-next-line no-template-curly-in-string
16-
if: "${{ !(contains(needs.*.result, 'failure')) }}",
17-
run: 'exit 0'
18-
},
19-
{
20-
name: 'Some matrix version failed',
21-
// eslint-disable-next-line no-template-curly-in-string
22-
if: "${{ contains(needs.*.result, 'failure') }}",
23-
run: 'exit 1'
24-
}
25-
]
26-
});
11+
const runner = any.word();
12+
const job = any.simpleObject();
13+
when(scaffoldJob)
14+
.calledWith({
15+
runner,
16+
needs: ['verify'],
17+
// eslint-disable-next-line no-template-curly-in-string
18+
if: '${{ !cancelled() }}',
19+
steps: [
20+
{
21+
name: 'All matrix versions passed',
22+
// eslint-disable-next-line no-template-curly-in-string
23+
if: "${{ !(contains(needs.*.result, 'failure')) }}",
24+
run: 'exit 0'
25+
},
26+
{
27+
name: 'Some matrix version failed',
28+
// eslint-disable-next-line no-template-curly-in-string
29+
if: "${{ contains(needs.*.result, 'failure') }}",
30+
run: 'exit 1'
31+
}
32+
]
33+
})
34+
.mockReturnValue(job);
35+
36+
expect(scaffoldWorkflowResultJob({runner})).toEqual(job);
2737
});
2838
});

test/integration/features/lift/result.feature

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ Feature: Overall Workflow Result
1313
When the project is lifted
1414
Then the workflow-result job exists
1515
And the workflow-result job depends on "verify"
16+
And the workflow-result job uses "ubuntu-latest" as the runner
17+
18+
Scenario: custom runner
19+
Given a CI workflow exists
20+
And a "verify" job exists
21+
And the project prefers to use the "foo" runner
22+
When the project is lifted
23+
Then the workflow-result job uses "foo" as the runner
1624

1725
@wip
1826
Scenario: No existing result job, existing verify and verify-matrix

test/integration/features/step_definitions/ci-steps.js

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {Before, Given, Then} from '@cucumber/cucumber';
1212
import {assert} from 'chai';
1313
import any from '@travi/any';
1414

15+
const ciWorkflowName = 'node-ci';
16+
1517
Before(async function () {
1618
this.prTriggerConfig = any.simpleObject();
1719

@@ -23,7 +25,7 @@ Given('a CI workflow exists', async function () {
2325

2426
await writeWorkflowFile({
2527
projectRoot: this.projectRoot,
26-
name: 'node-ci',
28+
name: ciWorkflowName,
2729
config: {
2830
on: {
2931
push: {branches: this.existingBranches},
@@ -35,14 +37,14 @@ Given('a CI workflow exists', async function () {
3537
});
3638

3739
Given('a {string} job exists', async function (jobName) {
38-
const existingWorkflowContents = await loadWorkflowFile({projectRoot: this.projectRoot, name: 'node-ci'});
40+
const existingWorkflowContents = await loadWorkflowFile({projectRoot: this.projectRoot, name: ciWorkflowName});
3941
const job = any.simpleObject();
4042

4143
this.injectedJobs[jobName] = job;
4244

4345
await writeWorkflowFile({
4446
projectRoot: this.projectRoot,
45-
name: 'node-ci',
47+
name: ciWorkflowName,
4648
config: {
4749
...existingWorkflowContents,
4850
jobs: {
@@ -54,7 +56,7 @@ Given('a {string} job exists', async function (jobName) {
5456
});
5557

5658
Then('the ci config remains unchanged', async function () {
57-
const {on: triggers, jobs} = await loadWorkflowFile({projectRoot: this.projectRoot, name: 'node-ci'});
59+
const {on: triggers, jobs} = await loadWorkflowFile({projectRoot: this.projectRoot, name: ciWorkflowName});
5860

5961
assert.deepEqual(triggers.push.branches, this.existingBranches);
6062
assert.deepEqual(triggers.pull_request, this.prTriggerConfig);
@@ -65,7 +67,7 @@ Then('the ci config remains unchanged', async function () {
6567
});
6668

6769
Then('dependency caching is enabled', async function () {
68-
const {jobs} = await loadWorkflowFile({projectRoot: this.projectRoot, name: 'node-ci'});
70+
const {jobs} = await loadWorkflowFile({projectRoot: this.projectRoot, name: ciWorkflowName});
6971

7072
const setupNodeStep = jobs[this.existingJobName].steps.find(step => 'Setup node' === step.name);
7173
assert.equal(setupNodeStep.with.cache, 'npm');
@@ -78,7 +80,7 @@ Then('the verification workflow is created', async function () {
7880
env,
7981
permissions,
8082
jobs
81-
} = await loadWorkflowFile({projectRoot: this.projectRoot, name: 'node-ci'});
83+
} = await loadWorkflowFile({projectRoot: this.projectRoot, name: ciWorkflowName});
8284

8385
assert.equal(name, 'Node.js CI');
8486
assert.deepEqual(
@@ -102,19 +104,26 @@ Then('the verification workflow is created', async function () {
102104
});
103105

104106
Then('the workflow-result job exists', async function () {
105-
const {jobs} = await loadWorkflowFile({projectRoot: this.projectRoot, name: 'node-ci'});
107+
const {jobs} = await loadWorkflowFile({projectRoot: this.projectRoot, name: ciWorkflowName});
106108

107109
assert.include(Object.keys(jobs), 'workflow-result');
108110
});
109111

110112
Then('the {string} job is unchanged', async function (jobName) {
111-
const {jobs} = await loadWorkflowFile({projectRoot: this.projectRoot, name: 'node-ci'});
113+
const {jobs} = await loadWorkflowFile({projectRoot: this.projectRoot, name: ciWorkflowName});
112114

113115
assert.deepEqual(jobs[jobName], this.injectedJobs[jobName]);
114116
});
115117

116118
Then('the workflow-result job depends on {string}', async function (jobName) {
117-
const {jobs} = await loadWorkflowFile({projectRoot: this.projectRoot, name: 'node-ci'});
119+
const {jobs} = await loadWorkflowFile({projectRoot: this.projectRoot, name: ciWorkflowName});
118120

119121
assert.include(jobs['workflow-result'].needs, jobName);
120122
});
123+
124+
Then('the workflow-result job uses {string} as the runner', async function (runner) {
125+
const {jobs} = await loadWorkflowFile({projectRoot: this.projectRoot, name: ciWorkflowName});
126+
const {'workflow-result': resultJob} = jobs;
127+
128+
assert.equal(resultJob['runs-on'], runner);
129+
});

0 commit comments

Comments
 (0)