From 8f3272a422dba0a6d93604beb3e1c95a16e947b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Vannicatte?= Date: Wed, 9 Mar 2022 18:52:30 +0100 Subject: [PATCH 1/5] feat(ci): make ci push generated code --- .github/actions/cache/action.yml | 152 +++++++++++++++++++-- .github/workflows/check.yml | 76 +++++++---- .github/workflows/codegen-cleanup.yml | 27 ++++ scripts/ci/codegen/cleanGeneratedBranch.ts | 35 +++++ scripts/ci/codegen/common.ts | 11 ++ scripts/ci/codegen/pushGeneratedCode.ts | 133 ++++++++++++++++++ scripts/package.json | 2 + scripts/release/common.ts | 8 ++ scripts/release/process-release.ts | 9 +- 9 files changed, 400 insertions(+), 53 deletions(-) create mode 100644 .github/workflows/codegen-cleanup.yml create mode 100644 scripts/ci/codegen/cleanGeneratedBranch.ts create mode 100644 scripts/ci/codegen/common.ts create mode 100644 scripts/ci/codegen/pushGeneratedCode.ts diff --git a/.github/actions/cache/action.yml b/.github/actions/cache/action.yml index 067dd014318..33c3574b295 100644 --- a/.github/actions/cache/action.yml +++ b/.github/actions/cache/action.yml @@ -40,6 +40,115 @@ runs: shell: bash run: curl -L "https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/5.4.0/openapi-generator-cli-5.4.0.jar" > /tmp/openapi-generator-cli.jar + # Restore bundled specs: used during 'client' generation or pushing the 'codegen' + - name: Restore built abtesting spec + if: ${{ inputs.job == 'client' || inputs.job == 'codegen' }} + uses: actions/cache@v2 + with: + path: specs/bundled/abtesting.yml + key: | + ${{ env.CACHE_VERSION }}-${{ + hashFiles( + 'specs/abtesting/**', + 'specs/common/**' + )}} + + - name: Restore built analytics spec + if: ${{ inputs.job == 'client' || inputs.job == 'codegen' }} + uses: actions/cache@v2 + with: + path: specs/bundled/analytics.yml + key: | + ${{ env.CACHE_VERSION }}-${{ + hashFiles( + 'specs/analytics/**', + 'specs/common/**' + )}} + + - name: Restore built insights spec + if: ${{ inputs.job == 'client' || inputs.job == 'codegen' }} + uses: actions/cache@v2 + with: + path: specs/bundled/insights.yml + key: | + ${{ env.CACHE_VERSION }}-${{ + hashFiles( + 'specs/insights/**', + 'specs/common/**' + )}} + + - name: Restore built personalization spec + if: ${{ inputs.job == 'client' || inputs.job == 'codegen' }} + uses: actions/cache@v2 + with: + path: specs/bundled/personalization.yml + key: | + ${{ env.CACHE_VERSION }}-${{ + hashFiles( + 'specs/personalization/**', + 'specs/common/**' + )}} + + - name: Restore built predict spec + if: ${{ inputs.job == 'client' || inputs.job == 'codegen' }} + uses: actions/cache@v2 + with: + path: specs/bundled/predict.yml + key: | + ${{ env.CACHE_VERSION }}-${{ + hashFiles( + 'specs/predict/**', + 'specs/common/**' + )}} + + - name: Restore built query-suggestions spec + if: ${{ inputs.job == 'client' || inputs.job == 'codegen' }} + uses: actions/cache@v2 + with: + path: specs/bundled/query-suggestions.yml + key: | + ${{ env.CACHE_VERSION }}-${{ + hashFiles( + 'specs/query-suggestions/**', + 'specs/common/**' + )}} + + - name: Restore built recommend spec + if: ${{ inputs.job == 'client' || inputs.job == 'codegen' }} + uses: actions/cache@v2 + with: + path: specs/bundled/recommend.yml + key: | + ${{ env.CACHE_VERSION }}-${{ + hashFiles( + 'specs/recommend/**', + 'specs/common/**' + )}} + + - name: Restore built search spec + if: ${{ inputs.job == 'client' || inputs.job == 'codegen' }} + uses: actions/cache@v2 + with: + path: specs/bundled/search.yml + key: | + ${{ env.CACHE_VERSION }}-${{ + hashFiles( + 'specs/search/**', + 'specs/common/**' + )}} + + - name: Restore built sources spec + if: ${{ inputs.job == 'client' || inputs.job == 'codegen' }} + uses: actions/cache@v2 + with: + path: specs/bundled/sources.yml + key: | + ${{ env.CACHE_VERSION }}-${{ + hashFiles( + 'specs/sources/**', + 'specs/common/**' + )}} + # Restore JavaScript clients utils: used during 'javascript' generation or 'cts' - name: Restore built JavaScript common client if: ${{ inputs.language == 'javascript' || inputs.job == 'cts' }} @@ -77,9 +186,9 @@ runs: '!clients/algoliasearch-client-javascript/packages/requester-browser-xhr/dist' )}} - # Restore JavaScript clients: used during 'cts' + # Restore JavaScript clients: used during 'cts' or 'codegen' - name: Restore built JavaScript algoliasearch client - if: ${{ inputs.job == 'cts'}} + if: ${{ inputs.job == 'cts' || inputs.job == 'codegen' }} uses: actions/cache@v2 with: path: clients/algoliasearch-client-javascript/packages/algoliasearch @@ -91,7 +200,7 @@ runs: )}} - name: Restore built JavaScript search client - if: ${{ inputs.job == 'cts' }} + if: ${{ inputs.job == 'cts' || inputs.job == 'codegen' }} uses: actions/cache@v2 with: path: clients/algoliasearch-client-javascript/packages/client-search @@ -104,7 +213,7 @@ runs: )}} - name: Restore built JavaScript recommend client - if: ${{ inputs.job == 'cts' }} + if: ${{ inputs.job == 'cts' || inputs.job == 'codegen' }} uses: actions/cache@v2 with: path: clients/algoliasearch-client-javascript/packages/recommend @@ -117,7 +226,7 @@ runs: )}} - name: Restore built JavaScript query-suggestions client - if: ${{ inputs.job == 'cts' }} + if: ${{ inputs.job == 'cts' || inputs.job == 'codegen' }} uses: actions/cache@v2 with: path: clients/algoliasearch-client-javascript/packages/client-query-suggestions @@ -130,7 +239,7 @@ runs: )}} - name: Restore built JavaScript personalization client - if: ${{ inputs.job == 'cts' }} + if: ${{ inputs.job == 'cts' || inputs.job == 'codegen' }} uses: actions/cache@v2 with: path: clients/algoliasearch-client-javascript/packages/client-personalization @@ -143,7 +252,7 @@ runs: )}} - name: Restore built JavaScript analytics client - if: ${{ inputs.job == 'cts' }} + if: ${{ inputs.job == 'cts' || inputs.job == 'codegen' }} uses: actions/cache@v2 with: path: clients/algoliasearch-client-javascript/packages/client-analytics @@ -156,7 +265,7 @@ runs: )}} - name: Restore built JavaScript abtesting client - if: ${{ inputs.job == 'cts' }} + if: ${{ inputs.job == 'cts' || inputs.job == 'codegen' }} uses: actions/cache@v2 with: path: clients/algoliasearch-client-javascript/packages/client-abtesting @@ -169,7 +278,7 @@ runs: )}} - name: Restore built JavaScript insights client - if: ${{ inputs.job == 'cts' }} + if: ${{ inputs.job == 'cts' || inputs.job == 'codegen' }} uses: actions/cache@v2 with: path: clients/algoliasearch-client-javascript/packages/client-insights @@ -182,7 +291,7 @@ runs: )}} - name: Restore built JavaScript sources client - if: ${{ inputs.job == 'cts' }} + if: ${{ inputs.job == 'cts' || inputs.job == 'codegen' }} uses: actions/cache@v2 with: path: clients/algoliasearch-client-javascript/packages/client-sources @@ -195,7 +304,7 @@ runs: )}} - name: Restore built JavaScript predict client - if: ${{ inputs.job == 'cts' }} + if: ${{ inputs.job == 'cts' || inputs.job == 'codegen' }} uses: actions/cache@v2 with: path: clients/algoliasearch-client-javascript/packages/client-predict @@ -207,16 +316,29 @@ runs: 'specs/bundled/predict.yml' )}} - # Restore Java clients: used during 'cts' + # Restore Java clients: used during 'cts' or 'codegen' - name: Restore built Java client - if: ${{ inputs.job == 'cts' }} + if: ${{ inputs.job == 'cts' || inputs.job == 'codegen' }} uses: actions/cache@v2 with: path: clients/algoliasearch-client-java-2 key: | ${{ env.CACHE_VERSION }}-${{ hashFiles( - 'clients/algoliasearch-client-java-2/client-predict/**', - '!clients/algoliasearch-client-java-2/client-predict/target', + 'clients/algoliasearch-client-java-2/**', + '!clients/algoliasearch-client-java-2/target', + 'specs/bundled/search.yml' + )}} + + # Restore PHP clients: used during 'cts' or 'codegen' + - name: Restore built PHP client + if: ${{ inputs.job == 'cts' || inputs.job == 'codegen' }} + uses: actions/cache@v2 + with: + path: clients/algoliasearch-client-php + key: | + ${{ env.CACHE_VERSION }}-${{ + hashFiles( + 'clients/algoliasearch-client-php/*', 'specs/bundled/search.yml' )}} diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 3705790260f..99c404e902e 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -66,7 +66,7 @@ jobs: runs-on: ubuntu-20.04 timeout-minutes: 10 needs: setup - if: ${{ needs.setup.outputs.RUN_SPECS == 'true' }} + if: ${{ always() && needs.setup.outputs.RUN_SPECS == 'true' }} strategy: matrix: ${{ fromJSON(needs.setup.outputs.SPECS_MATRIX) }} steps: @@ -80,22 +80,22 @@ jobs: uses: actions/cache@v2 with: path: specs/bundled/${{ matrix.client }}.yml - key: ${{ env.CACHE_VERSION }}-${{ hashFiles(format('specs/{0}/**', matrix.client), 'specs/common/**') }} + key: | + ${{ env.CACHE_VERSION }}-${{ + hashFiles( + format('specs/{0}/**', matrix.client), + 'specs/common/**' + )}} - name: Building '${{ matrix.client }}' specs if: steps.cache.outputs.cache-hit != 'true' run: yarn cli build specs ${{ matrix.client }} - - name: Check diff with pushed spec - run: | - git status - exit $(git status --porcelain specs/bundled/${{ matrix.client }}.yml | wc -l) - client_javascript_common: timeout-minutes: 10 runs-on: ubuntu-20.04 needs: setup - if: ${{ needs.setup.outputs.RUN_JS_COMMON == 'true' }} + if: ${{ always() && needs.setup.outputs.RUN_JS_COMMON == 'true' }} strategy: matrix: client: @@ -131,7 +131,7 @@ jobs: - setup - specs - client_javascript_common - if: ${{ needs.setup.outputs.RUN_JS == 'true' }} + if: ${{ always() && needs.setup.outputs.RUN_JS == 'true' }} strategy: matrix: ${{ fromJSON(needs.setup.outputs.JS_MATRIX) }} steps: @@ -160,12 +160,6 @@ jobs: if: steps.cache.outputs.cache-hit != 'true' && matrix.client.name != 'algoliasearch' run: yarn cli generate javascript ${{ matrix.client.name }} - - name: Check diff with pushed client - if: steps.cache.outputs.cache-hit != 'true' - run: | - git status - exit $(git status --porcelain ${{ matrix.client.folder }} | wc -l) - - name: Build '${{ matrix.client.name }}' client if: steps.cache.outputs.cache-hit != 'true' run: yarn cli build clients javascript ${{ matrix.client.name }} @@ -176,7 +170,7 @@ jobs: needs: - setup - specs - if: ${{ needs.setup.outputs.RUN_JAVA == 'true' }} + if: ${{ always() && needs.setup.outputs.RUN_JAVA == 'true' }} strategy: matrix: ${{ fromJSON(needs.setup.outputs.JAVA_MATRIX) }} steps: @@ -205,12 +199,6 @@ jobs: if: steps.cache.outputs.cache-hit != 'true' run: yarn cli generate java ${{ matrix.client.name }} - - name: Check diff with pushed client - if: steps.cache.outputs.cache-hit != 'true' - run: | - git status - exit $(git status --porcelain ${{ matrix.client.folder }} | wc -l) - - name: Build '${{ matrix.client.name }}' client if: steps.cache.outputs.cache-hit != 'true' run: yarn cli build clients java ${{ matrix.client.name }} @@ -221,7 +209,7 @@ jobs: needs: - setup - specs - if: ${{ needs.setup.outputs.RUN_PHP == 'true' }} + if: ${{ always() && needs.setup.outputs.RUN_PHP == 'true' }} strategy: matrix: ${{ fromJSON(needs.setup.outputs.PHP_MATRIX) }} steps: @@ -233,16 +221,22 @@ jobs: job: client language: php + - name: Cache '${{ matrix.client.name }}' client + id: cache + uses: actions/cache@v2 + with: + path: ${{ matrix.client.folder }} + key: | + ${{ env.CACHE_VERSION }}-${{ + hashFiles( + format('{0}/**', matrix.client.folder), + format('specs/bundled/{0}.yml', matrix.client.name) + )}} + - name: Generate '${{ matrix.client.name }}' client if: steps.cache.outputs.cache-hit != 'true' run: yarn cli generate php ${{ matrix.client.name }} - - name: Check diff with pushed client - if: steps.cache.outputs.cache-hit != 'true' - run: | - git status - exit $(git status --porcelain ${{ matrix.client.folder }} | wc -l) - - name: Build '${{ matrix.client.name }}' client if: steps.cache.outputs.cache-hit != 'true' run: yarn cli build clients php ${{ matrix.client.name }} @@ -254,7 +248,7 @@ jobs: - client_javascript - client_java - client_php - if: ${{ needs.setup.outputs.RUN_CTS == 'true' }} + if: ${{ always() && needs.setup.outputs.RUN_CTS == 'true' }} steps: - uses: actions/checkout@v2 @@ -273,3 +267,25 @@ jobs: - name: Run run: yarn cli cts run + + codegen: + runs-on: ubuntu-20.04 + timeout-minutes: 10 + if: ${{ always() }} + needs: cts + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.ref }} + + - name: Restore cache + uses: ./.github/actions/cache + with: + job: codegen + + - name: Push generated code + run: yarn workspace scripts pushGeneratedCode + env: + GITHUB_TOKEN: ${{ secrets.TOKEN_GENERATE_BOT }} + PR_NUMBER: ${{ github.event.number }} diff --git a/.github/workflows/codegen-cleanup.yml b/.github/workflows/codegen-cleanup.yml new file mode 100644 index 00000000000..764cf8ab9b4 --- /dev/null +++ b/.github/workflows/codegen-cleanup.yml @@ -0,0 +1,27 @@ +name: Codegen cleanup + +on: + pull_request: + types: [closed] + +env: + CACHE_VERSION: '8' + +jobs: + codegen: + runs-on: ubuntu-20.04 + timeout-minutes: 10 + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + ref: main + + - name: Setup + id: setup + uses: ./.github/actions/setup + + - name: Clean previously generated branch + run: yarn workspace scripts cleanGeneratedBranch + env: + HEAD_REF: ${{ github.head_ref }} diff --git a/scripts/ci/codegen/cleanGeneratedBranch.ts b/scripts/ci/codegen/cleanGeneratedBranch.ts new file mode 100644 index 00000000000..6346cc9a7e0 --- /dev/null +++ b/scripts/ci/codegen/cleanGeneratedBranch.ts @@ -0,0 +1,35 @@ +/* eslint-disable no-console */ +import { run } from '../../common'; + +import { branchExists } from './common'; + +/** + * Deletes a branch for it's `generated/headRef` name on origin. + * + * @param headRef - The name of the branch to search for. + */ +export async function cleanGeneratedBranch(headRef?: string): Promise { + if (!process.env.HEAD_REF && !headRef) { + throw new Error('Unable to run cleanup, HEAD_REF is missing.'); + } + + const generatedCodeBranch = `generated/${process.env.HEAD_REF || headRef}`; + + if (!(await branchExists(generatedCodeBranch))) { + console.log(`No branch named '${generatedCodeBranch}' was found.`); + + return; + } + + // Delete previous generations to avoid conflicts and out of date code + if (await branchExists(generatedCodeBranch)) { + console.log(`Deleting generated branch: '${generatedCodeBranch}'`); + + await run(`git fetch origin ${generatedCodeBranch}`); + await run(`git push -d origin ${generatedCodeBranch}`); + } +} + +if (process.env.HEAD_REF) { + cleanGeneratedBranch(); +} diff --git a/scripts/ci/codegen/common.ts b/scripts/ci/codegen/common.ts new file mode 100644 index 00000000000..99ab3d5469c --- /dev/null +++ b/scripts/ci/codegen/common.ts @@ -0,0 +1,11 @@ +import { run } from '../../common'; + +/** + * Checks if a remote branch with the `branch` name exists. + * + * @param branch - The name of the branch to check on `origin`. + * @returns Boolean. + */ +export async function branchExists(branch: string): Promise { + return Boolean(await run(`git ls-remote --heads origin ${branch}`)); +} diff --git a/scripts/ci/codegen/pushGeneratedCode.ts b/scripts/ci/codegen/pushGeneratedCode.ts new file mode 100644 index 00000000000..a7db450143b --- /dev/null +++ b/scripts/ci/codegen/pushGeneratedCode.ts @@ -0,0 +1,133 @@ +/* eslint-disable no-console */ +import { Octokit } from '@octokit/rest'; + +import { run } from '../../common'; +import { configureGitHubAuthor } from '../../release/common'; + +import { cleanGeneratedBranch } from './cleanGeneratedBranch'; + +if (!process.env.GITHUB_TOKEN) { + throw new Error('Environment variable `GITHUB_TOKEN` does not exist.'); +} + +const PR_NUMBER = parseInt(process.env.PR_NUMBER || '0', 10); +const FOLDERS_TO_CHECK = ['clients', 'specs/bundled']; +const REPOSITORY_URL = `https://github.com/algolia/api-clients-automation`; +// this should be changed to the bot name once we have the logs +const BOT_NAME = 'shortcuts'; + +const octokit = new Octokit({ + auth: `token ${process.env.GITHUB_TOKEN}`, +}); + +async function getCommentBody(commit: string, branch: string): Promise { + const generatedCommit = await run('git show -s --format=%H'); + const header = `✔️ codegen triggered on commit [${commit}](${REPOSITORY_URL}/pull/${PR_NUMBER}/commits/${commit}).`; + const body = `🔍 Browse the generated code on branch [${branch}](${REPOSITORY_URL}/tree/${branch}): [${generatedCommit}](${REPOSITORY_URL}/commit/${generatedCommit}).`; + + return `${header} + +${body}`; +} + +/** + * Add or update comment to the current `PR_NUMBER`. + */ +async function addCommentToPullRequest( + baseCommit: string, + generatedCodeBranch: string +): Promise { + const baseOctokitConfig = { + owner: 'algolia', + repo: 'api-clients-automation', + issue_number: PR_NUMBER, + }; + + try { + // Search for a previous comment from our bot. + const previousComment = await octokit.rest.issues + .listComments(baseOctokitConfig) + .then( + (res) => + res.data.filter( + (comment) => + comment.user?.login === BOT_NAME && + // this shouldn't be needed once we have a proper bot running + comment.body?.startsWith('✔️ codegen triggered on commit') + )[0] + ); + const commentBody = await getCommentBody(baseCommit, generatedCodeBranch); + + if (previousComment?.id) { + console.log(`Previous bot comment found ${previousComment.id}.`); + + await octokit.rest.issues.updateComment({ + ...baseOctokitConfig, + body: commentBody, + comment_id: previousComment.id, + }); + + return; + } + + console.log('Creating new comment.'); + await octokit.rest.issues.createComment({ + ...baseOctokitConfig, + body: commentBody, + }); + } catch (e) { + throw new Error(`Error with GitHub API: ${e}`); + } +} + +/** + * Push generated code for the current `JOB` and `CLIENT` on a `generated/` branch. + */ +async function pushGeneratedCode(): Promise { + await configureGitHubAuthor(); + + const baseBranch = await run('git branch --show-current'); + console.log(`Checking codegen status on '${baseBranch}'.`); + + // determine generated branch name based on current branch + const generatedCodeBranch = `generated/${baseBranch}`; + const generatedFolders = FOLDERS_TO_CHECK.join(' '); + + if ( + (await run( + `git status --porcelain ${generatedFolders} | wc -l | tr -d ' '` + )) === '0' + ) { + console.log(`No generated code changes found for '${baseBranch}'.`); + + return; + } + + await cleanGeneratedBranch(baseBranch); + + const baseCommit = await run(`git show ${baseBranch} -s --format=%H`); + console.log( + `Codegen triggered on branch '${baseBranch}' for commit ${baseCommit}.` + ); + + console.log(`Creating branch for generated code: '${generatedCodeBranch}'`); + await run(`git branch ${generatedCodeBranch}`); + const commitMessage = + await run(`git show -s --format="Generated code for commit %H. + +Co-authored-by: %an <%ae>"`); + + console.log( + `Pushing code for folders '${generatedFolders}' to generated branch: ${generatedCodeBranch}` + ); + await run(`git checkout ${generatedCodeBranch}`); + await run(`git add ${generatedFolders}`); + await run(`git commit -m "${commitMessage}"`); + await run(`git push origin ${generatedCodeBranch}`); + + if (PR_NUMBER) { + await addCommentToPullRequest(baseCommit, generatedCodeBranch); + } +} + +pushGeneratedCode(); diff --git a/scripts/package.json b/scripts/package.json index e48daed9bb2..1d1ec1c6938 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -5,6 +5,8 @@ "build": "tsc", "createReleaseIssue": "yarn build && node dist/scripts/release/create-release-issue.js", "processRelease": "yarn build && node dist/scripts/release/process-release.js", + "pushGeneratedCode": "yarn build && node dist/scripts/ci/codegen/pushGeneratedCode.js", + "cleanGeneratedBranch": "yarn build && node dist/scripts/ci/codegen/cleanGeneratedBranch.js", "test": "jest" }, "devDependencies": { diff --git a/scripts/release/common.ts b/scripts/release/common.ts index 512159f826a..21a4436e3d7 100644 --- a/scripts/release/common.ts +++ b/scripts/release/common.ts @@ -1,4 +1,5 @@ import config from '../../config/release.config.json'; +import { run } from '../common'; export const RELEASED_TAG = config.releasedTag; export const MAIN_BRANCH = config.mainBranch; @@ -28,3 +29,10 @@ export function getMarkdownSection(markdown: string, title: string): string { } return lines.slice(0, endIndex).join('\n'); } + +export async function configureGitHubAuthor(cwd?: string): Promise { + await run(`git config user.name "${getGitAuthor().name}"`, { cwd }); + await run(`git config user.email "${getGitAuthor().email}"`, { + cwd, + }); +} diff --git a/scripts/release/process-release.ts b/scripts/release/process-release.ts index b0e3a4a1e29..239d703fb15 100755 --- a/scripts/release/process-release.ts +++ b/scripts/release/process-release.ts @@ -19,8 +19,8 @@ import { OWNER, REPO, getMarkdownSection, - getGitAuthor, getTargetBranch, + configureGitHubAuthor, } from './common'; import TEXT from './text'; @@ -97,13 +97,6 @@ async function updateOpenApiTools( ); } -async function configureGitHubAuthor(cwd?: string): Promise { - await run(`git config user.name "${getGitAuthor().name}"`, { cwd }); - await run(`git config user.email "${getGitAuthor().email}"`, { - cwd, - }); -} - async function processRelease(): Promise { if (!process.env.GITHUB_TOKEN) { throw new Error('Environment variable `GITHUB_TOKEN` does not exist.'); From a8d9aa6568861efd89b8cb4f5896eeebc007af19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Vannicatte?= Date: Thu, 10 Mar 2022 17:50:30 +0100 Subject: [PATCH 2/5] apply changes from suggestion --- scripts/ci/codegen/cleanGeneratedBranch.ts | 14 +++++--------- scripts/ci/codegen/common.ts | 11 ----------- scripts/ci/codegen/pushGeneratedCode.ts | 16 ++++++++-------- scripts/release/common.ts | 8 ++++---- 4 files changed, 17 insertions(+), 32 deletions(-) delete mode 100644 scripts/ci/codegen/common.ts diff --git a/scripts/ci/codegen/cleanGeneratedBranch.ts b/scripts/ci/codegen/cleanGeneratedBranch.ts index 6346cc9a7e0..e8a0d16924d 100644 --- a/scripts/ci/codegen/cleanGeneratedBranch.ts +++ b/scripts/ci/codegen/cleanGeneratedBranch.ts @@ -1,10 +1,8 @@ /* eslint-disable no-console */ import { run } from '../../common'; -import { branchExists } from './common'; - /** - * Deletes a branch for it's `generated/headRef` name on origin. + * Deletes a branch for it's `generated/${headRef}` name on origin. * * @param headRef - The name of the branch to search for. */ @@ -15,19 +13,17 @@ export async function cleanGeneratedBranch(headRef?: string): Promise { const generatedCodeBranch = `generated/${process.env.HEAD_REF || headRef}`; - if (!(await branchExists(generatedCodeBranch))) { + if (!(await run(`git ls-remote --heads origin ${generatedCodeBranch}`))) { console.log(`No branch named '${generatedCodeBranch}' was found.`); return; } // Delete previous generations to avoid conflicts and out of date code - if (await branchExists(generatedCodeBranch)) { - console.log(`Deleting generated branch: '${generatedCodeBranch}'`); + console.log(`Deleting generated branch: '${generatedCodeBranch}'`); - await run(`git fetch origin ${generatedCodeBranch}`); - await run(`git push -d origin ${generatedCodeBranch}`); - } + await run(`git fetch origin ${generatedCodeBranch}`); + await run(`git push -d origin ${generatedCodeBranch}`); } if (process.env.HEAD_REF) { diff --git a/scripts/ci/codegen/common.ts b/scripts/ci/codegen/common.ts deleted file mode 100644 index 99ab3d5469c..00000000000 --- a/scripts/ci/codegen/common.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { run } from '../../common'; - -/** - * Checks if a remote branch with the `branch` name exists. - * - * @param branch - The name of the branch to check on `origin`. - * @returns Boolean. - */ -export async function branchExists(branch: string): Promise { - return Boolean(await run(`git ls-remote --heads origin ${branch}`)); -} diff --git a/scripts/ci/codegen/pushGeneratedCode.ts b/scripts/ci/codegen/pushGeneratedCode.ts index a7db450143b..d5890ee4ffa 100644 --- a/scripts/ci/codegen/pushGeneratedCode.ts +++ b/scripts/ci/codegen/pushGeneratedCode.ts @@ -2,7 +2,7 @@ import { Octokit } from '@octokit/rest'; import { run } from '../../common'; -import { configureGitHubAuthor } from '../../release/common'; +import { configureGitHubAuthor, OWNER, REPO } from '../../release/common'; import { cleanGeneratedBranch } from './cleanGeneratedBranch'; @@ -12,7 +12,6 @@ if (!process.env.GITHUB_TOKEN) { const PR_NUMBER = parseInt(process.env.PR_NUMBER || '0', 10); const FOLDERS_TO_CHECK = ['clients', 'specs/bundled']; -const REPOSITORY_URL = `https://github.com/algolia/api-clients-automation`; // this should be changed to the bot name once we have the logs const BOT_NAME = 'shortcuts'; @@ -21,9 +20,10 @@ const octokit = new Octokit({ }); async function getCommentBody(commit: string, branch: string): Promise { + const repoUrl = `https://github.com/${OWNER}/${REPO}`; const generatedCommit = await run('git show -s --format=%H'); - const header = `✔️ codegen triggered on commit [${commit}](${REPOSITORY_URL}/pull/${PR_NUMBER}/commits/${commit}).`; - const body = `🔍 Browse the generated code on branch [${branch}](${REPOSITORY_URL}/tree/${branch}): [${generatedCommit}](${REPOSITORY_URL}/commit/${generatedCommit}).`; + const header = `✔️ codegen triggered on commit [${commit}](${repoUrl}/pull/${PR_NUMBER}/commits/${commit}).`; + const body = `🔍 Browse the generated code on branch [${branch}](${repoUrl}/tree/${branch}): [${generatedCommit}](${repoUrl}/commit/${generatedCommit}).`; return `${header} @@ -33,13 +33,13 @@ ${body}`; /** * Add or update comment to the current `PR_NUMBER`. */ -async function addCommentToPullRequest( +async function upsertCommentToPullRequest( baseCommit: string, generatedCodeBranch: string ): Promise { const baseOctokitConfig = { - owner: 'algolia', - repo: 'api-clients-automation', + owner: OWNER, + repo: REPO, issue_number: PR_NUMBER, }; @@ -126,7 +126,7 @@ Co-authored-by: %an <%ae>"`); await run(`git push origin ${generatedCodeBranch}`); if (PR_NUMBER) { - await addCommentToPullRequest(baseCommit, generatedCodeBranch); + await upsertCommentToPullRequest(baseCommit, generatedCodeBranch); } } diff --git a/scripts/release/common.ts b/scripts/release/common.ts index 21a4436e3d7..e51dc0eedaa 100644 --- a/scripts/release/common.ts +++ b/scripts/release/common.ts @@ -31,8 +31,8 @@ export function getMarkdownSection(markdown: string, title: string): string { } export async function configureGitHubAuthor(cwd?: string): Promise { - await run(`git config user.name "${getGitAuthor().name}"`, { cwd }); - await run(`git config user.email "${getGitAuthor().email}"`, { - cwd, - }); + const { name, email } = getGitAuthor(); + + await run(`git config user.name "${name}"`, { cwd }); + await run(`git config user.email "${email}"`, { cwd }); } From 01733bcc78d5a23abb9d6f253b41bb26ef62cf68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Vannicatte?= Date: Thu, 10 Mar 2022 17:59:38 +0100 Subject: [PATCH 3/5] bump caches? --- .github/workflows/check.yml | 2 +- .github/workflows/codegen-cleanup.yml | 2 +- .github/workflows/process-release.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 99c404e902e..f1d11650b7d 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -8,7 +8,7 @@ on: - main env: - CACHE_VERSION: '8' + CACHE_VERSION: '9' concurrency: group: ${{ github.ref }} diff --git a/.github/workflows/codegen-cleanup.yml b/.github/workflows/codegen-cleanup.yml index 764cf8ab9b4..5c38bb3c47a 100644 --- a/.github/workflows/codegen-cleanup.yml +++ b/.github/workflows/codegen-cleanup.yml @@ -5,7 +5,7 @@ on: types: [closed] env: - CACHE_VERSION: '8' + CACHE_VERSION: '9' jobs: codegen: diff --git a/.github/workflows/process-release.yml b/.github/workflows/process-release.yml index a1911ea3e26..f1b6a46113e 100644 --- a/.github/workflows/process-release.yml +++ b/.github/workflows/process-release.yml @@ -6,7 +6,7 @@ on: - closed env: - CACHE_VERSION: '8' + CACHE_VERSION: '9' jobs: build: From 2344eb8cd781fc408206ad3567b5f3d0697540d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Vannicatte?= Date: Mon, 14 Mar 2022 10:09:29 +0100 Subject: [PATCH 4/5] replace status with diff --- .github/workflows/check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index f1d11650b7d..b7ae1804b74 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -262,7 +262,7 @@ jobs: - name: Check diff with pushed CTS run: | - git status + git --no-pager diff exit $(git status --porcelain ./tests/output | wc -l) - name: Run From b1d5dea3b2adef086362e9168dc444d13d018f83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Vannicatte?= Date: Mon, 14 Mar 2022 11:44:11 +0100 Subject: [PATCH 5/5] inline headRef parameter --- .github/workflows/codegen-cleanup.yml | 4 +--- scripts/ci/codegen/cleanGeneratedBranch.ts | 22 +++++++++++----------- scripts/ci/codegen/pushGeneratedCode.ts | 4 +--- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/.github/workflows/codegen-cleanup.yml b/.github/workflows/codegen-cleanup.yml index 5c38bb3c47a..02b40f7c00d 100644 --- a/.github/workflows/codegen-cleanup.yml +++ b/.github/workflows/codegen-cleanup.yml @@ -22,6 +22,4 @@ jobs: uses: ./.github/actions/setup - name: Clean previously generated branch - run: yarn workspace scripts cleanGeneratedBranch - env: - HEAD_REF: ${{ github.head_ref }} + run: yarn workspace scripts cleanGeneratedBranch ${{ github.head_ref }} diff --git a/scripts/ci/codegen/cleanGeneratedBranch.ts b/scripts/ci/codegen/cleanGeneratedBranch.ts index e8a0d16924d..e686243d7b5 100644 --- a/scripts/ci/codegen/cleanGeneratedBranch.ts +++ b/scripts/ci/codegen/cleanGeneratedBranch.ts @@ -2,16 +2,10 @@ import { run } from '../../common'; /** - * Deletes a branch for it's `generated/${headRef}` name on origin. - * - * @param headRef - The name of the branch to search for. + * Deletes a branch for its `generated/${headRef}` name on origin. */ -export async function cleanGeneratedBranch(headRef?: string): Promise { - if (!process.env.HEAD_REF && !headRef) { - throw new Error('Unable to run cleanup, HEAD_REF is missing.'); - } - - const generatedCodeBranch = `generated/${process.env.HEAD_REF || headRef}`; +async function cleanGeneratedBranch(headRef: string): Promise { + const generatedCodeBranch = `generated/${headRef}`; if (!(await run(`git ls-remote --heads origin ${generatedCodeBranch}`))) { console.log(`No branch named '${generatedCodeBranch}' was found.`); @@ -26,6 +20,12 @@ export async function cleanGeneratedBranch(headRef?: string): Promise { await run(`git push -d origin ${generatedCodeBranch}`); } -if (process.env.HEAD_REF) { - cleanGeneratedBranch(); +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 `cleanGeneratedBranch` script.' + ); } + +cleanGeneratedBranch(args[0]); diff --git a/scripts/ci/codegen/pushGeneratedCode.ts b/scripts/ci/codegen/pushGeneratedCode.ts index d5890ee4ffa..8fbdf7cd5e9 100644 --- a/scripts/ci/codegen/pushGeneratedCode.ts +++ b/scripts/ci/codegen/pushGeneratedCode.ts @@ -4,8 +4,6 @@ import { Octokit } from '@octokit/rest'; import { run } from '../../common'; import { configureGitHubAuthor, OWNER, REPO } from '../../release/common'; -import { cleanGeneratedBranch } from './cleanGeneratedBranch'; - if (!process.env.GITHUB_TOKEN) { throw new Error('Environment variable `GITHUB_TOKEN` does not exist.'); } @@ -103,7 +101,7 @@ async function pushGeneratedCode(): Promise { return; } - await cleanGeneratedBranch(baseBranch); + await run(`yarn workspace scripts cleanGeneratedBranch ${baseBranch}`); const baseCommit = await run(`git show ${baseBranch} -s --format=%H`); console.log(