Skip to content

Commit 39d20b6

Browse files
committed
lint
1 parent 5daee0f commit 39d20b6

3 files changed

Lines changed: 136 additions & 50 deletions

File tree

actions/release-tag-creation/current-version-validation.test.ts

Lines changed: 73 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { execSync } from 'node:child_process';
2-
import { appendFileSync } from 'node:fs';
32
import { beforeEach, describe, expect, it, vi } from 'vitest';
43

54
import { checkVersionIsNext } from './current-version-validation.ts';
@@ -14,40 +13,88 @@ function makeLsRemoteTags(tags: string[]): string {
1413
}
1514

1615
describe('checkVersionIsNext', () => {
17-
beforeEach(() => vi.clearAllMocks());
16+
beforeEach(() => {
17+
vi.clearAllMocks();
18+
});
1819

1920
it.each([
2021
// stable — patch
21-
['stable', ['4.2.0', '4.2.1', '4.2.2'], '4.2.3', true, null],
22-
['stable', ['4.2.0', '4.2.1', '4.2.2'], '4.2.4', false, 'Expected next patch release to be 4.2.3'],
23-
['stable', ['4.2.0', '4.2.1', '4.2.2'], '4.2.2', false, 'Expected next patch release to be 4.2.3'],
22+
['stable', ['4.2.0', '4.2.1', '4.2.2'], '4.2.3', true, null],
23+
[
24+
'stable',
25+
['4.2.0', '4.2.1', '4.2.2'],
26+
'4.2.4',
27+
false,
28+
'Expected next patch release to be 4.2.3',
29+
],
30+
[
31+
'stable',
32+
['4.2.0', '4.2.1', '4.2.2'],
33+
'4.2.2',
34+
false,
35+
'Expected next patch release to be 4.2.3',
36+
],
2437
// stable — minor
25-
['stable', ['4.1.0', '4.2.0', '4.2.5'], '4.3.0', true, null],
26-
['stable', ['4.1.0', '4.2.0', '4.2.5'], '4.4.0', false, 'Expected next minor release to be 4.3.0'],
38+
['stable', ['4.1.0', '4.2.0', '4.2.5'], '4.3.0', true, null],
39+
[
40+
'stable',
41+
['4.1.0', '4.2.0', '4.2.5'],
42+
'4.4.0',
43+
false,
44+
'Expected next minor release to be 4.3.0',
45+
],
2746
// stable — no existing tags
28-
['stable', ['4.1.0-beta1'], '4.1.0', true, null],
47+
['stable', ['4.1.0-beta1'], '4.1.0', true, null],
2948
// beta — next in same series
30-
['beta', ['4.2.0-beta1', '4.2.0-beta2'], '4.2.0-beta3', true, null],
31-
['beta', ['4.2.0-beta1', '4.2.0-beta2'], '4.2.0-beta4', false, 'Expected next beta to be 4.2.0-beta3'],
32-
['beta', ['4.2.0-beta1', '4.2.0-beta2'], '4.2.0-beta2', false, 'Expected next beta to be 4.2.0-beta3'],
49+
['beta', ['4.2.0-beta1', '4.2.0-beta2'], '4.2.0-beta3', true, null],
50+
[
51+
'beta',
52+
['4.2.0-beta1', '4.2.0-beta2'],
53+
'4.2.0-beta4',
54+
false,
55+
'Expected next beta to be 4.2.0-beta3',
56+
],
57+
[
58+
'beta',
59+
['4.2.0-beta1', '4.2.0-beta2'],
60+
'4.2.0-beta2',
61+
false,
62+
'Expected next beta to be 4.2.0-beta3',
63+
],
3364
// beta — new version line
34-
['beta', ['4.2.0-beta1', '4.2.0-beta2'], '4.3.0-beta1', true, null],
35-
['beta', ['4.2.0-beta1', '4.2.0-beta2'], '4.3.0-beta2', false, 'must be beta1'],
65+
['beta', ['4.2.0-beta1', '4.2.0-beta2'], '4.3.0-beta1', true, null],
66+
[
67+
'beta',
68+
['4.2.0-beta1', '4.2.0-beta2'],
69+
'4.3.0-beta2',
70+
false,
71+
'must be beta1',
72+
],
3673
// beta — no existing tags
37-
['beta', ['4.1.0', '4.2.0'], '4.2.0-beta1', true, null],
38-
] as const)('%s %s → %s (valid=%s)', (channel, existingTags, version, valid, errorMsg) => {
39-
mockExecSync.mockReturnValue(makeLsRemoteTags([...existingTags]) as never);
40-
const fn = () => checkVersionIsNext(version, channel);
41-
if (valid) {
42-
expect(fn).not.toThrow();
43-
} else {
44-
expect(fn).toThrow(errorMsg!);
45-
}
46-
});
74+
['beta', ['4.1.0', '4.2.0'], '4.2.0-beta1', true, null],
75+
] as const)(
76+
'%s %s → %s (valid=%s)',
77+
(channel, existingTags, version, valid, errorMsg) => {
78+
mockExecSync.mockReturnValue(
79+
makeLsRemoteTags([...existingTags]) as never,
80+
);
81+
const fn = () => {
82+
checkVersionIsNext(version, channel);
83+
};
84+
if (valid) {
85+
expect(fn).not.toThrow();
86+
} else {
87+
expect(fn).toThrow(errorMsg);
88+
}
89+
},
90+
);
4791

