diff --git a/.github/actions/code-pushup/src/runner.ts b/.github/actions/code-pushup/src/runner.ts index f1fbbbc87..fb14fc187 100644 --- a/.github/actions/code-pushup/src/runner.ts +++ b/.github/actions/code-pushup/src/runner.ts @@ -129,42 +129,51 @@ function createGitHubApiClient(): ProviderAPIClient { }; } +function setupOptions(): Options { + const isMonorepo = process.env['MODE'] === 'monorepo'; + + if (isMonorepo) { + return { + jobId: 'monorepo-mode', + monorepo: 'nx', + nxProjectsFilter: '--with-target=code-pushup --exclude=workspace', + configPatterns: { + persist: { + ...DEFAULT_PERSIST_CONFIG, + outputDir: '.code-pushup/{projectName}', + }, + ...(process.env['CP_API_KEY'] && { + upload: { + server: 'https://api.staging.code-pushup.dev/graphql', + apiKey: process.env['CP_API_KEY'], + organization: 'code-pushup', + project: 'cli-{projectName}', + }, + }), + }, + }; + } + + // tsx importer need to resolve plugin runner scripts + // eslint-disable-next-line functional/immutable-data + process.env['NODE_OPTIONS'] = '--import=tsx'; + + return { + jobId: 'standalone-mode', + // run without Nx to demonstrate native GitHub Actions log groups + bin: 'node packages/cli/src/index.ts', + }; +} + async function run(): Promise { try { if (core.isDebug()) { logger.setVerbose(true); } - const isMonorepo = process.env['MODE'] === 'monorepo'; - - const options: Options = isMonorepo - ? { - jobId: 'monorepo-mode', - monorepo: 'nx', - nxProjectsFilter: '--with-target=code-pushup --exclude=workspace', - configPatterns: { - persist: { - ...DEFAULT_PERSIST_CONFIG, - outputDir: '.code-pushup/{projectName}', - }, - ...(process.env['CP_API_KEY'] && { - upload: { - server: 'https://api.staging.code-pushup.dev/graphql', - apiKey: process.env['CP_API_KEY'], - organization: 'code-pushup', - project: 'cli-{projectName}', - }, - }), - }, - } - : { - jobId: 'standalone-mode', - bin: 'npx nx code-pushup --', - }; - const gitRefs = parseGitRefs(); - const apiClient = createGitHubApiClient(); + const options = setupOptions(); const result = await runInCI(gitRefs, apiClient, options); diff --git a/packages/utils/src/lib/logger.int.test.ts b/packages/utils/src/lib/logger.int.test.ts index e14869f16..6be9cc114 100644 --- a/packages/utils/src/lib/logger.int.test.ts +++ b/packages/utils/src/lib/logger.int.test.ts @@ -51,6 +51,7 @@ describe('Logger', () => { vi.stubEnv('CI', 'false'); vi.stubEnv('GITHUB_ACTIONS', 'false'); vi.stubEnv('GITLAB_CI', 'false'); + vi.stubEnv('NX_TASK_TARGET_TARGET', ''); }); afterAll(() => { @@ -247,6 +248,28 @@ ${ansis.cyan('└')} ${ansis.green(`Total line coverage is ${ansis.bold('82%')}` └ ESLint reported 4 errors and 11 warnings (1.23 s) ::endgroup:: +`); + }); + + it('should NOT use native GitHub Actions log groups if run within Nx target', async () => { + vi.stubEnv('CI', 'true'); + vi.stubEnv('GITHUB_ACTIONS', 'true'); + vi.stubEnv('NX_TASK_TARGET_TARGET', 'code-pushup'); + performanceNowSpy.mockReturnValueOnce(0).mockReturnValueOnce(1234); // group duration: 1.23 s + const logger = new Logger(); + + await logger.group('Running plugin "ESLint"', async () => { + logger.info('$ npx eslint . --format=json'); + logger.warn('Skipping unknown rule "deprecation/deprecation"'); + return 'ESLint reported 4 errors and 11 warnings'; + }); + + expect(ansis.strip(stdout)).toBe(` +❯ Running plugin "ESLint" +│ $ npx eslint . --format=json +│ Skipping unknown rule "deprecation/deprecation" +└ ESLint reported 4 errors and 11 warnings (1.23 s) + `); }); diff --git a/packages/utils/src/lib/logger.ts b/packages/utils/src/lib/logger.ts index 81f9849f5..8777771ce 100644 --- a/packages/utils/src/lib/logger.ts +++ b/packages/utils/src/lib/logger.ts @@ -10,7 +10,7 @@ import { formatDuration, indentLines, transformLines } from './formatting.js'; import { settlePromise } from './promises.js'; type GroupColor = Extract; -type CiPlatform = 'GitHub Actions' | 'GitLab CI/CD'; +type CiPlatform = 'GitHub' | 'GitLab'; /** Additional options for log methods */ export type LogOptions = { @@ -43,9 +43,9 @@ export class Logger { #isVerbose = isEnvVarEnabled('CP_VERBOSE'); #isCI = isEnvVarEnabled('CI'); #ciPlatform: CiPlatform | undefined = isEnvVarEnabled('GITHUB_ACTIONS') - ? 'GitHub Actions' + ? 'GitHub' : isEnvVarEnabled('GITLAB_CI') - ? 'GitLab CI/CD' + ? 'GitLab' : undefined; #groupColor: GroupColor | undefined; @@ -350,15 +350,23 @@ export class Logger { start: (title: string) => string; end: () => string; } { - switch (this.#ciPlatform) { - case 'GitHub Actions': + // Nx typically renders native log groups for each target in GitHub + // + GitHub doesn't support nested log groups: https://github.com/actions/toolkit/issues/1001 + // => skip native GitHub log groups if run within Nx target + const platform = + this.#ciPlatform === 'GitHub' && process.env['NX_TASK_TARGET_TARGET'] // https://nx.dev/docs/reference/environment-variables + ? undefined + : this.#ciPlatform; + + switch (platform) { + case 'GitHub': // https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-commands#grouping-log-lines return { start: title => `::group::${this.#formatGroupTitle(title, { prefix: false })}`, end: () => '::endgroup::', }; - case 'GitLab CI/CD': + case 'GitLab': // https://docs.gitlab.com/ci/jobs/job_logs/#custom-collapsible-sections const ansiEscCode = '\u001B[0K'; // '\e' ESC character only works for `echo -e`, Node console must use '\u001B' const id = Math.random().toString(HEX_RADIX).slice(2);