Skip to content

Commit 1efa4d9

Browse files
committed
feat(experimental-release-workflow): update the reusable workflow version based on node version
1 parent 6b64c3e commit 1efa4d9

File tree

2 files changed

+69
-11
lines changed

2 files changed

+69
-11
lines changed

src/semantic-release/ci-providers/github-workflows/experimental-release-workflow/lifter.js

+15-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {loadWorkflowFile, renameWorkflowFile, workflowFileExists} from '@form8ion/github-workflows-core';
22

3+
import {determineAppropriateWorkflow} from '../reusable-release-workflow.js';
34
import scaffoldWorkflow from './scaffolder.js';
45

56
function workflowPermissionsAreMinimal(existingContents) {
@@ -8,14 +9,23 @@ function workflowPermissionsAreMinimal(existingContents) {
89
&& 'read' === existingContents.permissions.contents;
910
}
1011

11-
async function contentsNeedToBeUpdated({projectRoot, name}) {
12+
function reusableWorkflowVersionAppropriateForNodeVersion({nodeVersion, reusableWorkflow}) {
13+
return reusableWorkflow === determineAppropriateWorkflow(nodeVersion);
14+
}
15+
16+
async function contentsNeedToBeUpdated({projectRoot, name, nodeVersion}) {
1217
const existingContents = await loadWorkflowFile({projectRoot, name});
1318

14-
return existingContents.on.workflow_dispatch || !workflowPermissionsAreMinimal(existingContents);
19+
return existingContents.on.workflow_dispatch
20+
|| !workflowPermissionsAreMinimal(existingContents)
21+
|| !reusableWorkflowVersionAppropriateForNodeVersion({
22+
nodeVersion,
23+
reusableWorkflow: existingContents.jobs.release.uses
24+
});
1525
}
1626

17-
async function releaseWorkflowShouldBeScaffolded({projectRoot, name}) {
18-
return !await workflowFileExists({projectRoot, name}) || contentsNeedToBeUpdated({projectRoot, name});
27+
async function releaseWorkflowShouldBeScaffolded({projectRoot, name, nodeVersion}) {
28+
return !await workflowFileExists({projectRoot, name}) || contentsNeedToBeUpdated({projectRoot, name, nodeVersion});
1929
}
2030

2131
async function renameLegacyReleaseWorkflow(projectRoot, experimentalReleaseWorkflowName) {
@@ -35,7 +45,7 @@ export default async function ({projectRoot, nodeVersion}) {
3545

3646
await renameLegacyReleaseWorkflow(projectRoot, experimentalReleaseWorkflowName);
3747

38-
if (await releaseWorkflowShouldBeScaffolded({projectRoot, name: experimentalReleaseWorkflowName})) {
48+
if (await releaseWorkflowShouldBeScaffolded({projectRoot, name: experimentalReleaseWorkflowName, nodeVersion})) {
3949
return scaffoldWorkflow({projectRoot, nodeVersion});
4050
}
4151

src/semantic-release/ci-providers/github-workflows/experimental-release-workflow/lifter.test.js

+54-6
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,27 @@ import any from '@travi/any';
44
import {it, describe, vi, expect, beforeEach} from 'vitest';
55
import {when} from 'jest-when';
66

7+
import {determineAppropriateWorkflow} from '../reusable-release-workflow.js';
78
import scaffoldWorkflow from './scaffolder.js';
89
import lift from './lifter.js';
910

1011
vi.mock('@form8ion/github-workflows-core');
12+
vi.mock('../reusable-release-workflow.js');
1113
vi.mock('./scaffolder.js');
1214

1315
const experimentalReleaseWorkflowName = 'experimental-release';
1416

1517
describe('experimental release workflow lifter', () => {
1618
const projectRoot = any.string();
1719
const nodeVersion = any.string();
20+
const appropriateReusableReleaseWorkflowVersion = any.string();
1821
const scaffoldResults = any.simpleObject();
1922

2023
beforeEach(() => {
2124
when(scaffoldWorkflow).calledWith({projectRoot, nodeVersion}).mockResolvedValue(scaffoldResults);
25+
when(determineAppropriateWorkflow)
26+
.calledWith(nodeVersion)
27+
.mockReturnValue(appropriateReusableReleaseWorkflowVersion);
2228
});
2329

2430
it('should call the scaffolder when the experimental release workflow does not exist', async () => {
@@ -32,15 +38,22 @@ describe('experimental release workflow lifter', () => {
3238
when(workflowFileExists).calledWith({projectRoot, name: experimentalReleaseWorkflowName}).mockResolvedValue(true);
3339
when(loadWorkflowFile)
3440
.calledWith({projectRoot, name: experimentalReleaseWorkflowName})
35-
.mockResolvedValue({on: {workflow_dispatch: {}}, permissions: {contents: 'read'}});
41+
.mockResolvedValue({
42+
on: {workflow_dispatch: {}},
43+
permissions: {contents: 'read'},
44+
jobs: {release: {uses: appropriateReusableReleaseWorkflowVersion}}
45+
});
3646

3747
expect(await lift({projectRoot, nodeVersion})).toEqual(scaffoldResults);
3848
expect(renameWorkflowFile).not.toHaveBeenCalled();
3949
});
4050

4151
it('should re-run the scaffolder when permissions have not been restricted', async () => {
4252
when(workflowFileExists).calledWith({projectRoot, name: experimentalReleaseWorkflowName}).mockResolvedValue(true);
43-
when(loadWorkflowFile).calledWith({projectRoot, name: experimentalReleaseWorkflowName}).mockResolvedValue({on: {}});
53+
when(loadWorkflowFile).calledWith({projectRoot, name: experimentalReleaseWorkflowName}).mockResolvedValue({
54+
on: {},
55+
jobs: {release: {uses: appropriateReusableReleaseWorkflowVersion}}
56+
});
4457

4558
expect(await lift({projectRoot, nodeVersion})).toEqual(scaffoldResults);
4659
expect(renameWorkflowFile).not.toHaveBeenCalled();
@@ -50,7 +63,11 @@ describe('experimental release workflow lifter', () => {
5063
when(workflowFileExists).calledWith({projectRoot, name: experimentalReleaseWorkflowName}).mockResolvedValue(true);
5164
when(loadWorkflowFile)
5265
.calledWith({projectRoot, name: experimentalReleaseWorkflowName})
53-
.mockResolvedValue({on: {}, permissions: any.simpleObject()});
66+
.mockResolvedValue({
67+
on: {},
68+
permissions: any.simpleObject(),
69+
jobs: {release: {uses: appropriateReusableReleaseWorkflowVersion}}
70+
});
5471

5572
expect(await lift({projectRoot, nodeVersion})).toEqual(scaffoldResults);
5673
expect(renameWorkflowFile).not.toHaveBeenCalled();
@@ -60,7 +77,11 @@ describe('experimental release workflow lifter', () => {
6077
when(workflowFileExists).calledWith({projectRoot, name: experimentalReleaseWorkflowName}).mockResolvedValue(true);
6178
when(loadWorkflowFile)
6279
.calledWith({projectRoot, name: experimentalReleaseWorkflowName})
63-
.mockResolvedValue({on: {}, permissions: {contents: 'write'}});
80+
.mockResolvedValue({
81+
on: {},
82+
permissions: {contents: 'write'},
83+
jobs: {release: {uses: appropriateReusableReleaseWorkflowVersion}}
84+
});
6485

6586
expect(await lift({projectRoot, nodeVersion})).toEqual(scaffoldResults);
6687
expect(renameWorkflowFile).not.toHaveBeenCalled();
@@ -70,18 +91,45 @@ describe('experimental release workflow lifter', () => {
7091
when(workflowFileExists).calledWith({projectRoot, name: experimentalReleaseWorkflowName}).mockResolvedValue(true);
7192
when(loadWorkflowFile)
7293
.calledWith({projectRoot, name: experimentalReleaseWorkflowName})
73-
.mockResolvedValue({on: {}, permissions: {contents: 'read'}});
94+
.mockResolvedValue({
95+
on: {},
96+
permissions: {contents: 'read'},
97+
jobs: {release: {uses: appropriateReusableReleaseWorkflowVersion}}
98+
});
7499

75100
expect(await lift({projectRoot, nodeVersion})).toBe(undefined);
76101
expect(renameWorkflowFile).not.toHaveBeenCalled();
77102
});
78103

104+
it('should re-run the scaffolder when an inappropriate version of the reusable workflow is referenced', async () => {
105+
const inappropriateReusableReleaseWorkflowVersion = any.string();
106+
when(workflowFileExists).calledWith({projectRoot, name: experimentalReleaseWorkflowName}).mockResolvedValue(true);
107+
when(loadWorkflowFile)
108+
.calledWith({projectRoot, name: experimentalReleaseWorkflowName})
109+
.mockResolvedValue({
110+
on: {},
111+
permissions: {contents: 'read'},
112+
jobs: {release: {uses: inappropriateReusableReleaseWorkflowVersion}}
113+
});
114+
115+
expect(await lift({projectRoot, nodeVersion})).toEqual(scaffoldResults);
116+
expect(renameWorkflowFile).not.toHaveBeenCalled();
117+
});
118+
79119
it('should should rename a legacy release workflow to clarify that it is for experimental releases', async () => {
80120
const legacyReleaseWorkflowName = 'release';
81121
when(workflowFileExists).calledWith({projectRoot, name: legacyReleaseWorkflowName}).mockResolvedValue(true);
82122
when(loadWorkflowFile)
83123
.calledWith({projectRoot, name: legacyReleaseWorkflowName})
84-
.mockResolvedValue({on: {}, permissions: {contents: 'read'}});
124+
.mockResolvedValue(any.simpleObject());
125+
when(workflowFileExists).calledWith({projectRoot, name: experimentalReleaseWorkflowName}).mockResolvedValue(true);
126+
when(loadWorkflowFile)
127+
.calledWith({projectRoot, name: experimentalReleaseWorkflowName})
128+
.mockResolvedValue({
129+
on: {},
130+
permissions: {contents: 'read'},
131+
jobs: {release: {uses: appropriateReusableReleaseWorkflowVersion}}
132+
});
85133

86134
expect(await lift({projectRoot, nodeVersion})).toBe(undefined);
87135
expect(renameWorkflowFile).toHaveBeenCalledWith({

0 commit comments

Comments
 (0)