4892
it('throws when git ls-remote fails', () => {
49-
mockExecSync.mockImplementation(() => { throw new Error('network error'); });
50-
expect(() => checkVersionIsNext('4.2.3', 'stable')).toThrow('Failed to fetch remote tags');
93+
mockExecSync.mockImplementation(() => {
94+
throw new Error('network error');
95+
});
96+
expect(() => {
97+
checkVersionIsNext('4.2.3', 'stable');
98+
}).toThrow('Failed to fetch remote tags');
5199
});
52100
});
53-

actions/release-tag-creation/current-version-validation.ts

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,13 @@ export const ALLOWED_PATTERN = /^\d+\.\d+\.\d+(-beta\d+)?$/;
66
function fetchTagsByChannel(channel: 'stable' | 'beta'): string[] {
77
let tagsOutput: string;
88
try {
9-
tagsOutput = execSync('git ls-remote --tags origin', { encoding: 'utf8' });
9+
tagsOutput = execSync('git ls-remote --tags origin', {
10+
encoding: 'utf8',
11+
});
1012
} catch (err) {
11-
throw new Error(`Failed to fetch remote tags: ${(err as Error).message}`);
13+
throw new Error(
14+
`Failed to fetch remote tags: ${(err as Error).message}`,
15+
);
1216
}
1317

1418
return tagsOutput
@@ -21,31 +25,42 @@ function fetchTagsByChannel(channel: 'stable' | 'beta'): string[] {
2125
});
2226
}
2327

