Skip to content

Commit 56c471a

Browse files
Make bun run --silent omit "error: "..." exited with code 1 (#5459)
* Make --silent behave as expected * Make the "tsconfig.json extends" error a debug level --------- Co-authored-by: Jarred Sumner <[email protected]>
1 parent 20f61b2 commit 56c471a

File tree

4 files changed

+93
-40
lines changed

4 files changed

+93
-40
lines changed

src/cli/run_command.zig

+23-12
Original file line numberDiff line numberDiff line change
@@ -282,15 +282,18 @@ pub const RunCommand = struct {
282282
child_process.stdout_behavior = .Inherit;
283283

284284
const result = child_process.spawnAndWait() catch |err| {
285-
Output.prettyErrorln("<r><red>error<r>: Failed to run script <b>{s}<r> due to error <b>{s}<r>", .{ name, @errorName(err) });
285+
if (!silent) {
286+
Output.prettyErrorln("<r><red>error<r>: Failed to run script <b>{s}<r> due to error <b>{s}<r>", .{ name, @errorName(err) });
287+
}
288+
286289
Output.flush();
287290
return true;
288291
};
289292

290293
switch (result) {
291294
.Exited => |code| {
292295
if (code > 0) {
293-
if (code != 2) {
296+
if (code != 2 and !silent) {
294297
Output.prettyErrorln("<r><red>error<r><d>:<r> script <b>\"{s}\"<r> exited with {any}<r>", .{ name, bun.SignalCode.from(code) });
295298
Output.flush();
296299
}
@@ -299,14 +302,18 @@ pub const RunCommand = struct {
299302
}
300303
},
301304
.Signal => |signal| {
302-
Output.prettyErrorln("<r><red>error<r><d>:<r> script <b>\"{s}\"<r> exited with {any}<r>", .{ name, bun.SignalCode.from(signal) });
303-
Output.flush();
305+
if (!silent) {
306+
Output.prettyErrorln("<r><red>error<r><d>:<r> script <b>\"{s}\"<r> exited with {any}<r>", .{ name, bun.SignalCode.from(signal) });
307+
Output.flush();
308+
}
304309

305310
Global.exit(1);
306311
},
307312
.Stopped => |signal| {
308-
Output.prettyErrorln("<r><red>error<r><d>:<r> script <b>\"{s}\"<r> was stopped by signal {any}<r>", .{ name, bun.SignalCode.from(signal) });
309-
Output.flush();
313+
if (!silent) {
314+
Output.prettyErrorln("<r><red>error<r><d>:<r> script <b>\"{s}\"<r> was stopped by signal {any}<r>", .{ name, bun.SignalCode.from(signal) });
315+
Output.flush();
316+
}
310317

311318
Global.exit(1);
312319
},
@@ -341,6 +348,7 @@ pub const RunCommand = struct {
341348
child_process.stderr_behavior = .Inherit;
342349
child_process.stdin_behavior = .Inherit;
343350
child_process.stdout_behavior = .Inherit;
351+
const silent = ctx.debug.silent;
344352

345353
const result = child_process.spawnAndWait() catch |err| {
346354
if (err == error.AccessDenied) {
@@ -349,7 +357,8 @@ pub const RunCommand = struct {
349357
const rc = bun.C.stat(executable[0.. :0].ptr, &stat);
350358
if (rc == 0) {
351359
if (std.os.S.ISDIR(stat.mode)) {
352-
Output.prettyErrorln("<r><red>error<r>: Failed to run directory \"<b>{s}<r>\"\n", .{executable});
360+
if (!silent)
361+
Output.prettyErrorln("<r><red>error<r>: Failed to run directory \"<b>{s}<r>\"\n", .{executable});
353362
Global.exit(1);
354363
}
355364
}
@@ -361,24 +370,25 @@ pub const RunCommand = struct {
361370
switch (result) {
362371
.Exited => |sig| {
363372
// 2 is SIGINT, which is CTRL + C so that's kind of annoying to show
364-
if (sig > 0 and sig != 2)
373+
if (sig > 0 and sig != 2 and !silent)
365374
Output.prettyErrorln("<r><red>error<r><d>:<r> \"<b>{s}<r>\" exited with <b>{any}<r>", .{ std.fs.path.basename(executable), bun.SignalCode.from(sig) });
366375
Global.exit(sig);
367376
},
368377
.Signal => |sig| {
369378
// 2 is SIGINT, which is CTRL + C so that's kind of annoying to show
370-
if (sig > 0 and sig != 2) {
379+
if (sig > 0 and sig != 2 and !silent) {
371380
Output.prettyErrorln("<r><red>error<r><d>:<r> \"<b>{s}<r>\" exited with <b>{any}<r>", .{ std.fs.path.basename(executable), bun.SignalCode.from(sig) });
372381
}
373382
Global.exit(std.mem.asBytes(&sig)[0]);
374383
},
375384
.Stopped => |sig| {
376-
if (sig > 0)
385+
if (sig > 0 and !silent)
377386
Output.prettyErrorln("<r><red>error<r> \"<b>{s}<r>\" stopped with {any}<r>", .{ std.fs.path.basename(executable), bun.SignalCode.from(sig) });
378387
Global.exit(std.mem.asBytes(&sig)[0]);
379388
},
380389
.Unknown => |sig| {
381-
Output.prettyErrorln("<r><red>error<r> \"<b>{s}<r>\" stopped: {d}<r>", .{ std.fs.path.basename(executable), sig });
390+
if (!silent)
391+
Output.prettyErrorln("<r><red>error<r> \"<b>{s}<r>\" stopped: {d}<r>", .{ std.fs.path.basename(executable), sig });
382392
Global.exit(1);
383393
},
384394
}
@@ -955,7 +965,8 @@ pub const RunCommand = struct {
955965
// "White space after #! is optional."
956966
var shebang_buf: [64]u8 = undefined;
957967
const shebang_size = file.pread(&shebang_buf, 0) catch |err| {
958-
Output.prettyErrorln("<r><red>error<r>: Failed to read file <b>{s}<r> due to error <b>{s}<r>", .{ file_path, @errorName(err) });
968+
if (!ctx.debug.silent)
969+
Output.prettyErrorln("<r><red>error<r>: Failed to read file <b>{s}<r> due to error <b>{s}<r>", .{ file_path, @errorName(err) });
959970
Global.exit(1);
960971
};
961972

src/logger.zig

+3-3
Original file line numberDiff line numberDiff line change
@@ -703,12 +703,12 @@ pub const Log = struct {
703703
};
704704
}
705705

706-
pub fn addVerboseFmt(log: *Log, source: ?*const Source, l: Loc, allocator: std.mem.Allocator, comptime text: string, args: anytype) !void {
707-
if (!Kind.shouldPrint(.verbose, log.level)) return;
706+
pub fn addDebugFmt(log: *Log, source: ?*const Source, l: Loc, allocator: std.mem.Allocator, comptime text: string, args: anytype) !void {
707+
if (!Kind.shouldPrint(.debug, log.level)) return;
708708

709709
@setCold(true);
710710
try log.addMsg(.{
711-
.kind = .verbose,
711+
.kind = .debug,
712712
.data = try rangeData(source, Range{ .loc = l }, allocPrint(allocator, text, args) catch unreachable).cloneLineText(log.clone_line_text, log.msgs.allocator),
713713
});
714714
}

src/resolver/resolver.zig

+1-1
Original file line numberDiff line numberDiff line change
@@ -3887,7 +3887,7 @@ pub const Resolver = struct {
38873887
// not sure why this needs cwd but we'll just pass in the dir of the tsconfig...
38883888
var abs_path = ResolvePath.joinAbsStringBuf(ts_dir_name, bufs(.tsconfig_path_abs), &[_]string{ ts_dir_name, current.extends }, .auto);
38893889
var parent_config_maybe = r.parseTSConfig(abs_path, 0) catch |err| {
3890-
r.log.addVerboseFmt(null, logger.Loc.Empty, r.allocator, "{s} loading tsconfig.json extends {}", .{ @errorName(err), strings.QuotedFormatter{
3890+
r.log.addDebugFmt(null, logger.Loc.Empty, r.allocator, "{s} loading tsconfig.json extends {}", .{ @errorName(err), strings.QuotedFormatter{
38913891
.text = abs_path,
38923892
} }) catch {};
38933893
break;

test/cli/install/bun-run.test.ts

+66-24
Original file line numberDiff line numberDiff line change
@@ -87,39 +87,81 @@ for (let withRun of [false, true]) {
8787
expect(exitCode).toBe(0);
8888
});
8989

90-
it("valid tsconfig.json with invalid extends doesn't crash", async () => {
91-
await writeFile(
92-
join(run_dir, "package.json"),
93-
JSON.stringify({
94-
name: "test",
95-
version: "0.0.0",
96-
scripts: {},
97-
}),
98-
);
99-
await writeFile(
100-
join(run_dir, "tsconfig.json"),
101-
JSON.stringify(
102-
{
103-
extends: "!!!bad!!!",
104-
},
105-
null,
106-
2,
107-
),
108-
);
90+
it("--silent omits error messages", async () => {
91+
const { stdout, stderr, exitCode } = spawnSync({
92+
cmd: [bunExe(), "run", "--silent", "bash", "-c", "exit 1"],
93+
cwd: run_dir,
94+
env: bunEnv,
95+
});
10996

110-
await writeFile(join(run_dir, "index.js"), "console.log('hi')");
97+
expect(stderr.toString()).toBe("");
98+
expect(stdout.toString()).toBe("");
99+
expect(exitCode).toBe(1);
100+
});
111101

102+
it("no --silent includes error messages", async () => {
112103
const { stdout, stderr, exitCode } = spawnSync({
113-
cmd: [bunExe(), "--silent", withRun ? "run" : "", "./index.js"].filter(Boolean),
104+
cmd: [bunExe(), "run", "bash", "-c", "exit 1"],
114105
cwd: run_dir,
115106
env: bunEnv,
116107
});
117108

118-
expect(stderr.toString().trim()).toContain("FileNotFound loading tsconfig.json extends");
119-
expect(stdout.toString()).toBe("hi\n");
120-
expect(exitCode).toBe(0);
109+
expect(stderr.toString()).toStartWith('error: "bash" exited with code 1');
110+
expect(exitCode).toBe(1);
121111
});
122112

113+
for (let withLogLevel of [true, false]) {
114+
it(
115+
"valid tsconfig.json with invalid extends doesn't crash" + (withLogLevel ? " (log level debug)" : ""),
116+
async () => {
117+
await writeFile(
118+
join(run_dir, "package.json"),
119+
JSON.stringify({
120+
name: "test",
121+
version: "0.0.0",
122+
scripts: {},
123+
}),
124+
);
125+
if (withLogLevel)
126+
await writeFile(
127+
join(run_dir, "bunfig.toml"),
128+
`
129+
logLevel = "debug"
130+
`,
131+
);
132+
133+
await writeFile(
134+
join(run_dir, "tsconfig.json"),
135+
JSON.stringify(
136+
{
137+
extends: "!!!bad!!!",
138+
},
139+
null,
140+
2,
141+
),
142+
);
143+
144+
await writeFile(join(run_dir, "index.js"), "console.log('hi')");
145+
146+
const { stdout, stderr, exitCode } = spawnSync({
147+
// TODO: figure out why -c is necessary here.
148+
cmd: [bunExe(), withRun ? "run" : "", "-c=" + join(run_dir, "bunfig.toml"), "./index.js"].filter(Boolean),
149+
cwd: run_dir,
150+
env: bunEnv,
151+
});
152+
if (withLogLevel) {
153+
expect(stderr.toString().trim()).toContain("FileNotFound loading tsconfig.json extends");
154+
} else {
155+
expect(stderr.toString().trim()).not.toContain("FileNotFound loading tsconfig.json extends");
156+
}
157+
158+
expect(stdout.toString()).toBe("hi\n");
159+
expect(exitCode).toBe(0);
160+
await rm(join(run_dir, "bunfig.toml"), { force: true });
161+
},
162+
);
163+
}
164+
123165
it("falling back to index with no package.json", async () => {
124166
await writeFile(join(run_dir, "index.ts"), "console.log('Hello, world!');");
125167

0 commit comments

Comments
 (0)