Skip to content

Commit 52dc118

Browse files
committed
feat(utils): print custom cwd in logger command spinner
1 parent a72e87c commit 52dc118

File tree

4 files changed

+71
-13
lines changed

4 files changed

+71
-13
lines changed

packages/utils/mocks/logger-demo.ts

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ async function sleep(delay: number) {
1111
logger.setVerbose(process.argv.includes('--verbose'));
1212

1313
const errorStage = process.argv
14-
.find(arg => arg.startsWith('--error='))
14+
.findLast(arg => arg.startsWith('--error='))
15+
?.split('=')[1];
16+
17+
const cwd = process.argv
18+
.findLast(arg => arg.startsWith('--cwd='))
1519
?.split('=')[1];
1620

1721
try {
@@ -35,14 +39,18 @@ try {
3539
`Running plugin "ESLint" ${ansis.gray('[1/2]')}`,
3640
async () => {
3741
const bin = 'npx eslint . --format=json';
38-
await logger.command(bin, async () => {
39-
await sleep(3000);
40-
if (errorStage === 'plugin') {
41-
logger.info('Configuration file not found.');
42-
throw new Error(`Command ${ansis.bold(bin)} exited with code 1`);
43-
}
44-
logger.debug('All files pass linting.');
45-
});
42+
await logger.command(
43+
bin,
44+
async () => {
45+
await sleep(3000);
46+
if (errorStage === 'plugin') {
47+
logger.info('Configuration file not found.');
48+
throw new Error(`Command ${ansis.bold(bin)} exited with code 1`);
49+
}
50+
logger.debug('All files pass linting.');
51+
},
52+
{ cwd },
53+
);
4654

4755
logger.info('Found 0 lint problems');
4856

packages/utils/project.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@
4343
},
4444
"error-upload": {
4545
"args": ["--error=upload"]
46+
},
47+
"custom-cwd": {
48+
"args": ["--cwd=src"]
4649
}
4750
}
4851
}

packages/utils/src/lib/logger.int.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import ansis from 'ansis';
22
import cliSpinners from 'cli-spinners';
33
import os from 'node:os';
4+
import path from 'node:path';
45
import process from 'node:process';
56
import type { MockInstance } from 'vitest';
67
import { Logger } from './logger.js';
@@ -503,6 +504,42 @@ ${ansis.red('✖')} Uploading report to portal → ${ansis.red('GraphQL error: I
503504
`${ansis.red('✖')} ${ansis.red('$')} npx eslint . --format=json\n`,
504505
);
505506
});
507+
508+
it("should print command's working directory if it differs from `process.cwd()`", async () => {
509+
const command = new Logger().command(
510+
'npx eslint . --format=json',
511+
async () => {},
512+
{ cwd: 'src' },
513+
);
514+
515+
expect(output).toBe(
516+
`${ansis.cyan('⠋')} ${ansis.blue('src')} ${ansis.blue('$')} npx eslint . --format=json`,
517+
);
518+
519+
await expect(command).resolves.toBeUndefined();
520+
521+
expect(output).toBe(
522+
`${ansis.green('✔')} ${ansis.blue('src')} ${ansis.green('$')} npx eslint . --format=json ${ansis.gray('(42 ms)')}\n`,
523+
);
524+
});
525+
526+
it('should print relative working directory if absoluted path provided', async () => {
527+
const command = new Logger().command(
528+
'npx eslint . --format=json',
529+
async () => {},
530+
{ cwd: path.join(process.cwd(), 'src') },
531+
);
532+
533+
expect(output).toBe(
534+
`${ansis.cyan('⠋')} ${ansis.blue('src')} ${ansis.blue('$')} npx eslint . --format=json`,
535+
);
536+
537+
await expect(command).resolves.toBeUndefined();
538+
539+
expect(output).toBe(
540+
`${ansis.green('✔')} ${ansis.blue('src')} ${ansis.green('$')} npx eslint . --format=json ${ansis.gray('(42 ms)')}\n`,
541+
);
542+
});
506543
});
507544

508545
describe('spinners + groups', () => {

packages/utils/src/lib/logger.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import ansis, { type AnsiColors } from 'ansis';
22
import os from 'node:os';
3+
import path from 'node:path';
34
import ora, { type Ora } from 'ora';
45
import { dateToUnixTimestamp } from './dates.js';
56
import { isEnvVarEnabled } from './env.js';
@@ -198,19 +199,28 @@ export class Logger {
198199
*
199200
* A `$`-prefix is added. Its color indicates the status (blue=pending, green=success, red=failure).
200201
*
202+
* If the command's working directory isn't `process.cwd()`, a relative path is prefixed to the output.
203+
*
201204
* @example
202205
* await logger.command('npx eslint . --format=json', async () => {
203206
* // ...
204207
* });
205208
*
206209
* @param bin Command string with arguments.
207210
* @param worker Asynchronous execution of the command (not implemented by the logger).
211+
* @param options Custom CWD path where the command is executed (default is `process.cwd()`).
208212
*/
209-
command(bin: string, worker: () => Promise<void>): Promise<void> {
213+
command(
214+
bin: string,
215+
worker: () => Promise<void>,
216+
options?: { cwd?: string },
217+
): Promise<void> {
218+
const cwd = options?.cwd && path.relative(process.cwd(), options.cwd);
219+
const cwdPrefix = cwd ? `${ansis.blue(cwd)} ` : '';
210220
return this.#spinner(worker, {
211-
pending: `${ansis.blue('$')} ${bin}`,
212-
success: () => `${ansis.green('$')} ${bin}`,
213-
failure: () => `${ansis.red('$')} ${bin}`,
221+
pending: `${cwdPrefix}${ansis.blue('$')} ${bin}`,
222+
success: () => `${cwdPrefix}${ansis.green('$')} ${bin}`,
223+
failure: () => `${cwdPrefix}${ansis.red('$')} ${bin}`,
214224
});
215225
}
216226

0 commit comments

Comments
 (0)