From 4bf47388b4edf8edb0c5c60d9b5e2a978539c3ed Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Tue, 15 Mar 2022 17:16:19 +0100 Subject: [PATCH 01/14] chore(ci): push to each repository on PR merge --- .github/workflows/codegen-cleanup.yml | 5 ++ .../__tests__/spreadGeneration.test.ts | 32 +++++++++ scripts/ci/codegen/spreadGeneration.ts | 69 +++++++++++++++++++ scripts/common.ts | 12 ++++ scripts/package.json | 1 + scripts/release/common.ts | 29 +++++++- scripts/release/process-release.ts | 30 ++++---- 7 files changed, 162 insertions(+), 16 deletions(-) create mode 100644 scripts/ci/codegen/__tests__/spreadGeneration.test.ts create mode 100644 scripts/ci/codegen/spreadGeneration.ts diff --git a/.github/workflows/codegen-cleanup.yml b/.github/workflows/codegen-cleanup.yml index bd5f198ffb..f1a80b140e 100644 --- a/.github/workflows/codegen-cleanup.yml +++ b/.github/workflows/codegen-cleanup.yml @@ -17,5 +17,10 @@ jobs: - name: Setup uses: ./.github/actions/setup + - name: Spread generation to each repository + run: yarn workspace scripts spreadGeneration $${{ github.head_ref }} + env: + GITHUB_TOKEN: ${{ secrets.TOKEN_RELEASE_BOT }} + - name: Clean previously generated branch run: yarn workspace scripts cleanGeneratedBranch ${{ github.head_ref }} diff --git a/scripts/ci/codegen/__tests__/spreadGeneration.test.ts b/scripts/ci/codegen/__tests__/spreadGeneration.test.ts new file mode 100644 index 0000000000..f168a681cb --- /dev/null +++ b/scripts/ci/codegen/__tests__/spreadGeneration.test.ts @@ -0,0 +1,32 @@ +import { LANGUAGES } from '../../../common'; +import { decideWhereToSpread, cleanUpCommitMessage } from '../spreadGeneration'; + +describe('spread generation', () => { + it('skips in case of release commit', () => { + expect(decideWhereToSpread('chore: release 2022-03-15')).toEqual([]); + }); + + it('spreads to all if scope is missing', () => { + expect(decideWhereToSpread('chore: do something')).toEqual(LANGUAGES); + }); + + it('spreads to javascript if the scope is javascript', () => { + expect(decideWhereToSpread('fix(javascript): fix something')).toEqual([ + 'javascript', + ]); + }); + + it('spreads to all if scope is not specific language', () => { + ['cts', 'spec', 'script', 'ci'].forEach((scope) => { + expect(decideWhereToSpread(`fix(${scope}): fix something`)).toEqual( + LANGUAGES + ); + }); + }); + + it('removes pull-request number from commit message', () => { + expect( + cleanUpCommitMessage(`feat(ci): make ci push generated code (#244)`) + ).toEqual(`feat(ci): make ci push generated code`); + }); +}); diff --git a/scripts/ci/codegen/spreadGeneration.ts b/scripts/ci/codegen/spreadGeneration.ts new file mode 100644 index 0000000000..2c829e110d --- /dev/null +++ b/scripts/ci/codegen/spreadGeneration.ts @@ -0,0 +1,69 @@ +/* eslint-disable no-console */ +import { gitCommit, LANGUAGES, run } from '../../common'; +import { + cloneAndApplyGeneration, + configureGitHubAuthor, +} from '../../release/common'; + +export function decideWhereToSpread(commitMessage: string): string[] { + if (commitMessage.startsWith('chore: release')) { + return []; + } + + const result = commitMessage.match(/(.+)\((.+)\):/); + if (!result) { + // no scope + return LANGUAGES; + } + + const scope = result[2]; + return LANGUAGES.includes(scope) ? [scope] : LANGUAGES; +} + +export function cleanUpCommitMessage(commitMessage: string): string { + const result = commitMessage.match(/(.+)\s\(#\d+\)$/); + return result?.[1] ?? commitMessage; +} + +async function spreadGeneration(headRef: string): Promise { + if (!process.env.GITHUB_TOKEN) { + throw new Error('Environment variable `GITHUB_TOKEN` does not exist.'); + } + + const generatedCodeBranch = `generated/${headRef}`; + + if (!(await run(`git ls-remote --heads origin ${generatedCodeBranch}`))) { + console.log(`No branch named '${generatedCodeBranch}' was found.`); + return; + } + + await run(`git checkout ${generatedCodeBranch}`); + const lastCommitMessage = await run(`git log -1 --format="%s"`); + const commitMessage = cleanUpCommitMessage(lastCommitMessage); + const langs = decideWhereToSpread(lastCommitMessage); + + for (const lang of langs) { + const { tempGitDir } = await cloneAndApplyGeneration({ + lang, + githubToken: process.env.GITHUB_TOKEN, + tempDir: process.env.RUNNER_TEMP!, + }); + + await configureGitHubAuthor(tempGitDir); + await run(`git add .`, { cwd: tempGitDir }); + await gitCommit({ message: commitMessage, cwd: tempGitDir }); + await run(`git push`, { cwd: tempGitDir }); + } +} + +if (require.main === module) { + const args = process.argv.slice(2); + + if (!args || args.length === 0) { + throw new Error( + 'The base branch should be passed as a cli parameter of the `spreadGeneration` script.' + ); + } + + spreadGeneration(args[0]); +} diff --git a/scripts/common.ts b/scripts/common.ts index f2a0dda131..eb5b535b45 100644 --- a/scripts/common.ts +++ b/scripts/common.ts @@ -151,3 +151,15 @@ export async function runIfExists( } return ''; } + +export async function gitCommit({ + message, + cwd = ROOT_DIR, +}: { + message: string; + cwd?: string; +}): Promise { + await execa('git', ['commit', '-m', message], { + cwd, + }); +} diff --git a/scripts/package.json b/scripts/package.json index 1142182689..e85a6a1c65 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -6,6 +6,7 @@ "processRelease": "ts-node release/process-release.ts", "pushGeneratedCode": "ts-node ci/codegen/pushGeneratedCode.ts", "cleanGeneratedBranch": "ts-node ci/codegen/cleanGeneratedBranch.ts", + "spreadGeneration": "ts-node ci/codegen/spreadGeneration.ts", "test": "jest" }, "devDependencies": { diff --git a/scripts/release/common.ts b/scripts/release/common.ts index e51dc0eeda..2d091beb5b 100644 --- a/scripts/release/common.ts +++ b/scripts/release/common.ts @@ -1,5 +1,6 @@ import config from '../../config/release.config.json'; -import { run } from '../common'; +import { getGitHubUrl, run, toAbsolutePath } from '../common'; +import { getLanguageFolder } from '../config'; export const RELEASED_TAG = config.releasedTag; export const MAIN_BRANCH = config.mainBranch; @@ -36,3 +37,29 @@ export async function configureGitHubAuthor(cwd?: string): Promise { await run(`git config user.name "${name}"`, { cwd }); await run(`git config user.email "${email}"`, { cwd }); } + +export async function cloneAndApplyGeneration({ + lang, + githubToken, + tempDir, +}: { + lang: string; + githubToken: string; + tempDir: string; +}): Promise<{ tempGitDir: string }> { + const clientPath = toAbsolutePath(getLanguageFolder(lang)); + const targetBranch = getTargetBranch(lang); + + const gitHubUrl = getGitHubUrl(lang, { token: githubToken }); + const tempGitDir = `${tempDir}/${lang}`; + await run(`rm -rf ${tempGitDir}`); + await run( + `git clone --depth 1 --branch ${targetBranch} ${gitHubUrl} ${tempGitDir}` + ); + + await run(`cp -r ${clientPath}/ ${tempGitDir}`); + + return { + tempGitDir, + }; +} diff --git a/scripts/release/process-release.ts b/scripts/release/process-release.ts index 239d703fb1..40adac6638 100755 --- a/scripts/release/process-release.ts +++ b/scripts/release/process-release.ts @@ -11,6 +11,7 @@ import { run, exists, getGitHubUrl, + gitCommit, } from '../common'; import { getLanguageFolder } from '../config'; @@ -19,8 +20,8 @@ import { OWNER, REPO, getMarkdownSection, - getTargetBranch, configureGitHubAuthor, + cloneAndApplyGeneration, } from './common'; import TEXT from './text'; @@ -163,27 +164,23 @@ async function processRelease(): Promise { await run(`git add ${changelogPath}`); } - // We push commits from submodules AFTER all the generations are done. + // We push commits to each repository AFTER all the generations are done. // Otherwise, we will end up having broken release. for (const lang of langsToReleaseOrUpdate) { - const clientPath = toAbsolutePath(getLanguageFolder(lang)); - const targetBranch = getTargetBranch(lang); - - const gitHubUrl = getGitHubUrl(lang, { token: process.env.GITHUB_TOKEN }); - const tempGitDir = `${process.env.RUNNER_TEMP}/${lang}`; - await run(`rm -rf ${tempGitDir}`); - await run( - `git clone --depth 1 --branch ${targetBranch} ${gitHubUrl} ${tempGitDir}` - ); + const { tempGitDir } = await cloneAndApplyGeneration({ + lang, + githubToken: process.env.GITHUB_TOKEN, + tempDir: process.env.RUNNER_TEMP!, + }); - await run(`cp -r ${clientPath}/ ${tempGitDir}`); await configureGitHubAuthor(tempGitDir); await run(`git add .`, { cwd: tempGitDir }); const { next, dateStamp } = versionsToRelease[lang]; if (willReleaseLibrary(lang)) { - await execa('git', ['commit', '-m', `chore: release ${next}`], { + await gitCommit({ + message: `chore: release ${next}`, cwd: tempGitDir, }); if (process.env.VERSION_TAG_ON_RELEASE === 'true') { @@ -191,7 +188,8 @@ async function processRelease(): Promise { await run(`git push --tags`, { cwd: tempGitDir }); } } else { - await execa('git', ['commit', '-m', `chore: update repo ${dateStamp}`], { + await gitCommit({ + message: `chore: update repo ${dateStamp}`, cwd: tempGitDir, }); } @@ -199,7 +197,9 @@ async function processRelease(): Promise { } // Commit and push from the monorepo level. - await execa('git', ['commit', '-m', `chore: release ${getDateStamp()}`]); + await gitCommit({ + message: `chore: release ${getDateStamp()}`, + }); await run(`git push`); // remove old `released` tag From de75fd7add47b64a4543b0b7edd2ecb7326d7fc1 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Wed, 16 Mar 2022 11:31:00 +0100 Subject: [PATCH 02/14] chore: separate spreadGeneration workflow --- .github/workflows/codegen-cleanup.yml | 5 ----- .github/workflows/spread-generation.yml | 24 ++++++++++++++++++++++++ scripts/ci/codegen/spreadGeneration.ts | 24 ++++++------------------ 3 files changed, 30 insertions(+), 23 deletions(-) create mode 100644 .github/workflows/spread-generation.yml diff --git a/.github/workflows/codegen-cleanup.yml b/.github/workflows/codegen-cleanup.yml index f1a80b140e..bd5f198ffb 100644 --- a/.github/workflows/codegen-cleanup.yml +++ b/.github/workflows/codegen-cleanup.yml @@ -17,10 +17,5 @@ jobs: - name: Setup uses: ./.github/actions/setup - - name: Spread generation to each repository - run: yarn workspace scripts spreadGeneration $${{ github.head_ref }} - env: - GITHUB_TOKEN: ${{ secrets.TOKEN_RELEASE_BOT }} - - name: Clean previously generated branch run: yarn workspace scripts cleanGeneratedBranch ${{ github.head_ref }} diff --git a/.github/workflows/spread-generation.yml b/.github/workflows/spread-generation.yml new file mode 100644 index 0000000000..bc95cd5616 --- /dev/null +++ b/.github/workflows/spread-generation.yml @@ -0,0 +1,24 @@ +name: Codegen cleanup + +on: + push: + branches: + - main + +jobs: + codegen: + runs-on: ubuntu-20.04 + timeout-minutes: 10 + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + ref: main + + - name: Setup + uses: ./.github/actions/setup + + - name: Spread generation to each repository + run: yarn workspace scripts spreadGeneration + env: + GITHUB_TOKEN: ${{ secrets.TOKEN_RELEASE_BOT }} diff --git a/scripts/ci/codegen/spreadGeneration.ts b/scripts/ci/codegen/spreadGeneration.ts index 2c829e110d..e6fe65a851 100644 --- a/scripts/ci/codegen/spreadGeneration.ts +++ b/scripts/ci/codegen/spreadGeneration.ts @@ -5,6 +5,8 @@ import { configureGitHubAuthor, } from '../../release/common'; +const GENERATED_MAIN_BRANCH = `generated/main`; + export function decideWhereToSpread(commitMessage: string): string[] { if (commitMessage.startsWith('chore: release')) { return []; @@ -25,23 +27,17 @@ export function cleanUpCommitMessage(commitMessage: string): string { return result?.[1] ?? commitMessage; } -async function spreadGeneration(headRef: string): Promise { +async function spreadGeneration(): Promise { if (!process.env.GITHUB_TOKEN) { throw new Error('Environment variable `GITHUB_TOKEN` does not exist.'); } - const generatedCodeBranch = `generated/${headRef}`; - - if (!(await run(`git ls-remote --heads origin ${generatedCodeBranch}`))) { - console.log(`No branch named '${generatedCodeBranch}' was found.`); - return; - } - - await run(`git checkout ${generatedCodeBranch}`); const lastCommitMessage = await run(`git log -1 --format="%s"`); const commitMessage = cleanUpCommitMessage(lastCommitMessage); const langs = decideWhereToSpread(lastCommitMessage); + await run(`git checkout ${GENERATED_MAIN_BRANCH}`); + for (const lang of langs) { const { tempGitDir } = await cloneAndApplyGeneration({ lang, @@ -57,13 +53,5 @@ async function spreadGeneration(headRef: string): Promise { } if (require.main === module) { - const args = process.argv.slice(2); - - if (!args || args.length === 0) { - throw new Error( - 'The base branch should be passed as a cli parameter of the `spreadGeneration` script.' - ); - } - - spreadGeneration(args[0]); + spreadGeneration(); } From 600fdc29f3491680481ff8186833d3c982fe3671 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Wed, 16 Mar 2022 11:34:15 +0100 Subject: [PATCH 03/14] chore: remove unnecessary eslint disable comment --- scripts/ci/codegen/spreadGeneration.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/ci/codegen/spreadGeneration.ts b/scripts/ci/codegen/spreadGeneration.ts index e6fe65a851..83d315e965 100644 --- a/scripts/ci/codegen/spreadGeneration.ts +++ b/scripts/ci/codegen/spreadGeneration.ts @@ -1,4 +1,3 @@ -/* eslint-disable no-console */ import { gitCommit, LANGUAGES, run } from '../../common'; import { cloneAndApplyGeneration, From 62a80fdc71537c717034eeec5cb9ee7a9a3a4733 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 17 Mar 2022 11:32:32 +0100 Subject: [PATCH 04/14] chore: rename workflow --- .github/workflows/spread-generation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/spread-generation.yml b/.github/workflows/spread-generation.yml index bc95cd5616..3d2b400eba 100644 --- a/.github/workflows/spread-generation.yml +++ b/.github/workflows/spread-generation.yml @@ -1,4 +1,4 @@ -name: Codegen cleanup +name: Spread generations on: push: From 8f8539a9092a32d37049837b598a951a76a91dcc Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 17 Mar 2022 11:39:24 +0100 Subject: [PATCH 05/14] chore: adjust abstraction --- scripts/ci/codegen/spreadGeneration.ts | 13 +++++++------ scripts/release/common.ts | 8 ++------ scripts/release/process-release.ts | 7 +++++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/scripts/ci/codegen/spreadGeneration.ts b/scripts/ci/codegen/spreadGeneration.ts index 83d315e965..2a68fc08cb 100644 --- a/scripts/ci/codegen/spreadGeneration.ts +++ b/scripts/ci/codegen/spreadGeneration.ts @@ -1,8 +1,6 @@ -import { gitCommit, LANGUAGES, run } from '../../common'; -import { - cloneAndApplyGeneration, - configureGitHubAuthor, -} from '../../release/common'; +import { gitCommit, LANGUAGES, run, toAbsolutePath } from '../../common'; +import { getLanguageFolder } from '../../config'; +import { cloneRepository, configureGitHubAuthor } from '../../release/common'; const GENERATED_MAIN_BRANCH = `generated/main`; @@ -38,12 +36,15 @@ async function spreadGeneration(): Promise { await run(`git checkout ${GENERATED_MAIN_BRANCH}`); for (const lang of langs) { - const { tempGitDir } = await cloneAndApplyGeneration({ + const { tempGitDir } = await cloneRepository({ lang, githubToken: process.env.GITHUB_TOKEN, tempDir: process.env.RUNNER_TEMP!, }); + const clientPath = toAbsolutePath(getLanguageFolder(lang)); + await run(`cp -r ${clientPath}/ ${tempGitDir}`); + await configureGitHubAuthor(tempGitDir); await run(`git add .`, { cwd: tempGitDir }); await gitCommit({ message: commitMessage, cwd: tempGitDir }); diff --git a/scripts/release/common.ts b/scripts/release/common.ts index 2d091beb5b..30b0908796 100644 --- a/scripts/release/common.ts +++ b/scripts/release/common.ts @@ -1,6 +1,5 @@ import config from '../../config/release.config.json'; -import { getGitHubUrl, run, toAbsolutePath } from '../common'; -import { getLanguageFolder } from '../config'; +import { getGitHubUrl, run } from '../common'; export const RELEASED_TAG = config.releasedTag; export const MAIN_BRANCH = config.mainBranch; @@ -38,7 +37,7 @@ export async function configureGitHubAuthor(cwd?: string): Promise { await run(`git config user.email "${email}"`, { cwd }); } -export async function cloneAndApplyGeneration({ +export async function cloneRepository({ lang, githubToken, tempDir, @@ -47,7 +46,6 @@ export async function cloneAndApplyGeneration({ githubToken: string; tempDir: string; }): Promise<{ tempGitDir: string }> { - const clientPath = toAbsolutePath(getLanguageFolder(lang)); const targetBranch = getTargetBranch(lang); const gitHubUrl = getGitHubUrl(lang, { token: githubToken }); @@ -57,8 +55,6 @@ export async function cloneAndApplyGeneration({ `git clone --depth 1 --branch ${targetBranch} ${gitHubUrl} ${tempGitDir}` ); - await run(`cp -r ${clientPath}/ ${tempGitDir}`); - return { tempGitDir, }; diff --git a/scripts/release/process-release.ts b/scripts/release/process-release.ts index 40adac6638..ec7ead84fd 100755 --- a/scripts/release/process-release.ts +++ b/scripts/release/process-release.ts @@ -21,7 +21,7 @@ import { REPO, getMarkdownSection, configureGitHubAuthor, - cloneAndApplyGeneration, + cloneRepository, } from './common'; import TEXT from './text'; @@ -167,12 +167,15 @@ async function processRelease(): Promise { // We push commits to each repository AFTER all the generations are done. // Otherwise, we will end up having broken release. for (const lang of langsToReleaseOrUpdate) { - const { tempGitDir } = await cloneAndApplyGeneration({ + const { tempGitDir } = await cloneRepository({ lang, githubToken: process.env.GITHUB_TOKEN, tempDir: process.env.RUNNER_TEMP!, }); + const clientPath = toAbsolutePath(getLanguageFolder(lang)); + await run(`cp -r ${clientPath}/ ${tempGitDir}`); + await configureGitHubAuthor(tempGitDir); await run(`git add .`, { cwd: tempGitDir }); From c9c40143a504a6558b90a15e2e162860fe2c102b Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Fri, 18 Mar 2022 09:51:27 +0100 Subject: [PATCH 06/14] chore: include PR url in commit message --- .../codegen/__tests__/spreadGeneration.test.ts | 4 +++- scripts/ci/codegen/spreadGeneration.ts | 18 +++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/scripts/ci/codegen/__tests__/spreadGeneration.test.ts b/scripts/ci/codegen/__tests__/spreadGeneration.test.ts index f168a681cb..5c59fa8975 100644 --- a/scripts/ci/codegen/__tests__/spreadGeneration.test.ts +++ b/scripts/ci/codegen/__tests__/spreadGeneration.test.ts @@ -27,6 +27,8 @@ describe('spread generation', () => { it('removes pull-request number from commit message', () => { expect( cleanUpCommitMessage(`feat(ci): make ci push generated code (#244)`) - ).toEqual(`feat(ci): make ci push generated code`); + ).toEqual( + `feat(ci): make ci push generated code\nhttps://github.com/algolia/api-clients-automation/pull/244` + ); }); }); diff --git a/scripts/ci/codegen/spreadGeneration.ts b/scripts/ci/codegen/spreadGeneration.ts index 2a68fc08cb..11ec295df8 100644 --- a/scripts/ci/codegen/spreadGeneration.ts +++ b/scripts/ci/codegen/spreadGeneration.ts @@ -1,6 +1,11 @@ import { gitCommit, LANGUAGES, run, toAbsolutePath } from '../../common'; import { getLanguageFolder } from '../../config'; -import { cloneRepository, configureGitHubAuthor } from '../../release/common'; +import { + cloneRepository, + configureGitHubAuthor, + OWNER, + REPO, +} from '../../release/common'; const GENERATED_MAIN_BRANCH = `generated/main`; @@ -20,8 +25,15 @@ export function decideWhereToSpread(commitMessage: string): string[] { } export function cleanUpCommitMessage(commitMessage: string): string { - const result = commitMessage.match(/(.+)\s\(#\d+\)$/); - return result?.[1] ?? commitMessage; + const result = commitMessage.match(/(.+)\s\(#(\d+)\)$/); + if (!result) { + return commitMessage; + } + + return [ + result[1], + `https://github.com/${OWNER}/${REPO}/pull/${result[2]}`, + ].join('\n'); } async function spreadGeneration(): Promise { From 12c71f12016c0de31c2ac7bb8196319ffec674a1 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Fri, 18 Mar 2022 09:54:48 +0100 Subject: [PATCH 07/14] chore: move generation workflow to after codegen --- .github/workflows/check.yml | 20 ++++++++++++++++++++ .github/workflows/spread-generation.yml | 24 ------------------------ 2 files changed, 20 insertions(+), 24 deletions(-) delete mode 100644 .github/workflows/spread-generation.yml diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index a84ece97d0..b3ceaa2330 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -310,3 +310,23 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.TOKEN_GENERATE_BOT }} PR_NUMBER: ${{ github.event.number }} + + spread_generation: + runs-on: ubuntu-20.04 + timeout-minutes: 10 + needs: codegen + if: | + always() + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + ref: main + + - name: Restore cache + uses: ./.github/actions/cache + + - name: Spread generation to each repository + run: yarn workspace scripts spreadGeneration + env: + GITHUB_TOKEN: ${{ secrets.TOKEN_RELEASE_BOT }} diff --git a/.github/workflows/spread-generation.yml b/.github/workflows/spread-generation.yml deleted file mode 100644 index 3d2b400eba..0000000000 --- a/.github/workflows/spread-generation.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Spread generations - -on: - push: - branches: - - main - -jobs: - codegen: - runs-on: ubuntu-20.04 - timeout-minutes: 10 - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - ref: main - - - name: Setup - uses: ./.github/actions/setup - - - name: Spread generation to each repository - run: yarn workspace scripts spreadGeneration - env: - GITHUB_TOKEN: ${{ secrets.TOKEN_RELEASE_BOT }} From 9a38b2dd4900f37e0563115e44bb4017f96d2d16 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Fri, 18 Mar 2022 11:25:14 +0100 Subject: [PATCH 08/14] chore: spread generation only on main --- .github/workflows/check.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index b3ceaa2330..f5cd43a4d9 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -316,7 +316,8 @@ jobs: timeout-minutes: 10 needs: codegen if: | - always() + always() && + github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v2 with: From 06572146463ae9a66e3c75d8b0f64be03cd50eba Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Fri, 18 Mar 2022 11:29:20 +0100 Subject: [PATCH 09/14] chore: spread generation only when codegen is successful --- .github/workflows/check.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index f5cd43a4d9..bf882b2bea 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -317,6 +317,7 @@ jobs: needs: codegen if: | always() && + needs.codegen.result == 'success' && github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v2 From 15d0d65c90e2ec17640fd8473b316ce0a6fcbcc4 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Fri, 18 Mar 2022 11:48:24 +0100 Subject: [PATCH 10/14] chore: spread generation as a part of codegen --- .github/workflows/check.yml | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index bf882b2bea..5487e41b2c 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -306,29 +306,16 @@ jobs: job: codegen - name: Push generated code + id: pushGeneratedCode run: yarn workspace scripts pushGeneratedCode env: GITHUB_TOKEN: ${{ secrets.TOKEN_GENERATE_BOT }} PR_NUMBER: ${{ github.event.number }} - spread_generation: - runs-on: ubuntu-20.04 - timeout-minutes: 10 - needs: codegen - if: | - always() && - needs.codegen.result == 'success' && - github.ref == 'refs/heads/main' - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - ref: main - - - name: Restore cache - uses: ./.github/actions/cache - - name: Spread generation to each repository + if: | + steps.pushGeneratedCode.exitcode == 0 && + github.ref == 'refs/heads/main' run: yarn workspace scripts spreadGeneration env: GITHUB_TOKEN: ${{ secrets.TOKEN_RELEASE_BOT }} From 3d7965ace755f474f3b05b1a9afe899df2f5200d Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Fri, 18 Mar 2022 14:23:40 +0100 Subject: [PATCH 11/14] chore: apply author name and email to commits --- .../codegen/__tests__/spreadGeneration.test.ts | 2 +- scripts/ci/codegen/spreadGeneration.ts | 6 ++++-- scripts/release/common.ts | 16 ++++++++++++---- scripts/release/process-release.ts | 2 +- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/scripts/ci/codegen/__tests__/spreadGeneration.test.ts b/scripts/ci/codegen/__tests__/spreadGeneration.test.ts index 5c59fa8975..f8d442e786 100644 --- a/scripts/ci/codegen/__tests__/spreadGeneration.test.ts +++ b/scripts/ci/codegen/__tests__/spreadGeneration.test.ts @@ -28,7 +28,7 @@ describe('spread generation', () => { expect( cleanUpCommitMessage(`feat(ci): make ci push generated code (#244)`) ).toEqual( - `feat(ci): make ci push generated code\nhttps://github.com/algolia/api-clients-automation/pull/244` + `feat(ci): make ci push generated code\n\nhttps://github.com/algolia/api-clients-automation/pull/244` ); }); }); diff --git a/scripts/ci/codegen/spreadGeneration.ts b/scripts/ci/codegen/spreadGeneration.ts index 11ec295df8..a393397ccc 100644 --- a/scripts/ci/codegen/spreadGeneration.ts +++ b/scripts/ci/codegen/spreadGeneration.ts @@ -33,7 +33,7 @@ export function cleanUpCommitMessage(commitMessage: string): string { return [ result[1], `https://github.com/${OWNER}/${REPO}/pull/${result[2]}`, - ].join('\n'); + ].join('\n\n'); } async function spreadGeneration(): Promise { @@ -42,6 +42,8 @@ async function spreadGeneration(): Promise { } const lastCommitMessage = await run(`git log -1 --format="%s"`); + const name = (await run(`git log -1 --format="%an"`)).trim(); + const email = (await run(`git log -1 --format="%ae"`)).trim(); const commitMessage = cleanUpCommitMessage(lastCommitMessage); const langs = decideWhereToSpread(lastCommitMessage); @@ -57,7 +59,7 @@ async function spreadGeneration(): Promise { const clientPath = toAbsolutePath(getLanguageFolder(lang)); await run(`cp -r ${clientPath}/ ${tempGitDir}`); - await configureGitHubAuthor(tempGitDir); + await configureGitHubAuthor({ name, email, cwd: tempGitDir }); await run(`git add .`, { cwd: tempGitDir }); await gitCommit({ message: commitMessage, cwd: tempGitDir }); await run(`git push`, { cwd: tempGitDir }); diff --git a/scripts/release/common.ts b/scripts/release/common.ts index 30b0908796..33d03020d9 100644 --- a/scripts/release/common.ts +++ b/scripts/release/common.ts @@ -30,11 +30,19 @@ export function getMarkdownSection(markdown: string, title: string): string { return lines.slice(0, endIndex).join('\n'); } -export async function configureGitHubAuthor(cwd?: string): Promise { - const { name, email } = getGitAuthor(); +export async function configureGitHubAuthor({ + name, + email, + cwd, +}: { + name?: string; + email?: string; + cwd?: string; +} = {}): Promise { + const bot = getGitAuthor(); - await run(`git config user.name "${name}"`, { cwd }); - await run(`git config user.email "${email}"`, { cwd }); + await run(`git config user.name "${name || bot.name}"`, { cwd }); + await run(`git config user.email "${email || bot.email}"`, { cwd }); } export async function cloneRepository({ diff --git a/scripts/release/process-release.ts b/scripts/release/process-release.ts index ec7ead84fd..453193cd4b 100755 --- a/scripts/release/process-release.ts +++ b/scripts/release/process-release.ts @@ -176,7 +176,7 @@ async function processRelease(): Promise { const clientPath = toAbsolutePath(getLanguageFolder(lang)); await run(`cp -r ${clientPath}/ ${tempGitDir}`); - await configureGitHubAuthor(tempGitDir); + await configureGitHubAuthor({ cwd: tempGitDir }); await run(`git add .`, { cwd: tempGitDir }); const { next, dateStamp } = versionsToRelease[lang]; From fab901231777d4b9892801c0c7bb2e53443d148a Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Fri, 18 Mar 2022 15:04:12 +0100 Subject: [PATCH 12/14] chore: include coauthor in commit message --- scripts/ci/codegen/spreadGeneration.ts | 8 ++++++-- scripts/common.ts | 22 +++++++++++++++++++--- scripts/release/common.ts | 16 ++++------------ scripts/release/process-release.ts | 2 +- 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/scripts/ci/codegen/spreadGeneration.ts b/scripts/ci/codegen/spreadGeneration.ts index a393397ccc..7f6999d2bc 100644 --- a/scripts/ci/codegen/spreadGeneration.ts +++ b/scripts/ci/codegen/spreadGeneration.ts @@ -59,9 +59,13 @@ async function spreadGeneration(): Promise { const clientPath = toAbsolutePath(getLanguageFolder(lang)); await run(`cp -r ${clientPath}/ ${tempGitDir}`); - await configureGitHubAuthor({ name, email, cwd: tempGitDir }); + await configureGitHubAuthor(tempGitDir); await run(`git add .`, { cwd: tempGitDir }); - await gitCommit({ message: commitMessage, cwd: tempGitDir }); + await gitCommit({ + message: commitMessage, + coauthor: { name, email }, + cwd: tempGitDir, + }); await run(`git push`, { cwd: tempGitDir }); } } diff --git a/scripts/common.ts b/scripts/common.ts index 9d5b99b712..67965ef11f 100644 --- a/scripts/common.ts +++ b/scripts/common.ts @@ -157,14 +157,30 @@ export async function runIfExists( export async function gitCommit({ message, + coauthor, cwd = ROOT_DIR, }: { message: string; + coauthor?: { + name: string; + email: string; + }; cwd?: string; }): Promise { - await execa('git', ['commit', '-m', message], { - cwd, - }); + await execa( + 'git', + [ + 'commit', + '-m', + message + + (coauthor + ? `\n\n\nCo-authored-by: ${coauthor.name} <${coauthor.email}>` + : ''), + ], + { + cwd, + } + ); } export async function buildCustomGenerators(verbose: boolean): Promise { diff --git a/scripts/release/common.ts b/scripts/release/common.ts index 33d03020d9..30b0908796 100644 --- a/scripts/release/common.ts +++ b/scripts/release/common.ts @@ -30,19 +30,11 @@ export function getMarkdownSection(markdown: string, title: string): string { return lines.slice(0, endIndex).join('\n'); } -export async function configureGitHubAuthor({ - name, - email, - cwd, -}: { - name?: string; - email?: string; - cwd?: string; -} = {}): Promise { - const bot = getGitAuthor(); +export async function configureGitHubAuthor(cwd?: string): Promise { + const { name, email } = getGitAuthor(); - await run(`git config user.name "${name || bot.name}"`, { cwd }); - await run(`git config user.email "${email || bot.email}"`, { cwd }); + await run(`git config user.name "${name}"`, { cwd }); + await run(`git config user.email "${email}"`, { cwd }); } export async function cloneRepository({ diff --git a/scripts/release/process-release.ts b/scripts/release/process-release.ts index 453193cd4b..ec7ead84fd 100755 --- a/scripts/release/process-release.ts +++ b/scripts/release/process-release.ts @@ -176,7 +176,7 @@ async function processRelease(): Promise { const clientPath = toAbsolutePath(getLanguageFolder(lang)); await run(`cp -r ${clientPath}/ ${tempGitDir}`); - await configureGitHubAuthor({ cwd: tempGitDir }); + await configureGitHubAuthor(tempGitDir); await run(`git add .`, { cwd: tempGitDir }); const { next, dateStamp } = versionsToRelease[lang]; From e041d58d26dd56c0581e0cc0a79d97300b7836fc Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Mon, 21 Mar 2022 11:01:28 +0100 Subject: [PATCH 13/14] chore: add tests --- scripts/__tests__/common.test.ts | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 scripts/__tests__/common.test.ts diff --git a/scripts/__tests__/common.test.ts b/scripts/__tests__/common.test.ts new file mode 100644 index 0000000000..d953c3d48d --- /dev/null +++ b/scripts/__tests__/common.test.ts @@ -0,0 +1,38 @@ +import execa from 'execa'; + +import { gitCommit } from '../common'; + +jest.mock('execa'); + +describe('gitCommit', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('commits with message', () => { + gitCommit({ message: 'chore: does something' }); + expect(execa).toHaveBeenCalledTimes(1); + expect(execa).toHaveBeenCalledWith( + 'git', + ['commit', '-m', 'chore: does something'], + { cwd: expect.any(String) } + ); + }); + + it('commits with co-author', () => { + gitCommit({ + message: 'chore: does something', + coauthor: { name: 'some', email: 'random@person.com' }, + }); + expect(execa).toHaveBeenCalledTimes(1); + expect(execa).toHaveBeenCalledWith( + 'git', + [ + 'commit', + '-m', + 'chore: does something\n\n\nCo-authored-by: some ', + ], + { cwd: expect.any(String) } + ); + }); +}); From 3d5055d891f820cb3ac30c3504b8dd0b384dd528 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Mon, 21 Mar 2022 16:10:00 +0100 Subject: [PATCH 14/14] chore: add tests --- .../ci/codegen/__tests__/spreadGeneration.test.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/scripts/ci/codegen/__tests__/spreadGeneration.test.ts b/scripts/ci/codegen/__tests__/spreadGeneration.test.ts index f8d442e786..454322cd2d 100644 --- a/scripts/ci/codegen/__tests__/spreadGeneration.test.ts +++ b/scripts/ci/codegen/__tests__/spreadGeneration.test.ts @@ -31,4 +31,18 @@ describe('spread generation', () => { `feat(ci): make ci push generated code\n\nhttps://github.com/algolia/api-clients-automation/pull/244` ); }); + + it('keeps the commit message even if it does not have PR number', () => { + const commitMessage = `feat(ci): make ci push generated code`; + expect(cleanUpCommitMessage(commitMessage)).toEqual(commitMessage); + }); + + it('cleans up correctly even if the title contains a url', () => { + const commitMessage = `fix(java): solve oneOf using a custom generator https://algolia.atlassian.net/browse/APIC-123 (#200)`; + expect(cleanUpCommitMessage(commitMessage)).toMatchInlineSnapshot(` + "fix(java): solve oneOf using a custom generator https://algolia.atlassian.net/browse/APIC-123 + + https://github.com/algolia/api-clients-automation/pull/200" + `); + }); });