From 803181ae7c88d7ef9f063e6b3bc038cd56a2a065 Mon Sep 17 00:00:00 2001 From: jarred-sumner-bot Date: Tue, 15 Jul 2025 01:14:58 -0700 Subject: [PATCH] Add --quiet flag to bun pm pack command (#21053) Co-authored-by: Claude Bot Co-authored-by: Claude Co-authored-by: jarred-sumner-bot <220441119+jarred-sumner-bot@users.noreply.github.com> Co-authored-by: Jarred Sumner --- docs/cli/pm.md | 67 +++++++++++++++++-- src/cli/pack_command.zig | 10 +-- src/cli/package_manager_command.zig | 3 +- .../PackageManager/CommandLineArguments.zig | 3 + .../PackageManager/PackageManagerOptions.zig | 4 ++ test/cli/install/bun-pack.test.ts | 29 ++++++++ 6 files changed, 105 insertions(+), 11 deletions(-) diff --git a/docs/cli/pm.md b/docs/cli/pm.md index 577ab383cd..5d0a29d1ef 100644 --- a/docs/cli/pm.md +++ b/docs/cli/pm.md @@ -8,15 +8,70 @@ To create a tarball of the current workspace: $ bun pm pack ``` -Options for the `pack` command: +This command creates a `.tgz` file containing all files that would be published to npm, following the same rules as `npm pack`. -- `--dry-run`: Perform all tasks except writing the tarball to disk. -- `--destination`: Specify the directory where the tarball will be saved. -- `--filename`: Specify an exact file name for the tarball to be saved at. +## Examples + +Basic usage: + +```bash +$ bun pm pack +# Creates my-package-1.0.0.tgz in current directory +``` + +Quiet mode for scripting: + +```bash +$ TARBALL=$(bun pm pack --quiet) +$ echo "Created: $TARBALL" +# Output: Created: my-package-1.0.0.tgz +``` + +Custom destination: + +```bash +$ bun pm pack --destination ./dist +# Saves tarball in ./dist/ directory +``` + +## Options + +- `--dry-run`: Perform all tasks except writing the tarball to disk. Shows what would be included. +- `--destination `: Specify the directory where the tarball will be saved. +- `--filename `: Specify an exact file name for the tarball to be saved at. - `--ignore-scripts`: Skip running pre/postpack and prepare scripts. -- `--gzip-level`: Set a custom compression level for gzip, ranging from 0 to 9 (default is 9). +- `--gzip-level <0-9>`: Set a custom compression level for gzip, ranging from 0 to 9 (default is 9). +- `--quiet`: Only output the tarball filename, suppressing verbose output. Ideal for scripts and automation. -> Note `--filename` and `--destination` cannot be used at the same time +> **Note:** `--filename` and `--destination` cannot be used at the same time. + +## Output Modes + +**Default output:** + +```bash +$ bun pm pack +bun pack v1.2.19 + +packed 131B package.json +packed 40B index.js + +my-package-1.0.0.tgz + +Total files: 2 +Shasum: f2451d6eb1e818f500a791d9aace80b394258a90 +Unpacked size: 171B +Packed size: 249B +``` + +**Quiet output:** + +```bash +$ bun pm pack --quiet +my-package-1.0.0.tgz +``` + +The `--quiet` flag is particularly useful for automation workflows where you need to capture the generated tarball filename for further processing. ## bin diff --git a/src/cli/pack_command.zig b/src/cli/pack_command.zig index 35e427ee49..8945aee711 100644 --- a/src/cli/pack_command.zig +++ b/src/cli/pack_command.zig @@ -63,7 +63,7 @@ pub const PackCommand = struct { maybe_integrity: ?[sha.SHA512.digest]u8, log_level: LogLevel, ) void { - if (log_level != .silent) { + if (log_level != .silent and log_level != .quiet) { Output.prettyln("\nTotal files: {d}", .{stats.total_files}); if (maybe_shasum) |shasum| { Output.prettyln("Shasum: {s}", .{std.fmt.bytesToHex(shasum, .lower)}); @@ -93,8 +93,10 @@ pub const PackCommand = struct { }; pub fn execWithManager(ctx: Command.Context, manager: *PackageManager) !void { - Output.prettyln("bun pack v" ++ Global.package_json_version_with_sha ++ "", .{}); - Output.flush(); + if (manager.options.log_level != .silent and manager.options.log_level != .quiet) { + Output.prettyln("bun pack v" ++ Global.package_json_version_with_sha ++ "", .{}); + Output.flush(); + } var lockfile: Lockfile = undefined; const load_from_disk_result = lockfile.loadFromCwd( @@ -2426,7 +2428,7 @@ pub const PackCommand = struct { package_json_len: usize, ) void { const root_dir = bun.FD.fromStdDir(root_dir_std); - if (ctx.manager.options.log_level == .silent) return; + if (ctx.manager.options.log_level == .silent or ctx.manager.options.log_level == .quiet) return; const packed_fmt = "packed {} {s}"; if (comptime is_dry_run) { diff --git a/src/cli/package_manager_command.zig b/src/cli/package_manager_command.zig index 9d22dc4c1c..113c53d2f2 100644 --- a/src/cli/package_manager_command.zig +++ b/src/cli/package_manager_command.zig @@ -121,7 +121,8 @@ pub const PackageManagerCommand = struct { \\ --destination the directory the tarball will be saved in \\ --filename the name of the tarball \\ --ignore-scripts don't run pre/postpack and prepare scripts - \\ --gzip-level specify a custom compression level for gzip (0-9, default is 9) + \\ --gzip-level specify a custom compression level for gzip (0-9, default is 9) + \\ --quiet only output the tarball filename \\ bun pm bin print the path to bin folder \\ -g print the global path to bin folder \\ bun pm ls list the dependency tree according to the current lockfile diff --git a/src/install/PackageManager/CommandLineArguments.zig b/src/install/PackageManager/CommandLineArguments.zig index a3251006ad..8e795ba3f4 100644 --- a/src/install/PackageManager/CommandLineArguments.zig +++ b/src/install/PackageManager/CommandLineArguments.zig @@ -32,6 +32,7 @@ const shared_params = [_]ParamType{ clap.parseParam("--cache-dir Store & load cached data from a specific directory path") catch unreachable, clap.parseParam("--no-cache Ignore manifest cache entirely") catch unreachable, clap.parseParam("--silent Don't log anything") catch unreachable, + clap.parseParam("--quiet Only show tarball name when packing") catch unreachable, clap.parseParam("--verbose Excessively verbose logging") catch unreachable, clap.parseParam("--no-progress Disable the progress bar") catch unreachable, clap.parseParam("--no-summary Don't print a summary") catch unreachable, @@ -168,6 +169,7 @@ dry_run: bool = false, force: bool = false, no_cache: bool = false, silent: bool = false, +quiet: bool = false, verbose: bool = false, no_progress: bool = false, no_verify: bool = false, @@ -672,6 +674,7 @@ pub fn parse(allocator: std.mem.Allocator, comptime subcommand: Subcommand) !Com cli.no_verify = args.flag("--no-verify"); cli.no_cache = args.flag("--no-cache"); cli.silent = args.flag("--silent"); + cli.quiet = args.flag("--quiet"); cli.verbose = args.flag("--verbose") or Output.is_verbose; cli.ignore_scripts = args.flag("--ignore-scripts"); cli.trusted = args.flag("--trust"); diff --git a/src/install/PackageManager/PackageManagerOptions.zig b/src/install/PackageManager/PackageManagerOptions.zig index 764d352a3a..919786e15f 100644 --- a/src/install/PackageManager/PackageManagerOptions.zig +++ b/src/install/PackageManager/PackageManagerOptions.zig @@ -101,6 +101,7 @@ pub const LogLevel = enum { default, verbose, silent, + quiet, default_no_progress, verbose_no_progress, @@ -511,6 +512,9 @@ pub fn load( } else if (cli.silent) { this.log_level = .silent; PackageManager.verbose_install = false; + } else if (cli.quiet) { + this.log_level = .quiet; + PackageManager.verbose_install = false; } else { this.log_level = if (disable_progress_bar) LogLevel.default_no_progress else LogLevel.default; PackageManager.verbose_install = false; diff --git a/test/cli/install/bun-pack.test.ts b/test/cli/install/bun-pack.test.ts index ec969e1c67..59b5044be9 100644 --- a/test/cli/install/bun-pack.test.ts +++ b/test/cli/install/bun-pack.test.ts @@ -394,6 +394,35 @@ describe("flags", () => { expect(results).toEqual([true, true, false, true, false]); }); + + test("--quiet", async () => { + await Promise.all([ + write( + join(packageDir, "package.json"), + JSON.stringify({ + name: "pack-quiet-test", + version: "1.1.1", + }), + ), + write(join(packageDir, "index.js"), "console.log('hello ./index.js')"), + ]); + + const { out } = await pack(packageDir, bunEnv, "--quiet"); + + // Should not contain verbose output + expect(out).not.toContain("Total files:"); + expect(out).not.toContain("Shasum:"); + expect(out).not.toContain("Integrity:"); + expect(out).not.toContain("Unpacked size:"); + expect(out).not.toContain("Packed size:"); + expect(out).not.toContain("bun pack v"); + + // Should only contain the tarball name + expect(out.trim()).toBe("pack-quiet-test-1.1.1.tgz"); + + // Should still create the tarball + expect(await exists(join(packageDir, "pack-quiet-test-1.1.1.tgz"))).toBeTrue(); + }); }); test("shasum and integrity are consistent", async () => {