Skip to content

Commit 25dcbce

Browse files
authored
Add --no-prefix global flag to remove command string from spawned output (#267)
* Add --no-prefix global flag to remove command string from spawned output * Spawn add/upgrade commands with basename and hide user agent output * Fix failing tests * Add tests for globalOptions and run commands with flags * Update and fix changelog
1 parent 3a9f9a0 commit 25dcbce

File tree

10 files changed

+216
-24
lines changed

10 files changed

+216
-24
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
# Bolt Changelog
22

3-
# 0.24.3
3+
# master
4+
* Add --no-prefix flag to disable prefixing subcommand output with the command string
5+
6+
# 0.24.4
7+
48
* Fix --no-bail not throwing when running in default orderMode (#256)
59

610
# 0.24.3
11+
712
* Fixes `--help` so that is is correctly passed down to other commands (#252)
813
* `bolt add` on an existing dependency now correctly updates all workspaces versions if required (#251)
914
* Allow exclusion of certain dependency types from dependency graph (#244)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
"inquirer": "3.3.0",
6060
"is-glob": "^4.0.0",
6161
"make-dir": "^1.0.0",
62-
"meow": "^4.0.0",
62+
"meow": "^5.0.0",
6363
"minimatch": "^3.0.4",
6464
"multimatch": "^2.1.0",
6565
"p-limit": "^1.1.0",

src/GlobalOptions.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* Singleton that manages global bolt options.
3+
*/
4+
5+
import * as options from './utils/options';
6+
7+
export type GlobalOptions = {
8+
disableCmdPrefix?: boolean
9+
};
10+
class GlobalOptionsStore {
11+
store = {
12+
disableCmdPrefix: undefined
13+
};
14+
set(key: $Keys<GlobalOptions>, value: $PropertyType<GlobalOptions, key>) {
15+
this.store[key] = value;
16+
}
17+
get(key: $Keys<GlobalOptions>): $PropertyType<GlobalOptions, key> {
18+
return this.store[key];
19+
}
20+
getAll(): GlobalOptions {
21+
return this.store;
22+
}
23+
setFromFlags(flags: options.Flags) {
24+
if (flags.prefix === false) {
25+
this.set('disableCmdPrefix', true);
26+
}
27+
}
28+
}
29+
30+
export const globalOptions = new GlobalOptionsStore();

src/__tests__/cli.test.js

Lines changed: 131 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
import cli from '../cli';
22
import * as commands from '../commands';
3+
import { globalOptions } from '../GlobalOptions';
34

45
jest.mock('../commands');
56
jest.mock('../utils/logger');
7+
jest.mock('../GlobalOptions', () => ({
8+
globalOptions: {
9+
setFromFlags: jest.fn()
10+
}
11+
}));
612

713
const mockedCommands: any = commands;
814

@@ -16,7 +22,6 @@ describe('cli', () => {
1622
mockedCommands.toHelpOptions.mockImplementationOnce(() => opts);
1723
await cli(['--help']);
1824
expect(mockedCommands.toHelpOptions).toHaveBeenCalledWith([], {
19-
'--': [],
2025
help: true
2126
});
2227
expect(commands.help).toHaveBeenCalledTimes(1);
@@ -34,9 +39,7 @@ describe('cli', () => {
3439
const opts = {};
3540
mockedCommands.toInstallOptions.mockImplementationOnce(() => opts);
3641
await cli([]);
37-
expect(mockedCommands.toInstallOptions).toHaveBeenCalledWith([], {
38-
'--': []
39-
});
42+
expect(mockedCommands.toInstallOptions).toHaveBeenCalledWith([], {});
4043
expect(commands.install).toHaveBeenCalledTimes(1);
4144
expect(commands.install).toHaveBeenCalledWith(opts);
4245
});
@@ -46,11 +49,134 @@ describe('cli', () => {
4649
mockedCommands.toAddOptions.mockImplementationOnce(() => opts);
4750
await cli(['add', 'foo', '--dev']);
4851
expect(mockedCommands.toAddOptions).toHaveBeenCalledWith(['foo'], {
49-
'--': [],
5052
dev: true
5153
});
5254
expect(commands.add).toHaveBeenCalledTimes(1);
5355
expect(commands.add).toHaveBeenCalledWith(opts);
5456
});
5557
});
58+
describe('global flags', () => {
59+
it('should parse global flags before a command', async () => {
60+
const opts = {};
61+
mockedCommands.toAddOptions.mockImplementationOnce(() => opts);
62+
await cli(['--no-prefix', 'add', 'foo']);
63+
expect(mockedCommands.toAddOptions).toHaveBeenCalledWith(['foo'], {
64+
prefix: false
65+
});
66+
expect(commands.add).toHaveBeenCalledTimes(1);
67+
expect(commands.add).toHaveBeenCalledWith(opts);
68+
});
69+
it('should parse global flags after a command', async () => {
70+
const opts = {};
71+
mockedCommands.toAddOptions.mockImplementationOnce(() => opts);
72+
await cli(['add', 'foo', '--no-prefix']);
73+
expect(mockedCommands.toAddOptions).toHaveBeenCalledWith(['foo'], {
74+
prefix: false
75+
});
76+
expect(commands.add).toHaveBeenCalledTimes(1);
77+
expect(commands.add).toHaveBeenCalledWith(opts);
78+
});
79+
it('should set global flags in globalOptions store', async () => {
80+
expect(globalOptions.setFromFlags).not.toHaveBeenCalled();
81+
await cli(['add', 'foo', '--no-prefix']);
82+
expect(globalOptions.setFromFlags).toHaveBeenCalledTimes(1);
83+
expect(globalOptions.setFromFlags).toHaveBeenCalledWith({
84+
prefix: false
85+
});
86+
});
87+
});
88+
describe('passing flags to run commands', () => {
89+
it('bolt script --flag1 --flag2', async () => {
90+
const opts = {};
91+
mockedCommands.toRunOptions.mockImplementationOnce(() => opts);
92+
await cli(['script', '--flag1', '--flag2']);
93+
expect(mockedCommands.toRunOptions).toHaveBeenCalledWith(['script'], {
94+
flag1: true,
95+
flag2: true
96+
});
97+
expect(commands.run).toHaveBeenCalledTimes(1);
98+
expect(commands.run).toHaveBeenCalledWith(opts);
99+
});
100+
it('bolt run script --flag1 --flag2', async () => {
101+
const opts = {};
102+
mockedCommands.toRunOptions.mockImplementationOnce(() => opts);
103+
await cli(['run', 'script', '--flag1', '--flag2']);
104+
expect(mockedCommands.toRunOptions).toHaveBeenCalledWith(['script'], {
105+
flag1: true,
106+
flag2: true
107+
});
108+
expect(commands.run).toHaveBeenCalledTimes(1);
109+
expect(commands.run).toHaveBeenCalledWith(opts);
110+
});
111+
it('bolt p run script --flag1 --flag2', async () => {
112+
const opts = {};
113+
mockedCommands.toProjectRunOptions.mockImplementationOnce(() => opts);
114+
await cli(['p', 'run', 'script', '--flag1', '--flag2']);
115+
expect(mockedCommands.toProjectRunOptions).toHaveBeenCalledWith(
116+
['script'],
117+
{
118+
flag1: true,
119+
flag2: true
120+
}
121+
);
122+
expect(commands.projectRun).toHaveBeenCalledTimes(1);
123+
expect(commands.projectRun).toHaveBeenCalledWith(opts);
124+
});
125+
it('bolt w my-package run script --flag1 --flag2', async () => {
126+
const opts = {};
127+
mockedCommands.toWorkspaceRunOptions.mockImplementationOnce(() => opts);
128+
await cli(['w', 'my-package', 'run', 'script', '--flag1', '--flag2']);
129+
expect(mockedCommands.toWorkspaceRunOptions).toHaveBeenCalledWith(
130+
['my-package', 'script'],
131+
{
132+
flag1: true,
133+
flag2: true
134+
}
135+
);
136+
expect(commands.workspaceRun).toHaveBeenCalledTimes(1);
137+
expect(commands.workspaceRun).toHaveBeenCalledWith(opts);
138+
});
139+
it('bolt ws --only="my-package" run script -- --flag1 --flag2', async () => {
140+
const opts = {};
141+
mockedCommands.toWorkspacesRunOptions.mockImplementationOnce(() => opts);
142+
await cli([
143+
'ws',
144+
'--only=my-package',
145+
'run',
146+
'script',
147+
'--',
148+
'--flag1',
149+
'--flag2'
150+
]);
151+
expect(mockedCommands.toWorkspacesRunOptions).toHaveBeenCalledWith(
152+
['script'],
153+
{
154+
'--': ['--flag1', '--flag2'],
155+
only: 'my-package'
156+
}
157+
);
158+
expect(commands.workspacesRun).toHaveBeenCalledTimes(1);
159+
expect(commands.workspacesRun).toHaveBeenCalledWith(opts);
160+
});
161+
it('bolt ws exec --only="my-package" -- yarn script --flag1 --flag2', async () => {
162+
const opts = {};
163+
mockedCommands.toWorkspacesExecOptions.mockImplementationOnce(() => opts);
164+
await cli([
165+
'ws',
166+
'exec',
167+
'--only=my-package',
168+
'--',
169+
'yarn',
170+
'script',
171+
'--flag1',
172+
'--flag2'
173+
]);
174+
expect(mockedCommands.toWorkspacesExecOptions).toHaveBeenCalledWith([], {
175+
'--': ['yarn', 'script', '--flag1', '--flag2'],
176+
only: 'my-package'
177+
});
178+
expect(commands.workspacesExec).toHaveBeenCalledTimes(1);
179+
expect(commands.workspacesExec).toHaveBeenCalledWith(opts);
180+
});
181+
});
56182
});

src/cli.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { BoltError } from './utils/errors';
88
import cleanStack from 'clean-stack';
99
import * as commands from './commands';
1010
import * as options from './utils/options';
11+
import { globalOptions } from './GlobalOptions';
1112

1213
const commandMap = {
1314
ADD: { add: true },
@@ -415,9 +416,15 @@ export default async function cli(argv: Array<string>, exit: boolean = false) {
415416
let { pkg, input, flags } = meow('', {
416417
argv,
417418
flags: {
418-
'--': true
419+
'--': true,
420+
/* Global options as defined in GlobalOptions.js.
421+
* Added here so bolt --<option> <cmd> doesn't parse <cmd> as the value of the <option> flag */
422+
prefix: {
423+
type: 'boolean'
424+
}
419425
},
420-
autoHelp: false
426+
autoHelp: false,
427+
booleanDefault: undefined
421428
});
422429

423430
logger.title(
@@ -429,6 +436,7 @@ export default async function cli(argv: Array<string>, exit: boolean = false) {
429436
processes.handleSignals();
430437

431438
try {
439+
globalOptions.setFromFlags(flags);
432440
await runCommandFromCli(input, flags);
433441
} catch (err) {
434442
if (err instanceof BoltError) {

src/utils/logger.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,12 @@ function fmt(str: Message | Buffer | string, opts: LoggerOpts = {}) {
2828
return result;
2929
}
3030

31-
function prompt(pkg) {
32-
return (pkg ? '(' + pkg.config.getName() + ') ' : '') + '$ ';
31+
function prompt(pkg, cmd) {
32+
let prompt = pkg ? '(' + pkg.config.getName() + ')' : '';
33+
if (!cmd) {
34+
return prompt;
35+
}
36+
return prompt + ' $ ' + cmd;
3337
}
3438

3539
function write(
@@ -81,7 +85,7 @@ export function stdout(
8185
pkg?: Package,
8286
opts: LoggerOpts = {}
8387
) {
84-
let prefix = chalk.cyan(prompt(pkg) + cmd);
88+
let prefix = chalk.cyan(prompt(pkg, cmd));
8589
write(data, { prefix, ...opts }, false);
8690
}
8791

@@ -91,12 +95,12 @@ export function stderr(
9195
pkg?: Package,
9296
opts: LoggerOpts = {}
9397
) {
94-
let prefix = chalk.red(prompt(pkg) + cmd);
98+
let prefix = chalk.red(prompt(pkg, cmd));
9599
write(data, { prefix, ...opts }, true);
96100
}
97101

98102
export function cmd(cmd: string, args: Array<string>, opts: LoggerOpts = {}) {
99-
let msg = chalk.dim(prompt() + cmd);
103+
let msg = chalk.dim(prompt(null, cmd));
100104
if (args.length) {
101105
msg += ' ';
102106
msg += chalk.magenta(args.join(' '));

src/utils/messages.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,9 @@ export function helpContent(): string {
190190
usage
191191
$ bolt [command] <...args> <...opts>
192192
193+
options:
194+
--no-prefix Do not prefix spawned process output with the command string
195+
193196
commands
194197
init init a bolt project
195198
install install a bolt project

src/utils/processes.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type Project from '../Project';
77
import pLimit from 'p-limit';
88
import os from 'os';
99
import path from 'path';
10+
import { globalOptions, type GlobalOptions } from '../GlobalOptions';
1011

1112
const limit = pLimit(os.cpus().length);
1213
const processes = new Set();
@@ -37,6 +38,7 @@ export class ChildProcessError extends Error {
3738
}
3839

3940
export type SpawnOptions = {
41+
...GlobalOptions,
4042
cwd?: string,
4143
pkg?: Package,
4244
silent?: boolean,
@@ -58,7 +60,11 @@ export function spawn(
5860
let isTTY = process.stdout.isTTY && opts.tty;
5961
let cmdDisplayName = opts.useBasename ? path.basename(cmd) : cmd;
6062

61-
let cmdStr = cmdDisplayName + ' ' + args.join(' ');
63+
let displayCmd =
64+
opts.disableCmdPrefix != null
65+
? opts.disableCmdPrefix
66+
: globalOptions.get('disableCmdPrefix');
67+
let cmdStr = displayCmd ? '' : cmdDisplayName + ' ' + args.join(' ');
6268

6369
let spawnOpts: child_process$spawnOpts = {
6470
cwd: opts.cwd,

src/utils/yarn.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ export async function add(
100100
await spawnWithUserAgent(localYarn, spawnArgs, {
101101
cwd: pkg.dir,
102102
pkg: pkg,
103-
tty: true
103+
tty: true,
104+
useBasename: true
104105
});
105106
}
106107

@@ -125,7 +126,8 @@ export async function upgrade(
125126
await spawnWithUserAgent(localYarn, [...spawnArgs, ...flags], {
126127
cwd: pkg.dir,
127128
pkg: pkg,
128-
tty: true
129+
tty: true,
130+
useBasename: true
129131
});
130132
}
131133

@@ -218,7 +220,8 @@ export async function userAgent() {
218220
localYarn,
219221
['config', 'get', 'user-agent'],
220222
{
221-
tty: false
223+
tty: false,
224+
silent: true
222225
}
223226
);
224227

0 commit comments

Comments
 (0)