Skip to content

Commit 38e9e76

Browse files
Copilotdibarbet
andcommitted
Add version helper and update snap tasks for new versioning scheme
Co-authored-by: dibarbet <5749229+dibarbet@users.noreply.github.com>
1 parent c01fc83 commit 38e9e76

File tree

5 files changed

+148
-5
lines changed

5 files changed

+148
-5
lines changed

jest.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const config: Config = {
1414
'<rootDir>/test/razor/razorIntegrationTests/jest.config.ts',
1515
'<rootDir>/test/razor/razorTests/jest.config.ts',
1616
'<rootDir>/test/untrustedWorkspace/integrationTests/jest.config.ts',
17+
'<rootDir>/test/tasks/jest.config.ts',
1718
],
1819
// Reporters are a global jest configuration property and cannot be set in the project jest config.
1920
// This configuration will create a 'junit.xml' file in the output directory, no matter which test project is running.

tasks/snapTasks.ts

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import * as os from 'os';
1010
import { exec } from 'child_process';
1111
import { promisify } from 'util';
1212
import { findTagsByVersion } from './gitTasks';
13+
import minimist from 'minimist';
1314

1415
const execAsync = promisify(exec);
1516

@@ -20,18 +21,51 @@ function logWarning(message: string, error?: unknown): void {
2021
}
2122
}
2223

24+
/**
25+
* Calculate the next release (stable) version from the current version.
26+
* Rounds up the minor version to the next tens version.
27+
* @param currentVersion The current version in "major.minor" format (e.g., "2.74")
28+
* @returns The next stable release version (e.g., "2.80")
29+
*/
30+
export function getNextReleaseVersion(currentVersion: string): string {
31+
const split = currentVersion.split('.');
32+
const major = parseInt(split[0]);
33+
const minor = parseInt(split[1]);
34+
35+
// Round up to the next tens version
36+
const nextTensMinor = Math.ceil((minor + 1) / 10) * 10;
37+
38+
return `${major}.${nextTensMinor}`;
39+
}
40+
2341
gulp.task('incrementVersion', async (): Promise<void> => {
42+
const argv = minimist(process.argv.slice(2));
43+
const isReleaseCandidate = argv['releaseCandidate'] === true || argv['releaseCandidate'] === 'true';
44+
2445
// Get the current version from version.json
2546
const versionFilePath = path.join(path.resolve(__dirname, '..'), 'version.json');
2647
const file = fs.readFileSync(versionFilePath, 'utf8');
2748
const versionJson = JSON.parse(file);
2849

29-
// Increment the minor version
50+
// Calculate new version
3051
const version = versionJson.version as string;
3152
const split = version.split('.');
32-
const newVersion = `${split[0]}.${parseInt(split[1]) + 1}`;
33-
34-
console.log(`Updating ${version} to ${newVersion}`);
53+
let newVersion: string;
54+
55+
if (isReleaseCandidate) {
56+
// If this is a release candidate, increment to be higher than the next stable version
57+
// e.g., if current is 2.74, next stable is 2.80, so main should be 2.81
58+
const nextStableVersion = getNextReleaseVersion(version);
59+
const stableSplit = nextStableVersion.split('.');
60+
newVersion = `${stableSplit[0]}.${parseInt(stableSplit[1]) + 1}`;
61+
console.log(
62+
`Release candidate mode: Updating ${version} to ${newVersion} (next stable would be ${nextStableVersion})`
63+
);
64+
} else {
65+
// Normal increment: just increment the minor version
66+
newVersion = `${split[0]}.${parseInt(split[1]) + 1}`;
67+
console.log(`Updating ${version} to ${newVersion}`);
68+
}
3569

3670
// Write the new version back to version.json
3771
versionJson.version = newVersion;
@@ -186,3 +220,27 @@ async function generatePRList(startSHA: string, endSHA: string): Promise<string[
186220
throw error;
187221
}
188222
}
223+
224+
/**
225+
* Update version.json to the next stable release version.
226+
* This task is used when snapping from prerelease to release.
227+
* It updates the version to round up to the next tens version (e.g., 2.74 -> 2.80).
228+
*/
229+
gulp.task('updateVersionForRelease', async (): Promise<void> => {
230+
// Get the current version from version.json
231+
const versionFilePath = path.join(path.resolve(__dirname, '..'), 'version.json');
232+
const file = fs.readFileSync(versionFilePath, 'utf8');
233+
const versionJson = JSON.parse(file);
234+
235+
const currentVersion = versionJson.version as string;
236+
const releaseVersion = getNextReleaseVersion(currentVersion);
237+
238+
console.log(`Updating version from ${currentVersion} to stable release version ${releaseVersion}`);
239+
240+
// Write the new version back to version.json
241+
versionJson.version = releaseVersion;
242+
const newJson = JSON.stringify(versionJson, null, 4);
243+
console.log(`New json: ${newJson}`);
244+
245+
fs.writeFileSync(versionFilePath, newJson);
246+
});

tasks/testTasks.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { jestOmniSharpUnitTestProjectName } from '../test/omnisharp/omnisharpUni
1212
import { jestUnitTestProjectName } from '../test/lsptoolshost/unitTests/jest.config';
1313
import { razorTestProjectName } from '../test/razor/razorTests/jest.config';
1414
import { jestArtifactTestsProjectName } from '../test/lsptoolshost/artifactTests/jest.config';
15+
import { jestTasksTestProjectName } from '../test/tasks/jest.config';
1516
import {
1617
getJUnitFileName,
1718
integrationTestProjects,
@@ -46,7 +47,11 @@ function createUnitTestSubTasks() {
4647
await runJestTest(razorTestProjectName);
4748
});
4849

49-
gulp.task('test:unit', gulp.series('test:unit:csharp', 'test:unit:razor'));
50+
gulp.task('test:unit:tasks', async () => {
51+
await runJestTest(jestTasksTestProjectName);
52+
});
53+
54+
gulp.task('test:unit', gulp.series('test:unit:csharp', 'test:unit:razor', 'test:unit:tasks'));
5055
}
5156

