Skip to content

Commit bf9173f

Browse files
authored
feat(scripts): compute eligibility dates (#4064)
1 parent ff2d23c commit bf9173f

File tree

7 files changed

+130
-44
lines changed

7 files changed

+130
-44
lines changed

scripts/cli/index.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { formatter } from '../formatter.js';
1212
import { generate } from '../generate.js';
1313
import { playground } from '../playground.js';
1414
import { createReleasePR } from '../release/createReleasePR.js';
15-
import { generateVersionsHistory } from '../release/versionsHistory.js';
1615
import { buildSpecs } from '../specs/index.js';
1716
import type { Language } from '../types.js';
1817

@@ -308,16 +307,11 @@ program
308307
.action(async ({ verbose, releaseType, dryRun, versionsHistory, breaking }) => {
309308
setVerbose(Boolean(verbose));
310309

311-
if (versionsHistory) {
312-
await generateVersionsHistory({});
313-
314-
return;
315-
}
316-
317310
await createReleasePR({
318311
releaseType,
319312
dryRun,
320313
breaking,
314+
versionsHistory,
321315
});
322316
});
323317

scripts/release/__tests__/createReleasePR.test.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -283,22 +283,22 @@ describe('createReleasePR', () => {
283283
],
284284
});
285285

286-
expect(versions).toEqual({
287-
java: {
288-
current: '0.1.2',
289-
next: '0.2.0',
290-
releaseType: 'minor',
291-
},
292-
javascript: {
293-
current: '0.1.2',
294-
next: '0.2.0',
295-
releaseType: 'minor',
296-
},
297-
php: {
298-
current: '0.1.2',
299-
next: '0.2.0',
300-
releaseType: 'minor',
301-
},
286+
expect(versions.java).toEqual({
287+
current: '0.1.2',
288+
next: '0.2.0',
289+
releaseType: 'minor',
290+
});
291+
292+
expect(versions.javascript).toEqual({
293+
current: '0.1.2',
294+
next: '0.2.0',
295+
releaseType: 'minor',
296+
});
297+
298+
expect(versions.php).toEqual({
299+
current: '0.1.2',
300+
next: '0.2.0',
301+
releaseType: 'minor',
302302
});
303303
});
304304
});

scripts/release/__tests__/versionsHistory.test.ts

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,43 +20,65 @@ describe('generateLanguageVersionsHistory', () => {
2020
expect(versions).toEqual({
2121
'1.2.4': {
2222
releaseDate: '2023-12-28',
23+
eligibilityDate: undefined,
24+
eligibilityStatus: 'eligible',
2325
},
2426
'1.2.5': {
2527
releaseDate: '2024-01-02',
28+
eligibilityDate: undefined,
29+
eligibilityStatus: 'eligible',
2630
},
2731
'1.2.6': {
2832
releaseDate: '2024-01-02',
33+
eligibilityDate: undefined,
34+
eligibilityStatus: 'eligible',
2935
},
3036
'1.2.7': {
3137
releaseDate: '2024-01-04',
38+
eligibilityDate: undefined,
39+
eligibilityStatus: 'eligible',
3240
},
3341
});
3442
});
3543

