From 65296dd7c6d346b80f4c9c607f3a33b1d9010d6b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Vannicatte?=
Date: Wed, 25 May 2022 11:38:42 +0200
Subject: [PATCH 1/2] fix(scripts): update release PR and process
---
.github/actions/setup/action.yml | 2 +-
.github/workflows/check.yml | 2 +-
package.json | 2 +-
scripts/common.ts | 2 +-
scripts/package.json | 2 +-
...lease-issue.test.ts => createReleasePR.ts} | 182 ++++++++++++------
...s-release.test.ts => updateAPIVersions.ts} | 10 +-
...te-release-issue.ts => createReleasePR.ts} | 75 +++++---
...rocess-release.ts => updateAPIVersions.ts} | 23 ++-
website/docs/automation/release-process.md | 16 +-
10 files changed, 200 insertions(+), 116 deletions(-)
rename scripts/release/__tests__/{create-release-issue.test.ts => createReleasePR.ts} (67%)
rename scripts/release/__tests__/{process-release.test.ts => updateAPIVersions.ts} (81%)
rename scripts/release/{create-release-issue.ts => createReleasePR.ts} (87%)
rename scripts/release/{process-release.ts => updateAPIVersions.ts} (92%)
diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml
index cdbf17e5ddc..97a8a23463b 100644
--- a/.github/actions/setup/action.yml
+++ b/.github/actions/setup/action.yml
@@ -78,7 +78,7 @@ runs:
shell: bash
run: |
previousCommit=${{ github.event.before }}
- baseRef=${{ inputs.workflow_name == 'process-release' && 'main' || github.base_ref }}
+ baseRef=${{ github.base_ref }}
origin=$( [[ -z $baseRef ]] && echo $previousCommit || echo "origin/$baseRef" )
yarn workspace scripts setRunVariables "$origin"
diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml
index b0fda5f0ded..cddd95fedee 100644
--- a/.github/workflows/check.yml
+++ b/.github/workflows/check.yml
@@ -230,7 +230,7 @@ jobs:
run: yarn cli cts run ${{ matrix.client.language }}
- name: Zip artifact before storing
- run: zip -q -r clients-${{ matrix.client.language }}.zip ${{ matrix.client.path }} ${{ matrix.client.testsOutputPath }} -x "${{ matrix.client.path }}/node_modules/.**"
+ run: zip -r -y clients-${{ matrix.client.language }}.zip ${{ matrix.client.path }} ${{ matrix.client.testsOutputPath }} -x "**/node_modules/**" "**/node_modules/.**" "clients/algoliasearch-client-javascript/.yarn/**"
- name: Store ${{ matrix.client.language }} clients
uses: actions/upload-artifact@v3
diff --git a/package.json b/package.json
index ccf8efb422c..ce2ac2ca664 100644
--- a/package.json
+++ b/package.json
@@ -24,7 +24,7 @@
"github-actions:lint": "eslint --ext=yml .github/",
"postinstall": "husky install && yarn workspace eslint-plugin-automation-custom build",
"playground:browser": "yarn workspace javascript-browser-playground start",
- "release": "yarn workspace scripts createReleaseIssue",
+ "release": "yarn workspace scripts createReleasePR",
"scripts:lint": "eslint --ext=ts scripts/",
"scripts:test": "yarn workspace scripts test",
"specs:fix": "eslint --ext=yml specs/$0 --fix",
diff --git a/scripts/common.ts b/scripts/common.ts
index 45d4c209e9a..a2b01bcaa1b 100644
--- a/scripts/common.ts
+++ b/scripts/common.ts
@@ -272,7 +272,7 @@ export function ensureGitHubToken(): string {
export function getOctokit(): Octokit {
const token = ensureGitHubToken();
return new Octokit({
- auth: `token ${token}`,
+ auth: token,
});
}
diff --git a/scripts/package.json b/scripts/package.json
index 9eb37afa2cf..aad518a8246 100644
--- a/scripts/package.json
+++ b/scripts/package.json
@@ -4,7 +4,7 @@
"scripts": {
"cleanGeneratedBranch": "ts-node ci/codegen/cleanGeneratedBranch.ts",
"createMatrix": "ts-node ci/githubActions/createMatrix.ts",
- "createReleaseIssue": "ts-node release/create-release-issue.ts",
+ "createReleasePR": "ts-node release/createReleasePR.ts",
"pre-commit": "./ci/husky/pre-commit.js",
"pushGeneratedCode": "ts-node ci/codegen/pushGeneratedCode.ts",
"renovateWeeklyPR": "ts-node ci/githubActions/renovateWeeklyPR.ts",
diff --git a/scripts/release/__tests__/create-release-issue.test.ts b/scripts/release/__tests__/createReleasePR.ts
similarity index 67%
rename from scripts/release/__tests__/create-release-issue.test.ts
rename to scripts/release/__tests__/createReleasePR.ts
index 1b2fc4c68cb..bff5c8b5881 100644
--- a/scripts/release/__tests__/create-release-issue.test.ts
+++ b/scripts/release/__tests__/createReleasePR.ts
@@ -5,9 +5,9 @@ import {
getSkippedCommitsText,
decideReleaseStrategy,
readVersions,
-} from '../create-release-issue';
+} from '../createReleasePR';
-describe('create release issue', () => {
+describe('createReleasePR', () => {
it('reads versions of the current language', () => {
expect(readVersions()).toEqual({
java: {
@@ -92,10 +92,10 @@ describe('create release issue', () => {
},
})
).toMatchInlineSnapshot(`
- "- javascript: 0.0.1 -> **\`patch\` _(e.g. 0.0.2)_**
- - java: 0.0.1 -> **\`patch\` _(e.g. 0.0.2)_**
- - php: 0.0.1 -> **\`patch\` _(e.g. 0.0.2)_**"
- `);
+ "- javascript: 0.0.1 -> **\`patch\` _(e.g. 0.0.2)_**
+ - java: 0.0.1 -> **\`patch\` _(e.g. 0.0.2)_**
+ - php: 0.0.1 -> **\`patch\` _(e.g. 0.0.2)_**"
+ `);
});
it('generates text for version changes with a language with no commit', () => {
@@ -118,10 +118,10 @@ describe('create release issue', () => {
},
})
).toMatchInlineSnapshot(`
- "- javascript: 0.0.1 -> **\`patch\` _(e.g. 0.0.2)_**
- - java: 0.0.1 -> **\`patch\` _(e.g. 0.0.2)_**
- - ~php: 0.0.1 (no commit)~"
- `);
+ "- javascript: 0.0.1 -> **\`patch\` _(e.g. 0.0.2)_**
+ - java: 0.0.1 -> **\`patch\` _(e.g. 0.0.2)_**
+ - ~php: 0.0.1 (no commit)~"
+ `);
});
it('generates text for version changes with a language to skip', () => {
@@ -144,11 +144,11 @@ describe('create release issue', () => {
},
})
).toMatchInlineSnapshot(`
- "- javascript: 0.0.1 -> **\`patch\` _(e.g. 0.0.2)_**
- - ~java: 0.0.1 -> **\`patch\` _(e.g. 0.0.2)_**~
- - No \`feat\` or \`fix\` commit, thus unchecked by default.
- - php: 0.0.1 -> **\`minor\` _(e.g. 0.1.0)_**"
- `);
+ "- javascript: 0.0.1 -> **\`patch\` _(e.g. 0.0.2)_**
+ - ~java: 0.0.1 -> **\`patch\` _(e.g. 0.0.2)_**~
+ - No \`feat\` or \`fix\` commit, thus unchecked by default.
+ - php: 0.0.1 -> **\`minor\` _(e.g. 0.1.0)_**"
+ `);
});
});
@@ -363,47 +363,117 @@ describe('create release issue', () => {
});
});
- it('generates text for skipped commits', () => {
- expect(
- getSkippedCommitsText({
- commitsWithoutLanguageScope: [],
- commitsWithUnknownLanguageScope: [],
- })
- ).toMatchInlineSnapshot(`"_(None)_"`);
-
- expect(
- getSkippedCommitsText({
- commitsWithoutLanguageScope: [
- 'abcdefg fix: something',
- 'abcdefg fix: somethin2',
- ],
+ describe('getSkippedCommitsText', () => {
+ it('does not generate text if there is no commits', () => {
+ expect(
+ getSkippedCommitsText({
+ commitsWithoutLanguageScope: [],
+ commitsWithUnknownLanguageScope: [],
+ })
+ ).toMatchInlineSnapshot(`"_(None)_"`);
+ });
- commitsWithUnknownLanguageScope: [
- 'abcdef2 fix(pascal): what',
- 'abcdef2 fix(pascal): what is that',
- ],
- })
- ).toMatchInlineSnapshot(`
- "
- It doesn't mean these commits are being excluded from the release. It means they're not taken into account when the release process figured out the next version number, and updated the changelog.
-
-
-
- Commits without language scope:
-
-
- - abcdefg fix: something
- - abcdefg fix: somethin2
-
-
-
-
- Commits with unknown language scope:
-
-
- - abcdef2 fix(pascal): what
- - abcdef2 fix(pascal): what is that
- "
- `);
+ it('generates text for skipped commits', () => {
+ expect(
+ getSkippedCommitsText({
+ commitsWithoutLanguageScope: [
+ 'abcdefg fix: something',
+ 'abcdefg fix: somethin2',
+ ],
+
+ commitsWithUnknownLanguageScope: [
+ 'abcdef2 fix(pascal): what',
+ 'abcdef2 fix(pascal): what is that',
+ ],
+ })
+ ).toMatchInlineSnapshot(`
+ "
+ It doesn't mean these commits are being excluded from the release. It means they're not taken into account when the release process figured out the next version number, and updated the changelog.
+
+
+
+ Commits without language scope:
+
+
+ - abcdefg fix: something
+ - abcdefg fix: somethin2
+
+
+
+
+ Commits with unknown language scope:
+
+
+ - abcdef2 fix(pascal): what
+ - abcdef2 fix(pascal): what is that
+ "
+ `);
+ });
+
+ it('limits the size of the commits to 15 if there is too many', () => {
+ const fakeCommitsWithoutLanguageScope: string[] = [];
+ const fakeCommitsWithUnknownLanguageScope: string[] = [];
+
+ for (let i = 0; i < 100; i++) {
+ fakeCommitsWithoutLanguageScope.push(`abcdefg${i} fix: something`);
+ fakeCommitsWithUnknownLanguageScope.push(
+ `abcdefg${i} fix(pascal): something`
+ );
+ }
+
+ expect(
+ getSkippedCommitsText({
+ commitsWithoutLanguageScope: fakeCommitsWithoutLanguageScope,
+ commitsWithUnknownLanguageScope: fakeCommitsWithUnknownLanguageScope,
+ })
+ ).toMatchInlineSnapshot(`
+ "
+ It doesn't mean these commits are being excluded from the release. It means they're not taken into account when the release process figured out the next version number, and updated the changelog.
+
+
+
+ Commits without language scope:
+
+
+ - abcdefg0 fix: something
+ - abcdefg1 fix: something
+ - abcdefg2 fix: something
+ - abcdefg3 fix: something
+ - abcdefg4 fix: something
+ - abcdefg5 fix: something
+ - abcdefg6 fix: something
+ - abcdefg7 fix: something
+ - abcdefg8 fix: something
+ - abcdefg9 fix: something
+ - abcdefg10 fix: something
+ - abcdefg11 fix: something
+ - abcdefg12 fix: something
+ - abcdefg13 fix: something
+ - abcdefg14 fix: something
+
+
+
+
+ Commits with unknown language scope:
+
+
+ - abcdefg0 fix(pascal): something
+ - abcdefg1 fix(pascal): something
+ - abcdefg2 fix(pascal): something
+ - abcdefg3 fix(pascal): something
+ - abcdefg4 fix(pascal): something
+ - abcdefg5 fix(pascal): something
+ - abcdefg6 fix(pascal): something
+ - abcdefg7 fix(pascal): something
+ - abcdefg8 fix(pascal): something
+ - abcdefg9 fix(pascal): something
+ - abcdefg10 fix(pascal): something
+ - abcdefg11 fix(pascal): something
+ - abcdefg12 fix(pascal): something
+ - abcdefg13 fix(pascal): something
+ - abcdefg14 fix(pascal): something
+ "
+ `);
+ });
});
});
diff --git a/scripts/release/__tests__/process-release.test.ts b/scripts/release/__tests__/updateAPIVersions.ts
similarity index 81%
rename from scripts/release/__tests__/process-release.test.ts
rename to scripts/release/__tests__/updateAPIVersions.ts
index 379201916eb..de2e8d95293 100644
--- a/scripts/release/__tests__/process-release.test.ts
+++ b/scripts/release/__tests__/updateAPIVersions.ts
@@ -1,8 +1,8 @@
-import { getVersionChangesText } from '../create-release-issue';
-import { getVersionsToRelease } from '../process-release';
+import { getVersionChangesText } from '../createReleasePR';
import TEXT from '../text';
+import { getVersionsToRelease } from '../updateAPIVersions';
-describe('process release', () => {
+describe('updateAPIversions', () => {
it('gets versions to release', () => {
const versions = getVersionsToRelease(`
## Version Changes
@@ -20,8 +20,8 @@ describe('process release', () => {
expect(versions.php?.releaseType).toEqual('patch');
});
- it('parses issue body correctly', () => {
- // This test is a glue between create-release-issue and process-release.
+ it('correctly reads clients version and their next release type', () => {
+ // This test is a glue between createReleasePR and updateAPIVersions.
const issueBody = [
TEXT.versionChangeHeader,
getVersionChangesText({
diff --git a/scripts/release/create-release-issue.ts b/scripts/release/createReleasePR.ts
similarity index 87%
rename from scripts/release/create-release-issue.ts
rename to scripts/release/createReleasePR.ts
index 6624ee59219..2504131bde9 100755
--- a/scripts/release/create-release-issue.ts
+++ b/scripts/release/createReleasePR.ts
@@ -19,7 +19,6 @@ import {
import { getPackageVersionDefault } from '../config';
import { RELEASED_TAG } from './common';
-import { processRelease } from './process-release';
import TEXT from './text';
import type {
Versions,
@@ -29,6 +28,7 @@ import type {
Scope,
Changelog,
} from './types';
+import { updateAPIVersions } from './updateAPIVersions';
dotenv.config({ path: ROOT_ENV_PATH });
@@ -79,7 +79,10 @@ export function getSkippedCommitsText({
return '_(None)_';
}
- return `
+ // GitHub API restrict the size of a PR body, if we send too many commits
+ // we might end up with 502 errors when trying to send the pull request
+ // So we limit the size of the missed commits
+ return `
${TEXT.skippedCommitsDesc}
@@ -87,7 +90,10 @@ export function getSkippedCommitsText({
Commits without language scope:
- ${commitsWithoutLanguageScope.map((commit) => `- ${commit}`).join('\n')}
+ ${commitsWithoutLanguageScope
+ .slice(0, 15)
+ .map((commit) => `- ${commit}`)
+ .join('\n')}
@@ -95,7 +101,10 @@ export function getSkippedCommitsText({
Commits with unknown language scope:
- ${commitsWithUnknownLanguageScope.map((commit) => `- ${commit}`).join('\n')}
+ ${commitsWithUnknownLanguageScope
+ .slice(0, 15)
+ .map((commit) => `- ${commit}`)
+ .join('\n')}
`;
}
@@ -270,7 +279,7 @@ async function getCommits(): Promise<{
};
}
-async function createReleaseIssue(): Promise {
+async function createReleasePR(): Promise {
ensureGitHubToken();
if (!process.env.LOCAL_TEST_DEV) {
@@ -336,38 +345,42 @@ async function createReleaseIssue(): Promise {
const headBranch = `chore/prepare-release-${TODAY}`;
console.log('Updating config files...');
- await processRelease(versionChanges, changelog, headBranch);
+ await updateAPIVersions(versionChanges, changelog, headBranch);
console.log('Creating pull request...');
const octokit = getOctokit();
- try {
- const {
- data: { number, html_url: url },
- } = await octokit.rest.pulls.create({
- owner: OWNER,
- repo: REPO,
- title: `chore: prepare release ${TODAY}`,
- body: [
- TEXT.header,
- TEXT.summary,
- TEXT.versionChangeHeader,
- versionChanges,
- TEXT.skippedCommitsHeader,
- skippedCommits,
- ].join('\n\n'),
- base: 'main',
- head: headBranch,
- });
-
- console.log(`Release PR #${number} is ready for review.`);
- console.log(` > ${url}`);
- } catch (e) {
- throw new Error(`Unable to create the release PR: ${e}`);
- }
+ const {
+ data: { number, html_url: url },
+ } = await octokit.pulls.create({
+ owner: OWNER,
+ repo: REPO,
+ title: `chore: prepare release ${TODAY}`,
+ body: [
+ TEXT.header,
+ TEXT.summary,
+ TEXT.versionChangeHeader,
+ versionChanges,
+ TEXT.skippedCommitsHeader,
+ skippedCommits,
+ ].join('\n\n'),
+ base: 'main',
+ head: headBranch,
+ });
+
+ console.log('Assigning team members to the PR...');
+ await octokit.pulls.requestReviewers({
+ owner: OWNER,
+ repo: REPO,
+ pull_number: number,
+ team_reviewers: ['api-clients-automation'],
+ });
+
+ console.log(`Release PR #${number} is ready for review.`);
+ console.log(` > ${url}`);
}
// JS version of `if __name__ == '__main__'`
if (require.main === module) {
- createReleaseIssue();
+ createReleasePR();
}
diff --git a/scripts/release/process-release.ts b/scripts/release/updateAPIVersions.ts
similarity index 92%
rename from scripts/release/process-release.ts
rename to scripts/release/updateAPIVersions.ts
index d639996a735..606f5400c70 100755
--- a/scripts/release/process-release.ts
+++ b/scripts/release/updateAPIVersions.ts
@@ -174,13 +174,13 @@ export function getVersionsToRelease(
}
/**
- * Updates the changelogs and the config files containing versions of the API clients.
+ * 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 changelog - The changelog of all the languages, which is generated by `create-release-issue`.
+ * @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 processRelease(
+export async function updateAPIVersions(
versionChanges: string,
changelog: Changelog,
headBranch: string
@@ -230,12 +230,17 @@ export async function processRelease(
});
}
- console.log(`Pushing updated configs to ${headBranch}`);
- await run(`git add .`, { verbose: true });
- await run(
- `CI=true git commit -m "${headBranch.replace('chore/', 'chore: ')}"`,
- { verbose: true }
- );
+ console.log(`Pushing updated changes to ${headBranch}`);
+ const commitMessage = headBranch.replace('chore/', 'chore: ');
+ await run(`git add clients config`, { verbose: true });
+ if (process.env.LOCAL_TEST_DEV) {
+ await run(`CI=true git commit -m "${commitMessage} [skip ci]"`, {
+ verbose: true,
+ });
+ } else {
+ await run(`CI=true git commit -m "${commitMessage}"`, { verbose: true });
+ }
+
await run(`git push origin ${headBranch}`, { verbose: true });
await run(`git checkout ${MAIN_BRANCH}`, { verbose: true });
}
diff --git a/website/docs/automation/release-process.md b/website/docs/automation/release-process.md
index 36b87c9d726..73cac73ce55 100644
--- a/website/docs/automation/release-process.md
+++ b/website/docs/automation/release-process.md
@@ -18,24 +18,20 @@ Once setup, you can run:
yarn release
```
-It will create [a release issue](https://github.com/algolia/api-clients-automation/issues/407).
+It will create [a release PR](https://github.com/algolia/api-clients-automation/pull/545).
-## 2. Review the release issue.
+## 2. Review the release PR.
-You need to review the release issue, in two parts:
+You need to review the release PR, in two parts:
1. version changes
2. CHANGELOGs
-Any changes applied in the issue will be taken into account by the release process.
+You need approval from a member of the [`@algolia/api-clients-automation`](https://github.com/orgs/algolia/teams/api-clients-automation) team to release clients.
-You need approval from a member of the [`@algolia/api-clients-automation`](https://github.com/orgs/algolia/teams/api-clients-automation) team to release clients. Commenting "approved" will close the issue and trigger [the release action](#3-the-release-action).
+## 3. The release process.
-## 3. The release action.
-
-The [GitHub action release](https://github.com/algolia/api-clients-automation/blob/main/.github/workflows/process-release.yml) is triggered. It generates clients and push changes to each language repository on their `next` branch.
-
-This part runs conditionally according to what has been done in [the issue review](#2-review-the-release-issue). Under "Version Changes" section of the release issue, if a language is checked, this part will creates a commit like `chore: release v` in each repository. If it is not checked, it will create a commit like `chore: update repo `.
+After a full CI run, a release commit will be sent to every repository and spread changes to their `next` branch.
Each language repository should have their own release process, and should run only when the latest commit starts with `chore: release`. By doing so, we have a way to just update the repository, for example READMEs, without having to release.
From 597135130a9b273ba4a9456927266daac1ca724d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Vannicatte?=
Date: Wed, 25 May 2022 13:30:06 +0200
Subject: [PATCH 2/2] fix test filenames
---
.../__tests__/{createReleasePR.ts => createReleasePR.test.ts} | 0
.../__tests__/{updateAPIVersions.ts => updateAPIVersions.test.ts} | 0
2 files changed, 0 insertions(+), 0 deletions(-)
rename scripts/release/__tests__/{createReleasePR.ts => createReleasePR.test.ts} (100%)
rename scripts/release/__tests__/{updateAPIVersions.ts => updateAPIVersions.test.ts} (100%)
diff --git a/scripts/release/__tests__/createReleasePR.ts b/scripts/release/__tests__/createReleasePR.test.ts
similarity index 100%
rename from scripts/release/__tests__/createReleasePR.ts
rename to scripts/release/__tests__/createReleasePR.test.ts
diff --git a/scripts/release/__tests__/updateAPIVersions.ts b/scripts/release/__tests__/updateAPIVersions.test.ts
similarity index 100%
rename from scripts/release/__tests__/updateAPIVersions.ts
rename to scripts/release/__tests__/updateAPIVersions.test.ts