Skip to content

Commit

Permalink
feat(cli): add logger (#459)
Browse files Browse the repository at this point in the history
  • Loading branch information
BioPhoton committed Feb 6, 2024
1 parent 1858c81 commit f436299
Show file tree
Hide file tree
Showing 16 changed files with 672 additions and 70 deletions.
413 changes: 405 additions & 8 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"dependencies": {
"@code-pushup/portal-client": "^0.4.1",
"@isaacs/cliui": "^8.0.2",
"@poppinss/cliui": "^6.3.0",
"@swc/helpers": "0.5.3",
"bundle-require": "^4.0.1",
"chalk": "^5.3.0",
Expand Down
3 changes: 2 additions & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"@code-pushup/core": "*",
"yargs": "^17.7.2",
"chalk": "^5.3.0",
"@code-pushup/utils": "*"
"@code-pushup/utils": "*",
"@poppinss/cliui": "^6.3.0"
}
}
35 changes: 18 additions & 17 deletions packages/cli/src/lib/autorun/autorun-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@ import {
collectAndPersistReports,
upload,
} from '@code-pushup/core';
import { getLatestCommit, validateCommitData } from '@code-pushup/utils';
import { CLI_NAME } from '../constants';
import {
collectSuccessfulLog,
renderConfigureCategoriesHint,
renderIntegratePortalHint,
ui,
uploadSuccessfulLog,
} from '../implementation/logging';
import { yargsOnlyPluginsOptionsDefinition } from '../implementation/only-plugins.options';

type AutorunOptions = CollectOptions & UploadOptions;
Expand All @@ -18,8 +26,8 @@ export function yargsAutorunCommandObject() {
describe: 'Shortcut for running collect followed by upload',
builder: yargsOnlyPluginsOptionsDefinition(),
handler: async <T>(args: ArgumentsCamelCase<T>) => {
console.info(chalk.bold(CLI_NAME));
console.info(chalk.gray(`Run ${command}...`));
ui().logger.log(chalk.bold(CLI_NAME));
ui().logger.info(chalk.gray(`Run ${command}...`));
const options = args as unknown as AutorunOptions;

// we need to ensure `json` is part of the formats as we want to upload
Expand All @@ -34,28 +42,21 @@ export function yargsAutorunCommandObject() {
};

await collectAndPersistReports(optionsWithFormat);
collectSuccessfulLog();

if (options.categories.length === 0) {
console.info(
chalk.gray(
'💡 Configure categories to see the scores in an overview table. See: https://github.com/code-pushup/cli/blob/main/packages/cli/README.md',
),
);
renderConfigureCategoriesHint();
}

if (options.upload) {
await upload(options);
const commitData = await getLatestCommit();
if (validateCommitData(commitData, { throwError: true })) {
uploadSuccessfulLog(options.upload, commitData.hash);
}
} else {
console.warn('Upload skipped because configuration is not set.');
console.info(
[
'💡 Integrate the portal:',
'- npx code-pushup upload - Run upload to upload the created report to the server',
' https://github.com/code-pushup/cli/tree/main/packages/cli#upload-command',
'- Portal Integration - https://github.com/code-pushup/cli/blob/main/packages/cli/README.md#portal-integration',
'- Upload Command - https://github.com/code-pushup/cli/blob/main/packages/cli/README.md#portal-integration',
].join('\n'),
);
ui().logger.warning('Upload skipped because configuration is not set.');
renderIntegratePortalHint();
}
},
} satisfies CommandModule;
Expand Down
56 changes: 40 additions & 16 deletions packages/cli/src/lib/collect/collect-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ import {
CollectAndPersistReportsOptions,
collectAndPersistReports,
} from '@code-pushup/core';
import { link } from '@code-pushup/utils';
import { CLI_NAME } from '../constants';
import {
collectSuccessfulLog,
renderConfigureCategoriesHint,
ui,
} from '../implementation/logging';
import { yargsOnlyPluginsOptionsDefinition } from '../implementation/only-plugins.options';

