Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support debug flag on format and lint #367

Merged
merged 1 commit into from
Feb 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/nice-apricots-turn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'skuba': minor
---

**format, lint:** Support `--debug` flag
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ Apply automatic fixes to code quality and flag issues that require manual interv

This script should be run locally before pushing code to a remote branch.

| Option | Description |
| :-------- | :-------------------------- |
| `--debug` | Enable debug console output |

### `skuba help`

```shell
Expand Down Expand Up @@ -221,6 +225,10 @@ Check for code quality issues.

This script should be run in CI to verify that [`skuba format`] was applied and triaged locally.

| Option | Description |
| :-------- | :-------------------------- |
| `--debug` | Enable debug console output |

### `skuba node`

Run a TypeScript source file, or open a REPL if none is provided:
Expand Down
100 changes: 100 additions & 0 deletions src/cli/format.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import execa from 'execa';

import { hasStringProp } from '../utils/validation';

import { format } from './format';

jest.mock('execa');

const execaCalls = () =>
((execa as unknown) as jest.Mock<typeof execa>).mock.calls
.flat(2)
.map((val) =>
Array.isArray(val) || !hasStringProp(val, 'localDir')
? val
: { ...val, localDir: 'REDACTED' },
);

describe('format', () => {
const consoleLog = jest.spyOn(global.console, 'log').mockReturnValue();

const consoleLogCalls = () => consoleLog.mock.calls.flat(2);

afterEach(jest.clearAllMocks);

const oldProcessArgv = process.argv;
afterAll(() => (process.argv = oldProcessArgv));

it('handles no flags', async () => {
process.argv = [];

await expect(format()).resolves.toBeUndefined();

expect(execaCalls()).toMatchInlineSnapshot(`
Array [
"eslint",
"--ext=js,ts,tsx",
"--fix",
".",
Object {
"localDir": "REDACTED",
"preferLocal": true,
"stdio": "inherit",
},
"prettier",
"--write",
".",
Object {
"localDir": "REDACTED",
"preferLocal": true,
"stdio": "inherit",
},
]
`);

expect(consoleLogCalls()).toMatchInlineSnapshot(`
Array [
"✔ ESLint",
"✔ Prettier",
]
`);
});

it('handles debug flag', async () => {
process.argv = ['something', '--dEbUg', 'else'];

await expect(format()).resolves.toBeUndefined();

expect(execaCalls()).toMatchInlineSnapshot(`
Array [
"eslint",
"--debug",
"--ext=js,ts,tsx",
"--fix",
".",
Object {
"localDir": "REDACTED",
"preferLocal": true,
"stdio": "inherit",
},
"prettier",
"--loglevel",
"debug",
"--write",
".",
Object {
"localDir": "REDACTED",
"preferLocal": true,
"stdio": "inherit",
},
]
`);

expect(consoleLogCalls()).toMatchInlineSnapshot(`
Array [
"✔ ESLint",
"✔ Prettier",
]
`);
});
});
18 changes: 16 additions & 2 deletions src/cli/format.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
import { hasDebugFlag } from '../utils/args';
import { exec } from '../utils/exec';
import { log } from '../utils/logging';

export const format = async () => {
await exec('eslint', '--ext=js,ts,tsx', '--fix', '.');
const debug = hasDebugFlag();

await exec(
'eslint',
...(debug ? ['--debug'] : []),
'--ext=js,ts,tsx',
'--fix',
'.',
);
log.ok('✔ ESLint');

await exec('prettier', '--write', '.');
await exec(
'prettier',
...(debug ? ['--loglevel', 'debug'] : []),
'--write',
'.',
);
log.ok('✔ Prettier');
};
86 changes: 85 additions & 1 deletion src/cli/lint.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,88 @@
import { internalLint } from './lint';
import concurrently from 'concurrently';

import { internalLint, lint } from './lint';

jest.mock('concurrently');

const concurrentlyCalls = () =>
((concurrently as unknown) as jest.Mock<typeof concurrently>).mock.calls
.flat(2)
.map(({ env, maxProcesses, ...rest }) => ({
...(typeof env !== 'undefined' && { env: 'REDACTED' }),
...(typeof maxProcesses !== 'undefined' && { maxProcesses: 'REDACTED' }),
...rest,
}));

describe('lint', () => {
afterEach(jest.clearAllMocks);

const oldProcessArgv = process.argv;
afterAll(() => (process.argv = oldProcessArgv));

it('handles no flags', async () => {
process.argv = [];

await expect(lint()).resolves.toBeUndefined();

expect(concurrentlyCalls()).toMatchInlineSnapshot(`
Array [
Object {
"command": "eslint --ext=js,ts,tsx --report-unused-disable-directives .",
"env": "REDACTED",
"name": "ESLint ",
"prefixColor": "magenta",
},
Object {
"command": "tsc --noEmit",
"env": "REDACTED",
"name": "tsc ",
"prefixColor": "blue",
},
Object {
"command": "prettier --check .",
"env": "REDACTED",
"name": "Prettier",
"prefixColor": "cyan",
},
Object {
"maxProcesses": "REDACTED",
},
]
`);
});

it('handles debug flag', async () => {
process.argv = ['something', '--DeBuG', 'else'];

await expect(lint()).resolves.toBeUndefined();

expect(concurrentlyCalls()).toMatchInlineSnapshot(`
Array [
Object {
"command": "eslint --debug --ext=js,ts,tsx --report-unused-disable-directives .",
"env": "REDACTED",
"name": "ESLint ",
"prefixColor": "magenta",
},
Object {
"command": "tsc --extendedDiagnostics --noEmit",
"env": "REDACTED",
"name": "tsc ",
"prefixColor": "blue",
},
Object {
"command": "prettier --check --loglevel debug .",
"env": "REDACTED",
"name": "Prettier",
"prefixColor": "cyan",
},
Object {
"maxProcesses": "REDACTED",
},
]
`);
});
});

describe('internalLint', () => {
it('passes on skuba itself', () =>
Expand Down
21 changes: 16 additions & 5 deletions src/cli/lint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,30 @@ import path from 'path';
import chalk from 'chalk';
import fs from 'fs-extra';

import { hasDebugFlag } from '../utils/args';
import { execConcurrently } from '../utils/exec';
import { getConsumerManifest } from '../utils/manifest';

const externalLint = () =>
interface Options {
debug: boolean;
}

const externalLint = ({ debug }: Options) =>
execConcurrently([
{
command: 'eslint --ext=js,ts,tsx --report-unused-disable-directives .',
command: `eslint${
debug ? ' --debug' : ''
} --ext=js,ts,tsx --report-unused-disable-directives .`,
name: 'ESLint',
prefixColor: 'magenta',
},
{
command: 'tsc --noEmit',
command: `tsc${debug ? ' --extendedDiagnostics' : ''} --noEmit`,
name: 'tsc',
prefixColor: 'blue',
},
{
command: 'prettier --check .',
command: `prettier --check${debug ? ' --loglevel debug' : ''} .`,
name: 'Prettier',
prefixColor: 'cyan',
},
Expand Down Expand Up @@ -51,7 +58,11 @@ export const internalLint = async () => {
};

export const lint = async () => {
await externalLint();
const opts: Options = {
debug: hasDebugFlag(),
};

await externalLint(opts);

await internalLint();
};
17 changes: 16 additions & 1 deletion src/utils/args.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
import { parseProcessArgs, parseRunArgs } from './args';
import { hasDebugFlag, parseProcessArgs, parseRunArgs } from './args';

describe('hasDebugFlag', () => {
test.each`
description | args | expected
${'no args'} | ${[]} | ${false}
${'unrelated args'} | ${['something', 'else']} | ${false}
${'single dash'} | ${['-debug']} | ${false}
${'matching lowercase arg'} | ${['--debug']} | ${true}
${'matching uppercase arg'} | ${['--DEBUG']} | ${true}
${'matching spongebob arg'} | ${['--dEBuG']} | ${true}
${'matching arg among others'} | ${['something', '--debug', 'else']} | ${true}
`('$description => $expected', ({ args, expected }) =>
expect(hasDebugFlag(args)).toBe(expected),
);
});

describe('parseProcessArgs', () => {
it('parses a macOS command with args', () => {
Expand Down
3 changes: 3 additions & 0 deletions src/utils/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import assert from 'assert';

import { COMMAND_ALIASES } from './command';

export const hasDebugFlag = (args = process.argv) =>
args.some((arg) => arg.toLocaleLowerCase() === '--debug');

/**
* Parse process arguments.
*
Expand Down