From 6fd195bfde14d5ace3f24a3258718b5b0d6fda16 Mon Sep 17 00:00:00 2001 From: Morgan Szafranski <94189859+m-szaf@users.noreply.github.com> Date: Tue, 30 Jan 2024 14:55:50 -0500 Subject: [PATCH] feat(clickup-cdk): Add new codecov bypass workflow [CLK-464388] (#241) * feat: Add new codecov bypass workflow [CLK-464388] * feat(clickup-cdk): Add new codecov bypass workflow [CLK-464388] * feat(clickup-cdk): Update readme path [CLK-464388] * feat(clickup-cdk): Add disabled option + tests [CLK-464388] --- API.md | 171 ++++++++++++++++++ docs/codecov-bypass-workflow/README.md | 32 ++++ src/clickup-cdk.ts | 12 ++ src/codecov-bypass-workflow.ts | 115 ++++++++++++ src/index.ts | 1 + .../codecov-bypass-workflow.test.ts.snap | 67 +++++++ test/codecov-bypass-workflow.test.ts | 49 +++++ 7 files changed, 447 insertions(+) create mode 100644 docs/codecov-bypass-workflow/README.md create mode 100644 src/codecov-bypass-workflow.ts create mode 100644 test/__snapshots__/codecov-bypass-workflow.test.ts.snap create mode 100644 test/codecov-bypass-workflow.test.ts diff --git a/API.md b/API.md index cc97114e..19779b13 100644 --- a/API.md +++ b/API.md @@ -5085,6 +5085,7 @@ const clickUpCdkCommonOptions: clickupCdk.ClickUpCdkCommonOptions = { ... } | sendSlackWebhookOnRelease | boolean | Should we send a slack webhook on release (required for compliance audits). | | sendSlackWebhookOnReleaseOpts | @time-loop/clickup-projen.slackAlert.ReleaseEventOptions | Slack alert on release options. | | cdkDiffOptionsConfig | @time-loop/clickup-projen.cdkDiffWorkflow.CDKDiffOptionsConfig | Cdk diff options. | +| codecovBypassOptionsConfig | @time-loop/clickup-projen.codecovBypassWorkflow.CodecovBypassOptionsConfig | Codecov Bypass options. | | renovateOptionsConfig | @time-loop/clickup-projen.renovateWorkflow.RenovateOptionsConfig | Renovate options. | | sendReleaseEvent | boolean | Feature flag for datadog event sending on release. | | sendReleaseEventOpts | @time-loop/clickup-projen.datadog.ReleaseEventOptions | Datadog event options to use on release. | @@ -5132,6 +5133,19 @@ Cdk diff options. --- +##### `codecovBypassOptionsConfig`Optional + +```typescript +public readonly codecovBypassOptionsConfig: CodecovBypassOptionsConfig; +``` + +- *Type:* @time-loop/clickup-projen.codecovBypassWorkflow.CodecovBypassOptionsConfig +- *Default:* undefined + +Codecov Bypass options. + +--- + ##### `renovateOptionsConfig`Optional ```typescript @@ -5378,6 +5392,7 @@ const clickUpCdkConstructLibraryOptions: clickupCdk.ClickUpCdkConstructLibraryOp | sendSlackWebhookOnRelease | boolean | Should we send a slack webhook on release (required for compliance audits). | | sendSlackWebhookOnReleaseOpts | @time-loop/clickup-projen.slackAlert.ReleaseEventOptions | Slack alert on release options. | | cdkDiffOptionsConfig | @time-loop/clickup-projen.cdkDiffWorkflow.CDKDiffOptionsConfig | Cdk diff options. | +| codecovBypassOptionsConfig | @time-loop/clickup-projen.codecovBypassWorkflow.CodecovBypassOptionsConfig | Codecov Bypass options. | | renovateOptionsConfig | @time-loop/clickup-projen.renovateWorkflow.RenovateOptionsConfig | Renovate options. | | sendReleaseEvent | boolean | Feature flag for datadog event sending on release. | | sendReleaseEventOpts | @time-loop/clickup-projen.datadog.ReleaseEventOptions | Datadog event options to use on release. | @@ -7890,6 +7905,19 @@ Cdk diff options. --- +##### `codecovBypassOptionsConfig`Optional + +```typescript +public readonly codecovBypassOptionsConfig: CodecovBypassOptionsConfig; +``` + +- *Type:* @time-loop/clickup-projen.codecovBypassWorkflow.CodecovBypassOptionsConfig +- *Default:* undefined + +Codecov Bypass options. + +--- + ##### `renovateOptionsConfig`Optional ```typescript @@ -8127,6 +8155,7 @@ const clickUpCdkTypeScriptAppOptions: clickupCdk.ClickUpCdkTypeScriptAppOptions | sendSlackWebhookOnRelease | boolean | Should we send a slack webhook on release (required for compliance audits). | | sendSlackWebhookOnReleaseOpts | @time-loop/clickup-projen.slackAlert.ReleaseEventOptions | Slack alert on release options. | | cdkDiffOptionsConfig | @time-loop/clickup-projen.cdkDiffWorkflow.CDKDiffOptionsConfig | Cdk diff options. | +| codecovBypassOptionsConfig | @time-loop/clickup-projen.codecovBypassWorkflow.CodecovBypassOptionsConfig | Codecov Bypass options. | | renovateOptionsConfig | @time-loop/clickup-projen.renovateWorkflow.RenovateOptionsConfig | Renovate options. | | sendReleaseEvent | boolean | Feature flag for datadog event sending on release. | | sendReleaseEventOpts | @time-loop/clickup-projen.datadog.ReleaseEventOptions | Datadog event options to use on release. | @@ -10505,6 +10534,19 @@ Cdk diff options. --- +##### `codecovBypassOptionsConfig`Optional + +```typescript +public readonly codecovBypassOptionsConfig: CodecovBypassOptionsConfig; +``` + +- *Type:* @time-loop/clickup-projen.codecovBypassWorkflow.CodecovBypassOptionsConfig +- *Default:* undefined + +Codecov Bypass options. + +--- + ##### `renovateOptionsConfig`Optional ```typescript @@ -12820,6 +12862,135 @@ public readonly renovateOptionsConfig: RenovateOptionsConfig; --- +### CodecovBypassOptionsConfig + +#### Initializer + +```typescript +import { codecovBypassWorkflow } from '@time-loop/clickup-projen' + +const codecovBypassOptionsConfig: codecovBypassWorkflow.CodecovBypassOptionsConfig = { ... } +``` + +#### Properties + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| checkName | string | Check Name. | +| checkSuiteCheckNames | string[] | Check Suite Check Names. | +| detailsUrl | string | Details URL. | +| disabled | boolean | Skip creating (using) the workflow. | +| githubAppId | string | GitHub App ID. | +| githubAppPrivateKey | string | GitHub App Private Key. | +| skipLabel | string | Skip Label. | +| workflowName | string | Workflow Name. | + +--- + +##### `checkName`Optional + +```typescript +public readonly checkName: string; +``` + +- *Type:* string +- *Default:* 'Code coverage increased' + +Check Name. + +--- + +##### `checkSuiteCheckNames`Optional + +```typescript +public readonly checkSuiteCheckNames: string[]; +``` + +- *Type:* string[] +- *Default:* ['codecov/patch', 'codecov/project'] + +Check Suite Check Names. + +--- + +##### `detailsUrl`Optional + +```typescript +public readonly detailsUrl: string; +``` + +- *Type:* string +- *Default:* 'https://app.codecov.io/gh/${{ github.repository }}/pull/<% prNumber %>' + +Details URL. + +--- + +##### `disabled`Optional + +```typescript +public readonly disabled: boolean; +``` + +- *Type:* boolean +- *Default:* false + +Skip creating (using) the workflow. + +--- + +##### `githubAppId`Optional + +```typescript +public readonly githubAppId: string; +``` + +- *Type:* string +- *Default:* '${{ vars.CODECOV_GITHUB_APP_ID }}' + +GitHub App ID. + +--- + +##### `githubAppPrivateKey`Optional + +```typescript +public readonly githubAppPrivateKey: string; +``` + +- *Type:* string +- *Default:* '${{ secrets.CODECOV_GITHUB_APP_PRIVATE_KEY }}' + +GitHub App Private Key. + +--- + +##### `skipLabel`Optional + +```typescript +public readonly skipLabel: string; +``` + +- *Type:* string +- *Default:* 'code coverage not required' + +Skip Label. + +--- + +##### `workflowName`Optional + +```typescript +public readonly workflowName: string; +``` + +- *Type:* string +- *Default:* 'Code coverage increased' + +Workflow Name. + +--- + ### ContactInfo #### Initializer diff --git a/docs/codecov-bypass-workflow/README.md b/docs/codecov-bypass-workflow/README.md new file mode 100644 index 00000000..675030c1 --- /dev/null +++ b/docs/codecov-bypass-workflow/README.md @@ -0,0 +1,32 @@ +# codecov-bypass + +This is currently an explict opt-in feature. Eventually it will be a default enabled workflow with an explicit disable. + +To add this to your project, you will need to + +- edit your `.projenrc.ts` +- run `npx projen` to generate a bunch of files +- update your branch protection rules + +## Edit your .projenrc.ts + +```diff + import { clickupCdk } from '@time-loop/clickup-projen'; + const project = new clickupCdk.ClickUpCdkTypeScriptApp({ + ... ++ codecovBypassOptionsConfig: { ++ githubAppId: '${{ vars.CODECOV_GITHUB_APP_ID }}', ++ githubAppPrivateKey: '${{ secrets.CODECOV_GITHUB_APP_PRIVATE_KEY }}' ++ }, +``` + +## Generate new files + +After the above change, run `npx projen` to generate the new files. + +## Update Branch Protection Rules + +Once the above changes are merged, you will need to update your branch protection rules: + +1. Remove `codecod/patch`, and `codecov/patch` from the list of required checks. +2. Add `Code coverage increased` to the list of required checks. diff --git a/src/clickup-cdk.ts b/src/clickup-cdk.ts index 900bc364..eeb83d76 100644 --- a/src/clickup-cdk.ts +++ b/src/clickup-cdk.ts @@ -7,6 +7,7 @@ import { cdkContextJson } from './cdk-context-json'; import { cdkDiffWorkflow } from './cdk-diff-workflow'; import { clickupTs } from './clickup-ts'; import { codecov } from './codecov'; +import { codecovBypassWorkflow } from './codecov-bypass-workflow'; import { datadog } from './datadog'; import { datadogServiceCatalog } from './datadog-service-catalog'; import { nodeVersion } from './node-version'; @@ -86,6 +87,13 @@ export module clickupCdk { */ readonly cdkDiffOptionsConfig?: cdkDiffWorkflow.CDKDiffOptionsConfig; + /** + * Codecov Bypass options + * + * @default undefined + */ + readonly codecovBypassOptionsConfig?: codecovBypassWorkflow.CodecovBypassOptionsConfig; + /** * Datadog Service Catalog options * @@ -123,6 +131,7 @@ export module clickupCdk { repositoryUrl, renovatebotOptions: renovateWorkflow.getRenovateOptions(options.renovateOptionsConfig), cdkDiffOptions: cdkDiffWorkflow.getCDKDiffOptions(options.cdkDiffOptionsConfig), + codecovBypassOptions: codecovBypassWorkflow.getCodecovBypassOptions(options.codecovBypassOptionsConfig), }); super(mergedOptions); clickupTs.fixTsNodeDeps(this.package); @@ -232,6 +241,9 @@ export module clickupCdk { cdkDiffWorkflow.addOidcRoleStack(this); } } + if (options.codecovBypassOptionsConfig) { + codecovBypassWorkflow.addCodecovBypassWorkflowYml(this, options.codecovBypassOptionsConfig); + } if (options.cdkContextJsonOptions) { if (options.cdkContextJsonOptions.injectionOptions) { diff --git a/src/codecov-bypass-workflow.ts b/src/codecov-bypass-workflow.ts new file mode 100644 index 00000000..3b60dc2c --- /dev/null +++ b/src/codecov-bypass-workflow.ts @@ -0,0 +1,115 @@ +import { YamlFile } from 'projen'; +import { clickupCdk } from './clickup-cdk'; + +const CODECOV_GITHUB_APP_ID = 254; + +export module codecovBypassWorkflow { + function createCodecovBypassWorkflow(options?: CodecovBypassOptionsConfig) { + const defaultWorkflow = { + name: options?.workflowName || 'Code coverage increased', + on: { + check_suite: { + types: ['completed'], + }, + pull_request: { + types: ['labeled', 'unlabeled'], + }, + }, + permissions: {}, + jobs: { + 'code-coverage-increased': { + 'runs-on': 'ubuntu-latest', + if: `github.event_name != \'check_suite\' || github.event.check_suite.app.id == ${CODECOV_GITHUB_APP_ID}`, + steps: [ + { + name: 'Check codecov results', + uses: 'time-loop/github-actions/dist/wrap-check-suite@wrap-check-suite+0.3.2', + env: { + FORCE_COLOR: 3, + }, + with: { + 'github-app-id': options?.githubAppId || '${{ vars.CODECOV_GITHUB_APP_ID }}', + 'github-private-key': options?.githubAppPrivateKey || '${{ secrets.CODECOV_GITHUB_APP_PRIVATE_KEY }}', + 'skip-label': options?.skipLabel || 'code coverage not required', + 'check-name': options?.checkName || 'Code coverage increased', + 'check-suite-app-id': CODECOV_GITHUB_APP_ID, + 'check-suite-check-names': options?.checkSuiteCheckNames?.join(',') || 'codecov/patch,codecov/project', + 'details-url': + options?.detailsUrl || 'https://app.codecov.io/gh/${{ github.repository }}/pull/<% prNumber %>', + }, + }, + ], + }, + }, + }; + + return defaultWorkflow; + } + + export interface CodecovBypassOptionsConfig { + /** + * GitHub App ID + * @default '${{ vars.CODECOV_GITHUB_APP_ID }}' + */ + readonly githubAppId?: string; + + /** + * GitHub App Private Key + * @default '${{ secrets.CODECOV_GITHUB_APP_PRIVATE_KEY }}' + */ + readonly githubAppPrivateKey?: string; + + /** + * Skip creating (using) the workflow + * @default false + */ + readonly disabled?: boolean; + + /** + * Workflow Name + * @default 'Code coverage increased' + */ + readonly workflowName?: string; + + /** + * Skip Label + * @default 'code coverage not required' + */ + readonly skipLabel?: string; + + /** + * Check Name + * @default 'Code coverage increased' + */ + readonly checkName?: string; + + /** + * Check Suite Check Names + * @default ['codecov/patch', 'codecov/project'] + */ + readonly checkSuiteCheckNames?: string[]; + + /** + * Details URL + * @default 'https://app.codecov.io/gh/${{ github.repository }}/pull/<% prNumber %>' + */ + readonly detailsUrl?: string; + } + + export function getCodecovBypassOptions(options?: CodecovBypassOptionsConfig) { + return options; + } + + export function addCodecovBypassWorkflowYml( + project: clickupCdk.ClickUpCdkTypeScriptApp, + options?: CodecovBypassOptionsConfig, + override?: any, + ): void { + if (options?.disabled) { + return; + } + new YamlFile(project, '.github/workflows/codecov-bypass.yml', { + obj: { ...createCodecovBypassWorkflow(options), ...override }, + }); + } +} diff --git a/src/index.ts b/src/index.ts index be829eaa..864c3ab0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,3 +8,4 @@ export * from './datadog-service-catalog'; export * from './renovate-workflow'; export * from './slack-alert'; export * from './optional-node-version'; +export * from './codecov-bypass-workflow'; diff --git a/test/__snapshots__/codecov-bypass-workflow.test.ts.snap b/test/__snapshots__/codecov-bypass-workflow.test.ts.snap new file mode 100644 index 00000000..6eeca70c --- /dev/null +++ b/test/__snapshots__/codecov-bypass-workflow.test.ts.snap @@ -0,0 +1,67 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`addCodecovBypassWorkflowYml - codecov-bypass .yml file added all default options 1`] = ` +"# ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". + +name: Code coverage increased +on: + check_suite: + types: + - completed + pull_request: + types: + - labeled + - unlabeled +permissions: {} +jobs: + code-coverage-increased: + runs-on: ubuntu-latest + if: github.event_name != 'check_suite' || github.event.check_suite.app.id == 254 + steps: + - name: Check codecov results + uses: time-loop/github-actions/dist/wrap-check-suite@wrap-check-suite+0.3.2 + env: + FORCE_COLOR: 3 + with: + github-app-id: \${{ vars.CODECOV_GITHUB_APP_ID }} + github-private-key: \${{ secrets.CODECOV_GITHUB_APP_PRIVATE_KEY }} + skip-label: code coverage not required + check-name: Code coverage increased + check-suite-app-id: 254 + check-suite-check-names: codecov/patch,codecov/project + details-url: https://app.codecov.io/gh/\${{ github.repository }}/pull/<% prNumber %> +" +`; + +exports[`addCodecovBypassWorkflowYml - codecov-bypass .yml file added all options provided 1`] = ` +"# ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". + +name: workflowName +on: + check_suite: + types: + - completed + pull_request: + types: + - labeled + - unlabeled +permissions: {} +jobs: + code-coverage-increased: + runs-on: ubuntu-latest + if: github.event_name != 'check_suite' || github.event.check_suite.app.id == 254 + steps: + - name: Check codecov results + uses: time-loop/github-actions/dist/wrap-check-suite@wrap-check-suite+0.3.2 + env: + FORCE_COLOR: 3 + with: + github-app-id: \${{ vars.GH_APP_ID_VAR_NAME }} + github-private-key: r\${{ secrets.GH_APP_ID_PRIVATE_KEY_SECRET_NAME }} + skip-label: skipLabel + check-name: checkName + check-suite-app-id: 254 + check-suite-check-names: checkSuiteCheckName1,checkSuiteCheckName2 + details-url: some url +" +`; diff --git a/test/codecov-bypass-workflow.test.ts b/test/codecov-bypass-workflow.test.ts new file mode 100644 index 00000000..6ec86552 --- /dev/null +++ b/test/codecov-bypass-workflow.test.ts @@ -0,0 +1,49 @@ +import { Testing } from 'projen'; + +import { clickupCdk } from '../src/clickup-cdk'; +import { codecovBypassWorkflow } from '../src/codecov-bypass-workflow'; + +describe('addCodecovBypassWorkflowYml - codecov-bypass .yml file added', () => { + test('all default options', () => { + const project = new clickupCdk.ClickUpCdkTypeScriptApp({ + cdkVersion: '2.91.0', + defaultReleaseBranch: 'main', + name: 'test', + }); + codecovBypassWorkflow.addCodecovBypassWorkflowYml(project); + const synth = Testing.synth(project); + expect(synth['.github/workflows/codecov-bypass.yml']).toMatchSnapshot(); + }); + + test('all options provided', () => { + const project = new clickupCdk.ClickUpCdkTypeScriptApp({ + cdkVersion: '2.91.0', + defaultReleaseBranch: 'main', + name: 'test', + }); + codecovBypassWorkflow.addCodecovBypassWorkflowYml(project, { + workflowName: 'workflowName', + githubAppId: '${{ vars.GH_APP_ID_VAR_NAME }}', + githubAppPrivateKey: 'r${{ secrets.GH_APP_ID_PRIVATE_KEY_SECRET_NAME }}', + skipLabel: 'skipLabel', + checkName: 'checkName', + checkSuiteCheckNames: ['checkSuiteCheckName1', 'checkSuiteCheckName2'], + detailsUrl: 'some url', + }); + const synth = Testing.synth(project); + expect(synth['.github/workflows/codecov-bypass.yml']).toMatchSnapshot(); + }); + + test('disabled', () => { + const project = new clickupCdk.ClickUpCdkTypeScriptApp({ + cdkVersion: '2.91.0', + defaultReleaseBranch: 'main', + name: 'test', + }); + codecovBypassWorkflow.addCodecovBypassWorkflowYml(project, { + disabled: true, + }); + const synth = Testing.synth(project); + expect(synth['.github/workflows/codecov-bypass.yml']).toBeUndefined(); + }); +});