export function yargsCollectCommandObject(): CommandModule {
Expand All @@ -15,33 +21,51 @@ export function yargsCollectCommandObject(): CommandModule {
builder: yargsOnlyPluginsOptionsDefinition(),
handler: async <T>(args: ArgumentsCamelCase<T>) => {
const options = args as unknown as CollectAndPersistReportsOptions;
console.info(chalk.bold(CLI_NAME));
console.info(chalk.gray(`Run ${command}...`));
ui().logger.log(chalk.bold(CLI_NAME));
ui().logger.info(chalk.gray(`Run ${command}...`));

await collectAndPersistReports(options);
collectSuccessfulLog();

if (options.categories.length === 0) {
console.info(
chalk.gray(
'💡 Configure categories to see the scores in an overview table. See: https://github.com/code-pushup/cli/blob/main/packages/cli/README.md',
),
);
renderConfigureCategoriesHint();
}

const { upload = {} } = args as unknown as Record<
'upload',
object | undefined
>;
if (Object.keys(upload).length === 0) {
console.info(
[
'💡 Visualize your reports:',
'- npx code-pushup upload - Run upload to upload the created report to the server',
' https://github.com/code-pushup/cli/tree/main/packages/cli#upload-command',
'- npx code-pushup autorun - Run collect & upload',
' https://github.com/code-pushup/cli/tree/main/packages/cli#autorun-command',
].join('\n'),
);
renderUploadAutorunHint();
}
},
} satisfies CommandModule;
}

export function renderUploadAutorunHint(): void {
ui()
.sticker()
.add(chalk.bold(chalk.gray('💡 Visualize your reports')))
.add('')
.add(
`${chalk.gray('❯')} npx code-pushup upload - ${chalk.gray(
'Run upload to upload the created report to the server',
)}`,
)
.add(
` ${link(
'https://github.com/code-pushup/cli/tree/main/packages/cli#upload-command',
)}`,
)
.add(
`${chalk.gray('❯')} npx code-pushup autorun - ${chalk.gray(
'Run collect & upload',
)}`,
)
.add(
` ${link(
'https://github.com/code-pushup/cli/tree/main/packages/cli#autorun-command',
)}`,
)
.render();
}
71 changes: 71 additions & 0 deletions packages/cli/src/lib/implementation/logging.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { cliui } from '@poppinss/cliui';
import chalk from 'chalk';
import { UploadConfig } from '@code-pushup/models';
import { link, portalCommitDashboardLink } from '@code-pushup/utils';

export type CliUi = ReturnType<typeof cliui>;

// eslint-disable-next-line import/no-mutable-exports,functional/no-let
export let singletonUiInstance: CliUi | undefined;
export function ui(): CliUi {
if (singletonUiInstance === undefined) {
singletonUiInstance = cliui();
}
return singletonUiInstance;
}

export function renderConfigureCategoriesHint(): void {
ui().logger.info(
chalk.gray(
`💡 Configure categories to see the scores in an overview table. See: ${link(
'https://github.com/code-pushup/cli/blob/main/packages/cli/README.md',
)}`,
),
);
}
export function uploadSuccessfulLog(
options: UploadConfig,
commit: string,
): void {
ui().logger.success('Upload successful!');
ui().logger.success(
link(
// @TODO extend config to maintain baseUrl under upload
portalCommitDashboardLink(
{ ...options, baseUrl: '<YOUR_PORTAL_URL>' },
commit,
),
),
);
}
export function collectSuccessfulLog(): void {
ui().logger.success('Collecting report successful!');
}

export function renderIntegratePortalHint(): void {
ui()
.sticker()
.add(chalk.bold(chalk.gray('💡 Integrate the portal')))
.add('')
.add(
`${chalk.gray('❯')} Upload a report to the server - ${chalk.gray(
'npx code-pushup upload',
)}`,
)
.add(
` ${link(
'https://github.com/code-pushup/cli/tree/main/packages/cli#upload-command',
)}`,
)
.add(
`${chalk.gray('❯')} ${chalk.gray('Portal Integration')} - ${link(
'https://github.com/code-pushup/cli/blob/main/packages/cli/README.md#portal-integration',
)}`,
)
.add(
`${chalk.gray('❯')} ${chalk.gray('Upload Command')} - ${link(
'https://github.com/code-pushup/cli/blob/main/packages/cli/README.md#portal-integration',
)}`,
)
.render();
}
8 changes: 8 additions & 0 deletions packages/cli/src/lib/implementation/logging.unit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { expect } from 'vitest';
import { ui } from './logging';

describe('ui', () => {
it('should return singleton', () => {
expect(ui()).toBe(ui());
});
});
3 changes: 2 additions & 1 deletion packages/cli/src/lib/print-config/print-config-command.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CommandModule } from 'yargs';
import { filterKebabCaseKeys } from '../implementation/global.utils';
import { ui } from '../implementation/logging';
import { onlyPluginsOption } from '../implementation/only-plugins.options';

