Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: prevent duplicate version compute in release #656

Merged
merged 1 commit into from
Jun 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 32 additions & 31 deletions scripts/release/__tests__/updateAPIVersions.test.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,48 @@
import { getVersionChangesText } from '../createReleasePR';
import TEXT from '../text';
import { getVersionsToRelease } from '../updateAPIVersions';

describe('updateAPIversions', () => {
it('gets versions to release', () => {
const versions = getVersionsToRelease(`
## Version Changes

- javascript: 1.0.0 -> **\`minor\` _(e.g. 1.1.0)_**
- ~java: 3.0.0 -> **\`patch\` _(e.g. 3.0.1)_**~
- No \`feat\` or \`fix\` commit, thus unchecked by default.
- php: 2.0.0 -> **\`patch\` _(e.g. 2.0.1)_**
`);
const versions = getVersionsToRelease({
javascript: {
current: '1.0.0',
releaseType: 'minor',
},
php: {
current: '2.0.0',
releaseType: 'patch',
},
java: {
current: '3.0.0',
releaseType: null,
noCommit: true,
skipRelease: true,
},
});

expect(Object.keys(versions)).toEqual(['javascript', 'php']);
expect(versions.java).toBeUndefined();
expect(versions.javascript?.current).toEqual('1.0.0');
expect(versions.javascript?.releaseType).toEqual('minor');
expect(versions.php?.current).toEqual('2.0.0');
expect(versions.php?.releaseType).toEqual('patch');
});

it('correctly reads clients version and their next release type', () => {
// This test is a glue between createReleasePR and updateAPIVersions.
const issueBody = [
TEXT.versionChangeHeader,
getVersionChangesText({
javascript: {
current: '0.0.1',
releaseType: 'patch',
},
php: {
current: '0.0.1',
releaseType: 'minor',
},
java: {
current: '0.0.1',
releaseType: 'patch',
skipRelease: true,
},
}),
].join('\n');

const versions = getVersionsToRelease(issueBody);
const versions = getVersionsToRelease({
javascript: {
current: '0.0.1',
releaseType: 'patch',
},
php: {
current: '0.0.1',
releaseType: 'minor',
},
java: {
current: '0.0.1',
releaseType: 'patch',
skipRelease: true,
},
});
expect(versions).toEqual({
javascript: expect.objectContaining({
current: '0.0.1',
Expand Down
2 changes: 1 addition & 1 deletion scripts/release/createReleasePR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ async function createReleasePR(): Promise<void> {
const headBranch = `chore/prepare-release-${TODAY}`;

console.log('Updating config files...');
await updateAPIVersions(versionChanges, changelog, headBranch);
await updateAPIVersions(versions, changelog, headBranch);

console.log('Creating pull request...');
const octokit = getOctokit();
Expand Down
3 changes: 1 addition & 2 deletions scripts/release/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ export type Commit =
| { error: 'unknown-language-scope' };

export type VersionsToRelease = {
[lang in Language]?: {
current: string;
[lang in Language]?: Pick<Version, 'current' | 'next'> & {
releaseType: ReleaseType;
};
};
Expand Down
66 changes: 30 additions & 36 deletions scripts/release/updateAPIVersions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
} from '../config';
import type { Language } from '../types';

import type { Changelog, VersionsToRelease } from './types';
import type { Changelog, Versions, VersionsToRelease } from './types';

dotenv.config({ path: ROOT_ENV_PATH });

Expand Down Expand Up @@ -95,18 +95,21 @@ async function updateConfigFiles(
if (lang === 'javascript' || !versionsToRelease[lang]) {
return;
}

const releaseType = versionsToRelease[lang]!.releaseType;
const nextVersion = versionsToRelease[lang]!.next;

const newVersion = semver.inc(getPackageVersionDefault(lang), releaseType);
if (!newVersion) {
if (!nextVersion) {
throw new Error(
`Failed to bump version ${getPackageVersionDefault(
lang
)} by ${releaseType}.`
);
}
clientsConfig[lang].packageVersion = newVersion;

clientsConfig[lang].packageVersion = nextVersion;
});

await fsp.writeFile(
toAbsolutePath('config/clients.config.json'),
JSON.stringify(clientsConfig, null, 2)
Expand Down Expand Up @@ -139,50 +142,43 @@ async function updateChangelog({
);
}

export function getVersionsToRelease(
versionChanges: string
): VersionsToRelease {
export function getVersionsToRelease(versions: Versions): VersionsToRelease {
const versionsToRelease: VersionsToRelease = {};

versionChanges.split('\n').forEach((line) => {
// This character means we've skipped the release of this language
if (line.includes('~')) {
return;
}

// example of string to match:
// - javascript: 0.0.1 -> **`patch` _(e.g. 0.0.2)_**
// ^ ^ ^
const result = line.match(/- (.+): (.+) -> \*\*`(.+)`/);
Object.entries(versions).forEach(
([lang, { noCommit, current, skipRelease, releaseType }]) => {
if (noCommit || skipRelease || !current) {
return;
}

if (!result) {
return;
}
if (
!releaseType ||
!['major', 'minor', 'patch', 'prerelease'].includes(releaseType)
) {
throw new Error(
`\`${releaseType}\` is unknown release type. Allowed: major, minor, patch, prerelease`
);
}

const [, lang, current, releaseType] = result;
if (!['major', 'minor', 'patch', 'prerelease'].includes(releaseType)) {
throw new Error(
`\`${releaseType}\` is unknown release type. Allowed: major, minor, patch, prerelease`
);
versionsToRelease[lang] = {
current,
releaseType,
};
}
versionsToRelease[lang] = {
current,
releaseType,
};
});
);

return versionsToRelease;
}

/**
* Updates the changelogs and the config files containing versions of the API clients, then pushes the changes to the `headBranch`.
*
* @param versionChanges - A summary of the version changes, with their new version.
* @param versions - A summary of the version changes, with their new version and release type.
* @param changelog - The changelog of all the languages, which is generated by `createReleasePR`.
* @param headBranch - The branch to push the changes to.
*/
export async function updateAPIVersions(
versionChanges: string,
versions: Versions,
changelog: Changelog,
headBranch: string
): Promise<void> {
Expand All @@ -193,11 +189,11 @@ export async function updateAPIVersions(

await run(`git checkout -b ${headBranch}`);

const versionsToRelease = getVersionsToRelease(versionChanges);
const versionsToRelease = getVersionsToRelease(versions);

await updateConfigFiles(versionsToRelease);

for (const [lang, { current, releaseType }] of Object.entries(
for (const [lang, { current, releaseType, next }] of Object.entries(
versionsToRelease
)) {
/*
Expand All @@ -221,8 +217,6 @@ export async function updateAPIVersions(
);
}

const next = semver.inc(current, releaseType);

await updateChangelog({
lang: lang as Language,
changelog,
Expand Down