3644
it('parses version of different same minor', () => {
3745
const versions = generateLanguageVersionsHistory(
3846
[
39-
'1.1.4 Thu Dec 28 15:48:25 2023 +0000',
40-
'1.2.5 Tue Jan 2 14:17:11 2024 +0000',
41-
'1.3.6 Tue Jan 2 15:26:06 2024 +0000',
42-
'1.4.7 Thu Jan 4 15:09:11 2024 +0000',
47+
'1.1.4 Thu Dec 28 15:48:25 2022 +0000',
48+
'2.1.2 Tue Jan 2 14:17:11 2022 +0000',
49+
'2.2.5 Tue Jan 2 14:17:11 2024 +0000',
50+
'2.3.6 Tue Jan 2 15:26:06 2024 +0000',
51+
'3.4.7 Thu Jan 4 15:09:11 2024 +0000',
4352
],
4453
'javascript',
45-
{ current: '1.4.7', next: null, releaseType: null },
54+
{ current: '3.4.7', next: null, releaseType: null },
4655
);
4756

4857
expect(versions).toEqual({
4958
'1.1.4': {
50-
releaseDate: '2023-12-28',
59+
releaseDate: '2022-12-28',
60+
eligibilityDate: undefined,
61+
eligibilityStatus: 'not eligible',
5162
},
52-
'1.2.5': {
63+
'2.1.2': {
64+
releaseDate: '2022-01-02',
65+
eligibilityDate: '2026-08-14',
66+
eligibilityStatus: 'replaced',
67+
},
68+
'2.2.5': {
5369
releaseDate: '2024-01-02',
70+
eligibilityDate: '2026-08-14',
71+
eligibilityStatus: 'replaced',
5472
},
55-
'1.3.6': {
73+
'2.3.6': {
5674
releaseDate: '2024-01-02',
75+
eligibilityDate: '2026-08-14',
76+
eligibilityStatus: 'replaced',
5777
},
58-
'1.4.7': {
78+
'3.4.7': {
5979
releaseDate: '2024-01-04',
80+
eligibilityDate: undefined,
81+
eligibilityStatus: 'eligible',
6082
},
6183
});
6284
});
@@ -77,6 +99,8 @@ describe('generateLanguageVersionsHistory', () => {
7799
expect(versions).toEqual({
78100
'1.2.4': {
79101
releaseDate: '2023-12-28',
102+
eligibilityDate: undefined,
103+
eligibilityStatus: 'eligible',
80104
},
81105
});
82106
});
@@ -91,9 +115,13 @@ describe('generateLanguageVersionsHistory', () => {
91115
expect(versions).toEqual({
92116
'1.2.4': {
93117
releaseDate: '2023-12-28',
118+
eligibilityDate: undefined,
119+
eligibilityStatus: 'eligible',
94120
},
95121
'2.0.0': {
96122
releaseDate: start.toISOString().split('T')[0],
123+
eligibilityDate: undefined,
124+
eligibilityStatus: 'eligible',
97125
},
98126
});
99127
});
@@ -108,9 +136,13 @@ describe('generateLanguageVersionsHistory', () => {
108136
expect(versions).toEqual({
109137
'1.2.4': {
110138
releaseDate: '2023-12-28',
139+
eligibilityDate: undefined,
140+
eligibilityStatus: 'eligible',
111141
},
112142
'1.3.0': {
113143
releaseDate: start.toISOString().split('T')[0],
144+
eligibilityDate: undefined,
145+
eligibilityStatus: 'eligible',
114146
},
115147
});
116148
});
@@ -125,9 +157,13 @@ describe('generateLanguageVersionsHistory', () => {
125157
expect(versions).toEqual({
126158
'1.2.4': {
127159
releaseDate: '2023-12-28',
160+
eligibilityDate: undefined,
161+
eligibilityStatus: 'eligible',
128162
},
129163
'1.2.5': {
130164
releaseDate: start.toISOString().split('T')[0],
165+
eligibilityDate: undefined,
166+
eligibilityStatus: 'eligible',
131167
},
132168
});
133169
});

scripts/release/createReleasePR.ts

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ export function decideReleaseStrategy({
204204
if (relevantCommits.length === 0) {
205205
console.log(` > Skipping, no commits found for ${lang}.`);
206206

207+
versionsToPublish[lang] = { current: currentVersion };
208+
207209
continue;
208210
}
209211

@@ -304,18 +306,20 @@ async function getCommits(force?: boolean): Promise<{
304306
/**
305307
* Ensure the release environment is correct before triggering.
306308
*/
307-
async function prepareGitEnvironment(): Promise<void> {
308-
ensureGitHubToken();
309+
async function prepareGitEnvironment(dryRun: boolean): Promise<void> {
310+
if (!dryRun) {
311+
ensureGitHubToken();
312+
}
309313

310-
if (CI) {
314+
if (CI && !dryRun) {
311315
await configureGitHubAuthor();
312316
}
313317

314-
if ((await run('git rev-parse --abbrev-ref HEAD')) !== MAIN_BRANCH) {
318+
if (!dryRun && (await run('git rev-parse --abbrev-ref HEAD')) !== MAIN_BRANCH) {
315319
throw new Error(`You can run this script only from \`${MAIN_BRANCH}\` branch.`);
316320
}
317321

318-
if (!process.env.FORCE && (await getNbGitDiff({ head: null })) !== 0) {
322+
if (!dryRun && !process.env.FORCE && (await getNbGitDiff({ head: null })) !== 0) {
319323
throw new Error('Working directory is not clean. Commit all the changes first.');
320324
}
321325

@@ -327,22 +331,25 @@ async function prepareGitEnvironment(): Promise<void> {
327331
console.log('Pulling from origin...');
328332
await run('git fetch origin');
329333
await run('git fetch --tags --force');
330-
await run('git pull origin $(git branch --show-current)');
334+
335+
if (!dryRun) {
336+
await run('git pull origin $(git branch --show-current)');
337+
}
331338
}
332339
}
333340

334341
export async function createReleasePR({
335342
releaseType,
336343
dryRun,
337344
breaking,
345+
versionsHistory,
338346
}: {
339347
releaseType?: semver.ReleaseType;
340348
dryRun?: boolean;
341349
breaking?: boolean;
350+
versionsHistory?: boolean;
342351
}): Promise<void> {
343-
if (!dryRun) {
344-
await prepareGitEnvironment();
345-
}
352+
await prepareGitEnvironment(dryRun || versionsHistory || false);
346353

347354
console.log('Searching for commits since last release...');
348355
const { validCommits, skippedCommits } = await getCommits(releaseType !== undefined);
@@ -351,6 +358,12 @@ export async function createReleasePR({
351358

352359
await generateVersionsHistory(versions);
353360

361+
if (versionsHistory) {
362+
console.log('Asked for a versions history refresh only, stopping here');
363+
364+
return;
365+
}
366+
354367
const versionChanges = getVersionChangesText(versions);
355368
const languages = Object.keys(versions).join(', ');
356369

scripts/release/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import type { Language } from '../types.js';
44

55
export type Version = {
66
current: string;
7-
releaseType: ReleaseType;
8-
next: string;
7+
releaseType?: ReleaseType;
8+
next?: string;
99
};
1010

1111
export type Versions = {

scripts/release/updateAPIVersions.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ export async function updateAPIVersions(versions: Versions, changelog: Changelog
4646
await updateConfigFiles(versions);
4747

4848
for (const [lang, { current, releaseType, next }] of Object.entries(versions)) {
49+
if (!next) {
50+
continue;
51+
}
52+
4953
if (lang === 'dart') {
5054
await updateDartPackages(changelog[lang]!, next);
5155

scripts/release/versionsHistory.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,20 @@ import type { Language } from '../types.js';
1010
import { preReleaseRegExp } from './createReleasePR.js';
1111
import type { Version, Versions } from './types.js';
1212

13+
// the date of the generated api clients release
14+
const generatedReleaseDate = new Date('2024-08-14');
15+
16+
// number of years of eligibility
17+
const eligibilityDuration = 2;
18+
const eligibilityEndDate = new Date(
19+
generatedReleaseDate.setFullYear(generatedReleaseDate.getFullYear() + eligibilityDuration),
20+
);
21+
22+
type Eligibility = {
23+
status: 'eligible' | 'not eligible' | 'replaced';
24+
date?: string;
25+
};
26+
1327
export function isPreRelease(version: string): boolean {
1428
return (
1529
version.match(preReleaseRegExp) !== null ||
@@ -21,6 +35,24 @@ export function isPreRelease(version: string): boolean {
2135
);
2236
}
2337

38+
function getCurrentMajor(version: string): int {
39+
return parseInt(version.match(/\d+/)[0]);
40+
}
41+
42+
function getEligibility(currentMajor: int, previousMajor: int, version: string, releaseDate: Date): Eligibility {
43+
const versionMajor = getCurrentMajor(version);
44+
45+
if (versionMajor == currentMajor) {
46+
return { status: 'eligible' };
47+
}
48+
49+
if (versionMajor == previousMajor && eligibilityEndDate >= new Date()) {
50+
return { status: 'replaced', date: eligibilityEndDate.toISOString().split('T')[0] };
51+
}
52+
53+
return { status: 'not eligible' };
54+
}
55+
2456
// fetches the git tags on the given `lang` repository, throws if none.
2557
async function getTags(lang: Language): Promise<string[]> {
2658
const githubToken = ensureGitHubToken();
@@ -56,8 +88,10 @@ export function generateLanguageVersionsHistory(
5688
lang: Language,
5789
version: Version,
5890
): Record<string, { releaseDate: string }> {
59-
const versions: Record<string, { releaseDate: string }> = {};
91+
const versions: Record<string, { releaseDate: string } & Eligibility> = {};
6092

93+
const currentMajor = getCurrentMajor(version.current);
94+
const previousMajor = currentMajor - 1 || currentMajor;
6195
let prevTagVersion = '';
6296

6397
for (const tag of tags) {
@@ -73,8 +107,12 @@ export function generateLanguageVersionsHistory(
73107
continue;
74108
}
75109

110+
const eligibility = getEligibility(currentMajor, previousMajor, tagVersion, new Date(tagReleaseDate));
111+
76112
versions[tagVersion] = {
77113
releaseDate: new Date(tagReleaseDate).toISOString().split('T')[0],
114+
eligibilityDate: eligibility.date,
115+
eligibilityStatus: eligibility.status,
78116
};
79117

80118
prevTagVersion = tagVersion;
@@ -84,6 +122,7 @@ export function generateLanguageVersionsHistory(
84122
if (version?.next && !isPreRelease(version?.next) && version?.next !== prevTagVersion) {
85123
versions[version.next] = {
86124
releaseDate: new Date().toISOString().split('T')[0],
125+
eligibilityStatus: 'eligible',
87126
};
88127
}
89128

0 commit comments

Comments
 (0)