5257
function createIntegrationTestSubTasks() {

test/tasks/jest.config.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
import type { Config } from 'jest';
6+
import { baseProjectConfig } from '../../baseJestConfig';
7+
8+
export const jestTasksTestProjectName = 'Tasks Unit Tests';
9+
10+
/**
11+
* Defines a jest project configuration for tasks unit tests.
12+
*/
13+
const tasksTestConfig: Config = {
14+
...baseProjectConfig,
15+
displayName: jestTasksTestProjectName,
16+
modulePathIgnorePatterns: ['out'],
17+
roots: ['<rootDir>', '<rootDir>../../__mocks__'],
18+
};
19+
20+
export default tasksTestConfig;

test/tasks/versionHelper.test.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { getNextReleaseVersion } from '../../tasks/snapTasks';
7+
import { describe, test, expect } from '@jest/globals';
8+
9+
describe('getNextReleaseVersion', () => {
10+
test('rounds up to next tens from single digit minor version', () => {
11+
expect(getNextReleaseVersion('2.1')).toBe('2.10');
12+
expect(getNextReleaseVersion('2.5')).toBe('2.10');
13+
expect(getNextReleaseVersion('2.9')).toBe('2.10');
14+
});
15+
16+
test('rounds up to next tens from teens minor version', () => {
17+
expect(getNextReleaseVersion('2.10')).toBe('2.20');
18+
expect(getNextReleaseVersion('2.15')).toBe('2.20');
19+
expect(getNextReleaseVersion('2.19')).toBe('2.20');
20+
});
21+
22+
test('rounds up to next tens from twenties minor version', () => {
23+
expect(getNextReleaseVersion('2.20')).toBe('2.30');
24+
expect(getNextReleaseVersion('2.25')).toBe('2.30');
25+
expect(getNextReleaseVersion('2.29')).toBe('2.30');
26+
});
27+
28+
test('rounds up from 74 to 80', () => {
29+
expect(getNextReleaseVersion('2.74')).toBe('2.80');
30+
});
31+
32+
test('rounds up from 75 to 80', () => {
33+
expect(getNextReleaseVersion('2.75')).toBe('2.80');
34+
});
35+
36+
test('rounds up from 79 to 80', () => {
37+
expect(getNextReleaseVersion('2.79')).toBe('2.80');
38+
});
39+
40+
test('rounds up from 80 to 90', () => {
41+
expect(getNextReleaseVersion('2.80')).toBe('2.90');
42+
});
43+
44+
test('rounds up from 90 to 100', () => {
45+
expect(getNextReleaseVersion('2.90')).toBe('2.100');
46+
});
47+
48+
test('works with different major versions', () => {
49+
expect(getNextReleaseVersion('1.74')).toBe('1.80');
50+
expect(getNextReleaseVersion('3.55')).toBe('3.60');
51+
expect(getNextReleaseVersion('10.99')).toBe('10.100');
52+
});
53+
54+
test('handles version at exactly tens boundary', () => {
55+
expect(getNextReleaseVersion('2.10')).toBe('2.20');
56+
expect(getNextReleaseVersion('2.20')).toBe('2.30');
57+
expect(getNextReleaseVersion('2.30')).toBe('2.40');
58+
});
59+
});

0 commit comments

Comments
 (0)