24-
25-
function validateNextStable(version: string, n: semver.SemVer, l: semver.SemVer): void {
28+
function validateNextStable(
29+
version: string,
30+
n: semver.SemVer,
31+
l: semver.SemVer,
32+
): void {
2633
const isNewMinor = n.patch === 0;
2734
const expected = isNewMinor
28-
? `${l.major}.${l.minor + 1}.0`
29-
: `${l.major}.${l.minor}.${l.patch + 1}`;
35+
? `${String(l.major)}.${String(l.minor + 1)}.0`
36+
: `${String(l.major)}.${String(l.minor)}.${String(l.patch + 1)}`;
3037
if (version !== expected) {
3138
const kind = isNewMinor ? 'minor' : 'patch';
3239
throw new Error(
33-
`Expected next ${kind} release to be ${expected}, got ${version} (latest: ${l}).`,
40+
`Expected next ${kind} release to be ${expected}, got ${version} (latest: ${l.version}).`,
3441
);
3542
}
3643
}
3744

38-
function validateNextBeta(version: string, n: semver.SemVer, l: semver.SemVer, latest: string): void {
45+
function validateNextBeta(
46+
version: string,
47+
n: semver.SemVer,
48+
l: semver.SemVer,
49+
latest: string,
50+
): void {
3951
const latestBetaNum = Number(String(l.prerelease[0]).replace('beta', ''));
4052
const newBetaNum = Number(String(n.prerelease[0]).replace('beta', ''));
41-
const sameLine = n.major === l.major && n.minor === l.minor && n.patch === l.patch;
53+
const sameLine =
54+
n.major === l.major && n.minor === l.minor && n.patch === l.patch;
4255
if (sameLine && newBetaNum !== latestBetaNum + 1) {
4356
throw new Error(
44-
`Expected next beta to be ${latest.replace(`beta${latestBetaNum}`, `beta${latestBetaNum + 1}`)}, got ${version}.`,
57+
`Expected next beta to be ${latest.replace(`beta${String(latestBetaNum)}`, `beta${String(latestBetaNum + 1)}`)}, got ${version}.`,
4558
);
4659
}
4760
if (!sameLine && newBetaNum !== 1) {
48-
throw new Error(`First beta of a new version line must be beta1, got ${version}.`);
61+
throw new Error(
62+
`First beta of a new version line must be beta1, got ${version}.`,
63+
);
4964
}
5065
}
5166

@@ -56,20 +71,34 @@ export function fetchCompanionTag(channel: 'stable' | 'beta'): string | null {
5671
return tags.sort(semver.rcompare)[0] ?? null;
5772
}
5873

59-
export function checkVersionIsNext(version: string, channel: 'stable' | 'beta'): void {
74+
export function checkVersionIsNext(
75+
version: string,
76+
channel: 'stable' | 'beta',
77+
): void {
6078
const channelTags = fetchTagsByChannel(channel);
6179
if (channelTags.length === 0) {
62-
console.log(`✅ No existing ${channel} tags — treating as first release.`);
80+
console.log(
81+
`✅ No existing ${channel} tags — treating as first release.`,
82+
);
6383
return;
6484
}
6585
const latest = channelTags.sort(semver.rcompare)[0];
66-
const l = semver.parse(latest)!;
67-
const n = semver.parse(version)!;
86+
if (!latest) {
87+
return;
88+
}
89+
const l = semver.parse(latest);
90+
const n = semver.parse(version);
91+
if (!l || !n) {
92+
throw new Error(
93+
`Failed to parse version strings: latest=${latest}, version=${version}`,
94+
);
95+
}
6896
if (channel === 'stable') {
6997
validateNextStable(version, n, l);
7098
} else {
7199
validateNextBeta(version, n, l, latest);
72100
}
73-
console.log(`✅ Version ${version} is the correct next version after ${latest}.`);
101+
console.log(
102+
`✅ Version ${version} is the correct next version after ${latest}.`,
103+
);
74104
}
75-

actions/release-tag-creation/main.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
import { spawnSync } from 'node:child_process';
22
import { appendFileSync } from 'node:fs';
33
import semver from 'semver';
4-
import { ALLOWED_PATTERN, checkVersionIsNext, fetchCompanionTag } from './current-version-validation.ts';
4+
import {
5+
ALLOWED_PATTERN,
6+
checkVersionIsNext,
7+
fetchCompanionTag,
8+
} from './current-version-validation.ts';
59

610
// ─── I/O helpers ──────────────────────────────────────────────────────────────
711

812
export function getVersion(): string {
913
const version = (process.env['INPUT_VERSION'] ?? '').trim();
1014

1115
if (!version) {
12-
throw new Error('No version provided. Set the INPUT_VERSION environment variable.');
16+
throw new Error(
17+
'No version provided. Set the INPUT_VERSION environment variable.',
18+
);
1319
}
1420

1521
return version;
@@ -41,7 +47,9 @@ export function validateFormat(version: string): void {
4147
export function checkCurrentTagDoesNotExist(version: string): void {
4248
const tagRef = `refs/tags/${version}`;
4349

44-
const result = spawnSync('git', ['ls-remote', 'origin', tagRef], { encoding: 'utf8' });
50+
const result = spawnSync('git', ['ls-remote', 'origin', tagRef], {
51+
encoding: 'utf8',
52+
});
4553

4654
if (result.error) {
4755
throw new Error(`Failed to check remote tags: ${result.error.message}`);
@@ -65,14 +73,16 @@ export function checkCurrentTagDoesNotExist(version: string): void {
6573
export function extractChannel(version: string): 'stable' | 'beta' {
6674
const prerelease = semver.prerelease(version);
6775

68-
console.log(`Determining channel for version "${version}" (prerelease: ${JSON.stringify(prerelease)})`);
76+
console.log(
77+
`Determining channel for version "${version}" (prerelease: ${JSON.stringify(prerelease)})`,
78+
);
6979

7080
if (prerelease === null) {
7181
return 'stable';
7282
}
7383

74-
const prereleaseChannel = String( prerelease[0] );
75-
if ( prereleaseChannel?.startsWith('beta') ) {
84+
const prereleaseChannel = String(prerelease[0]);
85+
if (prereleaseChannel.startsWith('beta')) {
7686
return 'beta';
7787
}
7888

@@ -83,7 +93,7 @@ export function extractChannel(version: string): 'stable' | 'beta' {
8393
}
8494

8595
export function deriveBranch(channel: 'stable' | 'beta'): string {
86-
return `release/${channel}`;
96+
return `release/${channel}`;
8797
}
8898

8999
// ─── entry point ──────────────────────────────────────────────────────────────

0 commit comments

Comments
 (0)