Skip to content

Commit d391f04

Browse files
committed
feat(workflow-file): leverage workflows-core loader and drop direct js-yaml dependency
1 parent 7af655b commit d391f04

11 files changed

Lines changed: 59 additions & 80 deletions

File tree

package-lock.json

Lines changed: 8 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,8 @@
5454
},
5555
"dependencies": {
5656
"@form8ion/core": "^4.0.0",
57-
"@form8ion/github-workflows-core": "^5.1.0",
57+
"@form8ion/github-workflows-core": "^5.2.0",
5858
"@form8ion/javascript-core": "^11.0.0",
59-
"js-yaml": "^4.0.0",
6059
"semver": "^7.3.7"
6160
},
6261
"devDependencies": {

src/lifter/lifter.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
import {promises as fs} from 'fs';
2-
import {load} from 'js-yaml';
3-
import {writeWorkflowFile} from '@form8ion/github-workflows-core';
2+
import {loadWorkflowFile, writeWorkflowFile} from '@form8ion/github-workflows-core';
43

54
import {scaffold as scaffoldBadges} from '../badges/index.js';
65
import {lift as liftJobs} from '../jobs/index.js';
76
import mergeBranches from './branches/merge-branches.js';
87

98
export default async function ({projectRoot, results: {branchesToVerify}, vcs, runner}) {
10-
const pathToConfig = `${projectRoot}/.github/workflows/node-ci.yml`;
11-
const existingConfig = load(await fs.readFile(pathToConfig, 'utf-8'));
9+
const existingConfig = await loadWorkflowFile({projectRoot, name: 'node-ci'});
1210
const {engines} = JSON.parse(await fs.readFile(`${projectRoot}/package.json`, 'utf-8'));
1311
const existingBranches = existingConfig.on.push.branches;
1412

src/lifter/lifter.test.js

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import {promises as fs} from 'node:fs';
2-
import jsYaml from 'js-yaml';
3-
import {writeWorkflowFile} from '@form8ion/github-workflows-core';
2+
import {loadWorkflowFile, writeWorkflowFile} from '@form8ion/github-workflows-core';
43

5-
import {afterEach, beforeEach, describe, it, vi, expect} from 'vitest';
4+
import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
65
import any from '@travi/any';
76
import {when} from 'jest-when';
87

@@ -12,26 +11,22 @@ import {lift as liftJobs} from '../jobs/index.js';
1211
import lift from './lifter.js';
1312

1413
vi.mock('node:fs');
15-
vi.mock('js-yaml');
1614
vi.mock('@form8ion/github-workflows-core');
1715
vi.mock('./branches/merge-branches');
1816
vi.mock('../jobs/index.js');
1917
vi.mock('../badges');
2018

2119
describe('lifter', () => {
2220
const projectRoot = any.string();
23-
const rawExistingConfig = any.string();
2421
const existingJobs = any.listOf(any.simpleObject);
2522
const liftedJobs = any.listOf(any.simpleObject);
2623
const enginesDefinition = any.simpleObject();
2724
const badgesResults = any.simpleObject();
2825
const vcs = any.simpleObject();
2926
const runner = any.word();
27+
const ciWorkflowName = 'node-ci';
3028

3129
beforeEach(() => {
32-
when(fs.readFile)
33-
.calledWith(`${projectRoot}/.github/workflows/node-ci.yml`, 'utf-8')
34-
.mockResolvedValue(rawExistingConfig);
3530
when(fs.readFile)
3631
.calledWith(`${projectRoot}/package.json`, 'utf-8')
3732
.mockResolvedValue(JSON.stringify({engines: enginesDefinition}));
@@ -49,12 +44,14 @@ describe('lifter', () => {
4944
on: {...any.simpleObject(), push: {branches: any.listOf(any.word)}},
5045
jobs: existingJobs
5146
};
52-
when(jsYaml.load).calledWith(rawExistingConfig).mockReturnValue(existingConfig);
47+
when(loadWorkflowFile)
48+
.calledWith({projectRoot, name: ciWorkflowName})
49+
.mockResolvedValue(existingConfig);
5350

5451
expect(await lift({projectRoot, results: any.simpleObject(), vcs, runner})).toEqual({badges: badgesResults});
5552
expect(writeWorkflowFile).toHaveBeenCalledWith({
5653
projectRoot,
57-
name: 'node-ci',
54+
name: ciWorkflowName,
5855
config: {...existingConfig, permissions: {contents: 'read'}, jobs: liftedJobs}
5956
});
6057
});
@@ -68,14 +65,16 @@ describe('lifter', () => {
6865
jobs: existingJobs
6966
};
7067
const mergedBranches = any.listOf(any.word);
71-
when(jsYaml.load).calledWith(rawExistingConfig).mockReturnValue(existingConfig);
68+
when(loadWorkflowFile)
69+
.calledWith({projectRoot, name: ciWorkflowName})
70+
.mockResolvedValue(existingConfig);
7271
when(mergeBranchList).calledWith(existingBranches, branchesToVerify).mockReturnValue(mergedBranches);
7372

7473
expect(await lift({projectRoot, results: {...any.simpleObject(), branchesToVerify}, vcs, runner}))
7574
.toEqual({badges: badgesResults});
7675
expect(writeWorkflowFile).toHaveBeenCalledWith({
7776
projectRoot,
78-
name: 'node-ci',
77+
name: ciWorkflowName,
7978
config: {
8079
...existingConfig,
8180
on: {...existingConfig.on, push: {branches: mergedBranches}},

src/scaffolder/config-scaffolder.test.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {nvmrcVerification} from '../jobs/scaffolder.js';
99
import scaffoldConfig from './config-scaffolder.js';
1010

1111
vi.mock('fs');
12-
vi.mock('js-yaml');
1312
vi.mock('@form8ion/github-workflows-core');
1413
vi.mock('../jobs/scaffolder.js');
1514

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import {promises as fs} from 'node:fs';
1+
import {loadWorkflowFile} from '@form8ion/github-workflows-core';
2+
23
import {Given, Then} from '@cucumber/cucumber';
34
import any from '@travi/any';
45
import {assert} from 'chai';
5-
import {load} from 'js-yaml';
66

77
Given('additional branches are provided', async function () {
88
this.additionalBranches = any.listOf(any.word);
@@ -17,7 +17,7 @@ Given('existing branches are provided as additional branches', async function ()
1717
});
1818

1919
Then('the branches are added to the ci config', async function () {
20-
const triggers = load(await fs.readFile(`${process.cwd()}/.github/workflows/node-ci.yml`)).on;
20+
const {on: triggers} = await loadWorkflowFile({projectRoot: this.projectRoot, name: 'node-ci'});
2121

2222
assert.deepEqual(triggers.push.branches, [...this.existingBranches, ...this.additionalBranches]);
2323
assert.deepEqual(triggers.pull_request, this.prTriggerConfig);

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

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {promises as fs} from 'node:fs';
2-
import {load} from 'js-yaml';
32
import {
3+
loadWorkflowFile,
44
scaffoldCheckoutStep,
55
scaffoldDependencyInstallationStep,
66
scaffoldNodeSetupStep,
@@ -12,14 +12,12 @@ import {Before, Given, Then} from '@cucumber/cucumber';
1212
import {assert} from 'chai';
1313
import any from '@travi/any';
1414

15-
export const pathToWorkflowsDirectory = `${process.cwd()}/.github/workflows`;
16-
1715
Before(async function () {
1816
this.prTriggerConfig = any.simpleObject();
1917
});
2018

2119
Given('a CI workflow exists', async function () {
22-
await fs.mkdir(pathToWorkflowsDirectory, {recursive: true});
20+
await fs.mkdir(`${process.cwd()}/.github/workflows`, {recursive: true});
2321

2422
await writeWorkflowFile({
2523
projectRoot: this.projectRoot,
@@ -35,7 +33,7 @@ Given('a CI workflow exists', async function () {
3533
});
3634

3735
Then('the ci config remains unchanged', async function () {
38-
const {on: triggers, jobs} = load(await fs.readFile(`${process.cwd()}/.github/workflows/node-ci.yml`, 'utf-8'));
36+
const {on: triggers, jobs} = await loadWorkflowFile({projectRoot: this.projectRoot, name: 'node-ci'});
3937

4038
assert.deepEqual(triggers.push.branches, this.existingBranches);
4139
assert.deepEqual(triggers.pull_request, this.prTriggerConfig);
@@ -46,17 +44,20 @@ Then('the ci config remains unchanged', async function () {
4644
});
4745

4846
Then('dependency caching is enabled', async function () {
49-
const {jobs} = load(await fs.readFile(`${process.cwd()}/.github/workflows/node-ci.yml`, 'utf-8'));
47+
const {jobs} = await loadWorkflowFile({projectRoot: this.projectRoot, name: 'node-ci'});
5048

5149
const setupNodeStep = jobs[this.existingJobName].steps.find(step => 'Setup node' === step.name);
5250
assert.equal(setupNodeStep.with.cache, 'npm');
5351
});
5452

5553
Then('the verification workflow is created', async function () {
56-
const {name, on: triggers, env, permissions, jobs} = load(await fs.readFile(
57-
`${process.cwd()}/.github/workflows/node-ci.yml`,
58-
'utf-8'
59-
));
54+
const {
55+
name,
56+
on: triggers,
57+
env,
58+
permissions,
59+
jobs
60+
} = await loadWorkflowFile({projectRoot: this.projectRoot, name: 'node-ci'});
6061

6162
assert.equal(name, 'Node.js CI');
6263
assert.deepEqual(

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

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
1-
import {promises as fs} from 'fs';
2-
import {load} from 'js-yaml';
3-
import {writeWorkflowFile} from '@form8ion/github-workflows-core';
1+
import {loadWorkflowFile, writeWorkflowFile} from '@form8ion/github-workflows-core';
42

53
import {Given, Then} from '@cucumber/cucumber';
64
import any from '@travi/any';
75
import {assert} from 'chai';
86

9-
import {pathToWorkflowsDirectory} from './ci-steps.js';
10-
11-
const pathToCiWorkflow = `${pathToWorkflowsDirectory}/node-ci.yml`;
12-
137
Given('the legacy action is in use for installing dependencies', async function () {
148
this.existingJobName = any.word();
159
this.existingJobSteps = [
@@ -22,7 +16,7 @@ Given('the legacy action is in use for installing dependencies', async function
2216
{uses: 'bahmutov/npm-install@v1'}
2317
];
2418

25-
const ciWorkflow = load(await fs.readFile(pathToCiWorkflow, 'utf-8'));
19+
const ciWorkflow = await loadWorkflowFile({projectRoot: this.projectRoot, name: 'node-ci'});
2620

2721
ciWorkflow.jobs[this.existingJobName] = {steps: this.existingJobSteps};
2822

@@ -32,7 +26,7 @@ Given('the legacy action is in use for installing dependencies', async function
3226
Then('the legacy action is replaced with direct installation', async function () {
3327
const {
3428
jobs: {[this.existingJobName]: existingJob}
35-
} = load(await fs.readFile(`${process.cwd()}/.github/workflows/node-ci.yml`, 'utf-8'));
29+
} = await loadWorkflowFile({projectRoot: this.projectRoot, name: 'node-ci'});
3630

3731
assert.notDeepInclude(existingJob.steps, {uses: 'bahmutov/npm-install@v1'});
3832
assert.deepInclude(existingJob.steps, {run: 'npm clean-install'});

test/integration/features/step_definitions/node-versions-steps.js

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
import {promises as fs} from 'fs';
2-
import {load} from 'js-yaml';
32
import {writePackageJson} from '@form8ion/javascript-core';
4-
import {scaffoldCheckoutStep, scaffoldNodeSetupStep, writeWorkflowFile} from '@form8ion/github-workflows-core';
3+
import {
4+
loadWorkflowFile,
5+
scaffoldCheckoutStep,
6+
scaffoldNodeSetupStep,
7+
writeWorkflowFile
8+
} from '@form8ion/github-workflows-core';
59

610
import {Given, Then} from '@cucumber/cucumber';
711
import any from '@travi/any';
812
import {assert} from 'chai';
913
import * as td from 'testdouble';
1014

11-
import {pathToWorkflowsDirectory} from './ci-steps.js';
12-
1315
const ciWorkflowName = 'node-ci';
14-
const pathToCiWorkflow = `${pathToWorkflowsDirectory}/${ciWorkflowName}.yml`;
1516

1617
Given('the nvmrc is referenced using the modern property {string} caching enabled', async function (cachingEnabled) {
1718
this.existingJobName = any.word();
@@ -28,7 +29,7 @@ Given('the nvmrc is referenced using the modern property {string} caching enable
2829
{run: 'npm clean-install'}
2930
];
3031

31-
const ciWorkflow = load(await fs.readFile(pathToCiWorkflow, 'utf-8'));
32+
const ciWorkflow = await loadWorkflowFile({projectRoot: this.projectRoot, name: ciWorkflowName});
3233

3334
ciWorkflow.jobs[this.existingJobName] = {steps: this.existingJobSteps};
3435

@@ -56,7 +57,7 @@ Given('the version is read from the nvmrc and passed as a value to the setup-nod
5657
{run: 'npm clean-install'}
5758
];
5859

59-
const ciWorkflow = load(await fs.readFile(pathToCiWorkflow, 'utf-8'));
60+
const ciWorkflow = await loadWorkflowFile({projectRoot: this.projectRoot, name: ciWorkflowName});
6061

6162
ciWorkflow.jobs[this.existingJobName] = {steps: this.existingJobSteps};
6263

@@ -83,7 +84,7 @@ Given('the node version is based on a matrix {string} caching enabled', async fu
8384
{run: 'npm clean-install'}
8485
];
8586

86-
const ciWorkflow = load(await fs.readFile(pathToCiWorkflow, 'utf-8'));
87+
const ciWorkflow = await loadWorkflowFile({projectRoot: this.projectRoot, name: ciWorkflowName});
8788

8889
ciWorkflow.jobs[this.existingJobName] = {
8990
strategy: {matrix: {node: this.existingNodeVersions}},
@@ -105,7 +106,7 @@ Given('the version is defined statically', async function () {
105106
{run: 'npm clean-install'}
106107
];
107108

108-
const ciWorkflow = load(await fs.readFile(pathToCiWorkflow, 'utf-8'));
109+
const ciWorkflow = await loadWorkflowFile({projectRoot: this.projectRoot, name: ciWorkflowName});
109110

110111
ciWorkflow.jobs[this.existingJobName] = {steps: this.existingJobSteps};
111112

@@ -156,7 +157,7 @@ Given('multiple node version ranges are defined', async function () {
156157
Then('the setup-node step is updated to reference the nvmrc file using the modern property', async function () {
157158
const {
158159
jobs: {[this.existingJobName]: existingJob}
159-
} = load(await fs.readFile(`${process.cwd()}/.github/workflows/node-ci.yml`, 'utf-8'));
160+
} = await loadWorkflowFile({projectRoot: this.projectRoot, name: ciWorkflowName});
160161

161162
assert.isEmpty(existingJob.steps.filter(step => 'nvm' === step.id));
162163

@@ -166,13 +167,13 @@ Then('the setup-node step is updated to reference the nvmrc file using the moder
166167
});
167168

168169
Then('no matrix job is configured', async function () {
169-
const {jobs} = load(await fs.readFile(`${process.cwd()}/.github/workflows/node-ci.yml`, 'utf-8'));
170+
const {jobs} = await loadWorkflowFile({projectRoot: this.projectRoot, name: ciWorkflowName});
170171

171172
assert.equal(Object.values(jobs).filter(job => job.strategy?.matrix).length, 0);
172173
});
173174

174175
Then('the matrix job is unchanged', async function () {
175-
const {jobs} = load(await fs.readFile(`${process.cwd()}/.github/workflows/node-ci.yml`, 'utf-8'));
176+
const {jobs} = await loadWorkflowFile({projectRoot: this.projectRoot, name: ciWorkflowName});
176177

177178
assert.deepEqual(
178179
jobs[this.existingJobName],
@@ -181,7 +182,7 @@ Then('the matrix job is unchanged', async function () {
181182
});
182183

183184
Then('a matrix job is added', async function () {
184-
const {jobs} = load(await fs.readFile(`${process.cwd()}/.github/workflows/node-ci.yml`, 'utf-8'));
185+
const {jobs} = await loadWorkflowFile({projectRoot: this.projectRoot, name: ciWorkflowName});
185186
const {'verify-matrix': verifyMatrixJob} = jobs;
186187
const jobDefinitions = Object.values(jobs);
187188

@@ -204,14 +205,14 @@ Then('a matrix job is added', async function () {
204205
});
205206

206207
Then('the matrix job uses {string} as the runner', async function (runner) {
207-
const {jobs} = load(await fs.readFile(`${process.cwd()}/.github/workflows/node-ci.yml`, 'utf-8'));
208+
const {jobs} = await loadWorkflowFile({projectRoot: this.projectRoot, name: ciWorkflowName});
208209
const {'verify-matrix': verifyMatrixJob} = jobs;
209210

210211
assert.equal(verifyMatrixJob['runs-on'], runner);
211212
});
212213

213214
Then('the matrix job is updated', async function () {
214-
const {jobs} = load(await fs.readFile(`${process.cwd()}/.github/workflows/node-ci.yml`, 'utf-8'));
215+
const {jobs} = await loadWorkflowFile({projectRoot: this.projectRoot, name: ciWorkflowName});
215216

216217
assert.equal(Object.values(jobs).filter(job => job.strategy?.matrix).length, 1);
217218
assert.deepEqual(

test/integration/features/step_definitions/reusable-workflow-steps.js

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
1-
import {promises as fs} from 'fs';
2-
import {load} from 'js-yaml';
3-
import {writeWorkflowFile} from '@form8ion/github-workflows-core';
1+
import {loadWorkflowFile, writeWorkflowFile} from '@form8ion/github-workflows-core';
42

53
import {Given} from '@cucumber/cucumber';
64
import any from '@travi/any';
75

8-
import {pathToWorkflowsDirectory} from './ci-steps.js';
9-
106
Given('a reusable workflow is called', async function () {
11-
const pathToCiWorkflow = `${pathToWorkflowsDirectory}/node-ci.yml`;
12-
13-
const existingWorkflowDetails = load(await fs.readFile(pathToCiWorkflow, 'utf-8'));
7+
const existingWorkflowDetails = await loadWorkflowFile({projectRoot: this.projectRoot, name: 'node-ci'});
148

159
await writeWorkflowFile({
1610
projectRoot: this.projectRoot,

0 commit comments

Comments
 (0)