Skip to content
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
53 changes: 53 additions & 0 deletions src/cli.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { describe, expect, it } from "bun:test";

const readStream = async (stream: ReadableStream<Uint8Array> | null): Promise<string> => {
if (!stream) {
return "";
}
return await new Response(stream).text();
};

const packageVersion = async (): Promise<string> => {
const packageJson = (await Bun.file(`${import.meta.dir}/../package.json`).json()) as {
version: string;
};
return packageJson.version;
};

const runWorkbox = async (args: string[]) => {
const proc = Bun.spawn(["bun", "./src/cli.ts", ...args], {
cwd: `${import.meta.dir}/..`,
stdout: "pipe",
stderr: "pipe",
});
const [stdout, stderr, exitCode] = await Promise.all([
readStream(proc.stdout),
readStream(proc.stderr),
proc.exited,
]);
return { stdout, stderr, exitCode };
};

describe("cli", () => {
it("prints the package version", async () => {
const version = await packageVersion();
const result = await runWorkbox(["--version"]);

expect(result.exitCode).toBe(0);
expect(result.stderr).toBe("");
expect(result.stdout).toBe(`workbox ${version}\n`);
});

it("prints the package version as JSON", async () => {
const version = await packageVersion();
const result = await runWorkbox(["--json", "--version"]);

expect(result.exitCode).toBe(0);
expect(result.stderr).toBe("");
expect(JSON.parse(result.stdout)).toEqual({
ok: true,
message: `workbox ${version}`,
data: { version },
});
});
});
23 changes: 23 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ const TOOL_ALIAS = "wkb";

type OutputTarget = NodeJS.WritableStream;

const loadPackageVersion = async (): Promise<string> => {
const packageJson = (await Bun.file(new URL("../package.json", import.meta.url)).json()) as {
version?: unknown;
};
return typeof packageJson.version === "string" ? packageJson.version : "unknown";
};

const writeOutput = (output: string, stream: OutputTarget): void => {
if (output.trim().length === 0) {
return;
Expand All @@ -27,6 +34,22 @@ export const runCli = async (argv: string[], cwd = process.cwd()): Promise<numbe
throw new UsageError(`${parsed.errors.join(" ")} Run '${TOOL_NAME} --help' for usage.`);
}

if (parsed.flags.version) {
const version = await loadPackageVersion();
writeOutput(
formatOutput(
{
ok: true,
message: `${TOOL_NAME} ${version}`,
data: { version },
},
outputMode
),
process.stdout
);
return 0;
}

if (parsed.flags.nonInteractive) {
process.env.CI ??= "1";
process.env.GIT_TERMINAL_PROMPT ??= "0";
Expand Down
7 changes: 7 additions & 0 deletions src/cli/args.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ describe("parseCliArgs", () => {
expect(result.command).toBe("list");
});

it("parses version flag", () => {
const result = parseCliArgs(["--version"]);
expect(result.flags.version).toBe(true);
expect(result.command).toBeNull();
expect(result.errors).toEqual([]);
});

it("treats passthrough options as the command when no command is set", () => {
const result = parseCliArgs(["--", "--do", "thing"]);
expect(result.command).toBe("--do");
Expand Down
5 changes: 5 additions & 0 deletions src/cli/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ type CliFlags = {
help: boolean;
json: boolean;
nonInteractive: boolean;
version: boolean;
};

type ParsedArgs = {
Expand All @@ -17,6 +18,7 @@ const GLOBAL_OPTIONS = {
help: { type: "boolean", short: "h" },
json: { type: "boolean" },
"non-interactive": { type: "boolean" },
version: { type: "boolean" },
} as const;

type ParsedToken =
Expand Down Expand Up @@ -46,6 +48,8 @@ const flagFromOption = (name: string): keyof CliFlags | null => {
return "json";
case "non-interactive":
return "nonInteractive";
case "version":
return "version";
default:
return null;
}
Expand Down Expand Up @@ -74,6 +78,7 @@ export const parseCliArgs = (argv: string[]): ParsedArgs => {
help: false,
json: false,
nonInteractive: false,
version: false,
};
const errors: string[] = [];
const commandArgs: string[] = [];
Expand Down
2 changes: 2 additions & 0 deletions src/cli/help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const renderGlobalHelp = (toolName: string, alias: string): string => {
" --help Show help for a command",
" --json Output machine-readable JSON",
" --non-interactive Disable prompts and fail fast",
" --version Show the current version",
].join("\n");
};

Expand All @@ -37,4 +38,5 @@ export const renderCommandHelp = (toolName: string, command: CommandDefinition):
" --help Show help for this command",
" --json Output machine-readable JSON",
" --non-interactive Disable prompts and fail fast",
" --version Show the current version",
].join("\n");