export function yargsConfigCommandObject() {
Expand All @@ -16,7 +17,7 @@ export function yargsConfigCommandObject() {
// it is important to filter out kebab case keys
// because yargs duplicates options in camel case and kebab case
const cleanArgs = filterKebabCaseKeys(args);
console.info(JSON.stringify(cleanArgs, null, 2));
ui().logger.log(JSON.stringify(cleanArgs, null, 2));
},
} satisfies CommandModule;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { describe, expect } from 'vitest';
import { beforeAll, describe, expect } from 'vitest';
import { DEFAULT_CLI_CONFIGURATION } from '../../../mocks/constants';
import { ui } from '../implementation/logging';
import { yargsCli } from '../yargs-cli';
import { yargsConfigCommandObject } from './print-config-command';

Expand All @@ -14,6 +15,11 @@ vi.mock('@code-pushup/core', async () => {
});

describe('print-config-command', () => {
beforeAll(() => {
// initialize it in raw mode
ui().switchMode('raw');
});

it('should filter out meta arguments and kebab duplicates', async () => {
await yargsCli(
[
Expand All @@ -25,17 +31,30 @@ describe('print-config-command', () => {
{ ...DEFAULT_CLI_CONFIGURATION, commands: [yargsConfigCommandObject()] },
).parseAsync();

expect(console.info).not.toHaveBeenCalledWith(
expect.stringContaining('"$0":'),
const log = ui().logger.getLogs()[0];

expect(log).toEqual(
expect.objectContaining({
message: expect.not.stringContaining('"$0":'),
}),
);
expect(console.info).not.toHaveBeenCalledWith(
expect.stringContaining('"_":'),

expect(log).toEqual(
expect.objectContaining({
message: expect.not.stringContaining('"_":'),
}),
);
expect(console.info).toHaveBeenCalledWith(
expect.stringContaining('"outputDir": "destinationDir"'),

expect(log).toEqual(
expect.objectContaining({
message: expect.stringContaining('"outputDir": "destinationDir"'),
}),
);
expect(console.info).not.toHaveBeenCalledWith(
expect.stringContaining('"output-dir":'),

expect(log).toEqual(
expect.objectContaining({
message: expect.not.stringContaining('"output-dir":'),
}),
);
});
});
25 changes: 14 additions & 11 deletions packages/cli/src/lib/upload/upload-command.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
import chalk from 'chalk';
import { ArgumentsCamelCase, CommandModule } from 'yargs';
import { UploadOptions, upload } from '@code-pushup/core';
import { getLatestCommit, validateCommitData } from '@code-pushup/utils';
import { CLI_NAME } from '../constants';
import {
renderIntegratePortalHint,
ui,
uploadSuccessfulLog,
} from '../implementation/logging';

export function yargsUploadCommandObject() {
const command = 'upload';
return {
command,
describe: 'Upload report results to the portal',
handler: async <T>(args: ArgumentsCamelCase<T>) => {
console.info(chalk.bold(CLI_NAME));
console.info(chalk.gray(`Run ${command}...`));
ui().logger.log(chalk.bold(CLI_NAME));
ui().logger.info(chalk.gray(`Run ${command}...`));

const options = args as unknown as UploadOptions;
if (!options.upload) {
console.info(
[
'💡 Integrate the portal:',
'- npx code-pushup upload - Run upload to upload the created report to the server',
' https://github.com/code-pushup/cli/tree/main/packages/cli#upload-command',
'- Portal Integration - https://github.com/code-pushup/cli/blob/main/packages/cli/README.md#portal-integration',
'- Upload Command - https://github.com/code-pushup/cli/blob/main/packages/cli/README.md#portal-integration',
].join('\n'),
);
renderIntegratePortalHint();
throw new Error('Upload configuration not set');
}
await upload(options);

const commitData = await getLatestCommit();
if (validateCommitData(commitData, { throwError: true })) {
uploadSuccessfulLog(options.upload, commitData.hash);
}
},
} satisfies CommandModule;
}
7 changes: 1 addition & 6 deletions packages/core/src/lib/implementation/persist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
logMultipleFileResults,
scoreReport,
sortReport,
validateCommitData,
} from '@code-pushup/utils';

export class PersistDirError extends Error {
Expand Down Expand Up @@ -73,12 +74,6 @@ export async function persistReport(
);
}

function validateCommitData(commitData?: unknown) {
if (!commitData) {
console.warn('no commit data available');
}
}

async function persistResult(reportPath: string, content: string) {
return (
writeFile(reportPath, content)
Expand Down
Loading

0 comments on commit f436299

Please sign in to comment.