goke 6.5.1 → 6.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -9
- package/dist/__test__/readme-examples.test.d.ts +5 -0
- package/dist/__test__/readme-examples.test.d.ts.map +1 -0
- package/dist/__test__/readme-examples.test.js +169 -0
- package/dist/__test__/types.test-d.js +238 -1
- package/dist/goke.d.ts +105 -16
- package/dist/goke.d.ts.map +1 -1
- package/dist/goke.js +21 -1
- package/dist/runtime-node.js +2 -2
- package/package.json +2 -2
- package/src/__test__/readme-examples.test.ts +225 -0
- package/src/__test__/types.test-d.ts +262 -1
- package/src/goke.ts +148 -15
- package/src/runtime-node.ts +2 -2
package/dist/goke.d.ts
CHANGED
|
@@ -73,6 +73,70 @@ type OptionEntry<RawName extends string, Schema> = IsOptionalOption<RawName> ext
|
|
|
73
73
|
} : {
|
|
74
74
|
[K in ExtractOptionName<RawName>]: InferSchemaOutput<Schema>;
|
|
75
75
|
};
|
|
76
|
+
/**
|
|
77
|
+
* Infer the raw runtime value shape for an option declared without a schema.
|
|
78
|
+
*
|
|
79
|
+
* Required value options (`--port <port>`) always reach actions as strings.
|
|
80
|
+
* Optional value options (`--host [host]`) can be strings, the sentinel
|
|
81
|
+
* boolean `true` when passed without a value, or `undefined` when omitted.
|
|
82
|
+
* Plain flags (`--verbose`) are booleans.
|
|
83
|
+
*/
|
|
84
|
+
type UntypedOptionValue<RawName extends string> = RawName extends `${string}<${string}>` ? string : RawName extends `${string}[${string}]` ? string | boolean | undefined : boolean | undefined;
|
|
85
|
+
/**
|
|
86
|
+
* Build the option type entry for a `.option()` call that uses a plain
|
|
87
|
+
* description (no schema).
|
|
88
|
+
*/
|
|
89
|
+
type UntypedOptionEntry<RawName extends string> = RawName extends `${string}<${string}>` ? {
|
|
90
|
+
[K in ExtractOptionName<RawName>]: UntypedOptionValue<RawName>;
|
|
91
|
+
} : {
|
|
92
|
+
[K in ExtractOptionName<RawName>]?: UntypedOptionValue<RawName>;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Tokenize a command raw name by splitting on whitespace.
|
|
96
|
+
* "mcp getNodeXml <id>" → ["mcp", "getNodeXml", "<id>"]
|
|
97
|
+
* "" → []
|
|
98
|
+
*/
|
|
99
|
+
type TokenizeName<S extends string, Acc extends readonly string[] = []> = S extends `${infer Head} ${infer Rest}` ? TokenizeName<Rest, [...Acc, Head]> : S extends '' ? Acc : [...Acc, S];
|
|
100
|
+
/**
|
|
101
|
+
* Given a single token, return the corresponding positional arg type or
|
|
102
|
+
* `never` if the token is not a bracketed arg.
|
|
103
|
+
*
|
|
104
|
+
* `<id>` → string (required)
|
|
105
|
+
* `[id]` → string | undefined (optional)
|
|
106
|
+
* `<...files>` → string[] (variadic required)
|
|
107
|
+
* `[...files]` → string[] (variadic optional)
|
|
108
|
+
* Anything else → never (filtered out by ExtractCommandArgs)
|
|
109
|
+
*/
|
|
110
|
+
type TokenToArgType<T extends string> = T extends `<...${string}>` ? string[] : T extends `[...${string}]` ? string[] : T extends `<${string}>` ? string : T extends `[${string}]` ? string | undefined : never;
|
|
111
|
+
/**
|
|
112
|
+
* Filter a tokenized command raw name down to the positional arg tokens
|
|
113
|
+
* and map each to its inferred type.
|
|
114
|
+
*/
|
|
115
|
+
type ExtractCommandArgs<T extends readonly string[]> = T extends readonly [infer Head extends string, ...infer Tail extends string[]] ? [TokenToArgType<Head>] extends [never] ? ExtractCommandArgs<Tail> : [TokenToArgType<Head>, ...ExtractCommandArgs<Tail>] : [];
|
|
116
|
+
/**
|
|
117
|
+
* Extract the tuple of positional arg types from a command raw name.
|
|
118
|
+
*
|
|
119
|
+
* "mcp getNodeXml <id>" → [string]
|
|
120
|
+
* "convert <input> <output>" → [string, string]
|
|
121
|
+
* "run [script]" → [string | undefined]
|
|
122
|
+
* "exec [...args]" → [string[]]
|
|
123
|
+
* "deploy" → []
|
|
124
|
+
*/
|
|
125
|
+
type ExtractPositionalArgs<RawName extends string> = ExtractCommandArgs<TokenizeName<RawName>>;
|
|
126
|
+
/**
|
|
127
|
+
* Build the full argument tuple passed to a command's action callback.
|
|
128
|
+
*
|
|
129
|
+
* Format: [...positionalArgs, options, executionContext]
|
|
130
|
+
*
|
|
131
|
+
* This matches the runtime behavior in Goke.runMatchedCommand(): the action
|
|
132
|
+
* is called with positional args from the parsed command, then the parsed
|
|
133
|
+
* options object, then the injected GokeExecutionContext.
|
|
134
|
+
*/
|
|
135
|
+
type ActionArgs<RawName extends string, Opts> = [
|
|
136
|
+
...ExtractPositionalArgs<RawName>,
|
|
137
|
+
Opts,
|
|
138
|
+
GokeExecutionContext
|
|
139
|
+
];
|
|
76
140
|
interface CommandArg {
|
|
77
141
|
required: boolean;
|
|
78
142
|
value: string;
|
|
@@ -88,8 +152,8 @@ interface CommandConfig {
|
|
|
88
152
|
}
|
|
89
153
|
type HelpCallback = (sections: HelpSection[]) => void | HelpSection[];
|
|
90
154
|
type CommandExample = ((bin: string) => string) | string;
|
|
91
|
-
declare class Command {
|
|
92
|
-
rawName:
|
|
155
|
+
declare class Command<RawName extends string = string, Opts = {}> {
|
|
156
|
+
rawName: RawName;
|
|
93
157
|
description: string;
|
|
94
158
|
config: CommandConfig;
|
|
95
159
|
cli: Goke<any>;
|
|
@@ -104,7 +168,7 @@ declare class Command {
|
|
|
104
168
|
helpCallback?: HelpCallback;
|
|
105
169
|
globalCommand?: GlobalCommand;
|
|
106
170
|
_hidden?: boolean;
|
|
107
|
-
constructor(rawName:
|
|
171
|
+
constructor(rawName: RawName, description: string, config: CommandConfig | undefined, cli: Goke<any>);
|
|
108
172
|
usage(text: string): this;
|
|
109
173
|
allowUnknownOptions(): this;
|
|
110
174
|
ignoreOptionDefaultValue(): this;
|
|
@@ -115,7 +179,9 @@ declare class Command {
|
|
|
115
179
|
*
|
|
116
180
|
* The second argument is either a description string or a StandardJSONSchemaV1
|
|
117
181
|
* schema. When a schema is provided, description and default are extracted from
|
|
118
|
-
* the JSON Schema automatically
|
|
182
|
+
* the JSON Schema automatically, and the option's type is tracked on the
|
|
183
|
+
* Command's `Opts` type parameter so that subsequent `.action()` callbacks
|
|
184
|
+
* receive a fully-typed options object.
|
|
119
185
|
*
|
|
120
186
|
* @example
|
|
121
187
|
* ```ts
|
|
@@ -126,13 +192,26 @@ declare class Command {
|
|
|
126
192
|
* cmd.option('--verbose', 'Verbose output')
|
|
127
193
|
* ```
|
|
128
194
|
*/
|
|
129
|
-
option<
|
|
130
|
-
|
|
131
|
-
};
|
|
132
|
-
option(rawName: string, descriptionOrSchema?: string | StandardJSONSchemaV1): this;
|
|
195
|
+
option<OptionRawName extends string, S extends StandardJSONSchemaV1>(rawName: OptionRawName, schema: S): Command<RawName, Opts & OptionEntry<OptionRawName, S>>;
|
|
196
|
+
option<OptionRawName extends string>(rawName: OptionRawName, description?: string): Command<RawName, Opts & UntypedOptionEntry<OptionRawName>>;
|
|
133
197
|
alias(name: string): this;
|
|
134
198
|
hidden(): this;
|
|
135
|
-
|
|
199
|
+
/**
|
|
200
|
+
* Register the action callback that runs when this command is matched.
|
|
201
|
+
*
|
|
202
|
+
* The callback receives positional args extracted from the command's raw name,
|
|
203
|
+
* followed by the parsed options object and the injected GokeExecutionContext.
|
|
204
|
+
*
|
|
205
|
+
* Positional arg types are inferred from the raw name at the type level:
|
|
206
|
+
* `command('convert <input> <output>')` → `(input: string, output: string, options, ctx)`
|
|
207
|
+
* `command('run [script]')` → `(script: string | undefined, options, ctx)`
|
|
208
|
+
* `command('exec [...args]')` → `(args: string[], options, ctx)`
|
|
209
|
+
*
|
|
210
|
+
* The options object is typed according to every `.option()` call chained
|
|
211
|
+
* on this command, plus any global options declared on the parent Goke
|
|
212
|
+
* instance before `.command()` was called.
|
|
213
|
+
*/
|
|
214
|
+
action(callback: (...args: ActionArgs<RawName, Opts>) => unknown | Promise<unknown>): this;
|
|
136
215
|
isMatched(args: string[]): {
|
|
137
216
|
matched: boolean;
|
|
138
217
|
consumedArgs: number;
|
|
@@ -242,17 +321,17 @@ interface ParsedArgv {
|
|
|
242
321
|
[k: string]: any;
|
|
243
322
|
};
|
|
244
323
|
}
|
|
245
|
-
declare class Goke<Opts
|
|
324
|
+
declare class Goke<Opts = {}> extends EventEmitter {
|
|
246
325
|
#private;
|
|
247
326
|
/** The program name to display in help and version message */
|
|
248
327
|
name: string;
|
|
249
|
-
commands: Command[];
|
|
328
|
+
commands: Command<any, any>[];
|
|
250
329
|
/** Middleware functions that run before the matched command action, in registration order */
|
|
251
330
|
middlewares: Array<{
|
|
252
331
|
action: (options: any, context: GokeExecutionContext) => void | Promise<void>;
|
|
253
332
|
}>;
|
|
254
333
|
globalCommand: GlobalCommand;
|
|
255
|
-
matchedCommand?: Command
|
|
334
|
+
matchedCommand?: Command<any, any>;
|
|
256
335
|
matchedCommandName?: string;
|
|
257
336
|
/**
|
|
258
337
|
* Raw CLI arguments
|
|
@@ -303,19 +382,29 @@ declare class Goke<Opts extends Record<string, any> = {}> extends EventEmitter {
|
|
|
303
382
|
*/
|
|
304
383
|
usage(text: string): this;
|
|
305
384
|
/**
|
|
306
|
-
* Add a sub-command
|
|
385
|
+
* Add a sub-command.
|
|
386
|
+
*
|
|
387
|
+
* The returned Command is parameterized by the literal `rawName` (so positional
|
|
388
|
+
* args can be inferred at the type level) and by this Goke's accumulated global
|
|
389
|
+
* `Opts` (so global options declared before `.command()` are visible inside
|
|
390
|
+
* `.action()` callbacks alongside the command's own options).
|
|
307
391
|
*/
|
|
308
|
-
command(rawName:
|
|
392
|
+
command<CommandRawName extends string>(rawName: CommandRawName, description?: string, config?: CommandConfig): Command<CommandRawName, Opts>;
|
|
309
393
|
/**
|
|
310
394
|
* Add a global CLI option.
|
|
311
395
|
*
|
|
312
396
|
* Which is also applied to sub-commands.
|
|
313
397
|
*
|
|
314
398
|
* When a StandardJSONSchemaV1 schema is provided, the return type is narrowed
|
|
315
|
-
* to include the inferred option type — enabling type-safe `.use()` callbacks
|
|
399
|
+
* to include the inferred option type — enabling type-safe `.use()` callbacks
|
|
400
|
+
* and typed `options` params inside command `.action()` handlers.
|
|
401
|
+
*
|
|
402
|
+
* When a plain description string is provided, the option is still tracked on
|
|
403
|
+
* the Goke's `Opts` type, but with a loose `string | boolean | undefined` value
|
|
404
|
+
* type (since no coercion schema is available).
|
|
316
405
|
*/
|
|
317
406
|
option<RawName extends string, S extends StandardJSONSchemaV1>(rawName: RawName, schema: S): Goke<Opts & OptionEntry<RawName, S>>;
|
|
318
|
-
option(rawName:
|
|
407
|
+
option<RawName extends string>(rawName: RawName, description?: string): Goke<Opts & UntypedOptionEntry<RawName>>;
|
|
319
408
|
/**
|
|
320
409
|
* Register a middleware function that runs before the matched command action.
|
|
321
410
|
*
|
package/dist/goke.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"goke.d.ts","sourceRoot":"","sources":["../src/goke.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"goke.d.ts","sourceRoot":"","sources":["../src/goke.ts"],"names":[],"mappings":"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"}
|
package/dist/goke.js
CHANGED
|
@@ -306,6 +306,21 @@ class Command {
|
|
|
306
306
|
this._hidden = true;
|
|
307
307
|
return this;
|
|
308
308
|
}
|
|
309
|
+
/**
|
|
310
|
+
* Register the action callback that runs when this command is matched.
|
|
311
|
+
*
|
|
312
|
+
* The callback receives positional args extracted from the command's raw name,
|
|
313
|
+
* followed by the parsed options object and the injected GokeExecutionContext.
|
|
314
|
+
*
|
|
315
|
+
* Positional arg types are inferred from the raw name at the type level:
|
|
316
|
+
* `command('convert <input> <output>')` → `(input: string, output: string, options, ctx)`
|
|
317
|
+
* `command('run [script]')` → `(script: string | undefined, options, ctx)`
|
|
318
|
+
* `command('exec [...args]')` → `(args: string[], options, ctx)`
|
|
319
|
+
*
|
|
320
|
+
* The options object is typed according to every `.option()` call chained
|
|
321
|
+
* on this command, plus any global options declared on the parent Goke
|
|
322
|
+
* instance before `.command()` was called.
|
|
323
|
+
*/
|
|
309
324
|
action(callback) {
|
|
310
325
|
this.commandAction = callback;
|
|
311
326
|
return this;
|
|
@@ -745,7 +760,12 @@ class Goke extends EventEmitter {
|
|
|
745
760
|
return this;
|
|
746
761
|
}
|
|
747
762
|
/**
|
|
748
|
-
* Add a sub-command
|
|
763
|
+
* Add a sub-command.
|
|
764
|
+
*
|
|
765
|
+
* The returned Command is parameterized by the literal `rawName` (so positional
|
|
766
|
+
* args can be inferred at the type level) and by this Goke's accumulated global
|
|
767
|
+
* `Opts` (so global options declared before `.command()` are visible inside
|
|
768
|
+
* `.action()` callbacks alongside the command's own options).
|
|
749
769
|
*/
|
|
750
770
|
command(rawName, description, config) {
|
|
751
771
|
const command = new Command(rawName, description || '', config, this);
|
package/dist/runtime-node.js
CHANGED
|
@@ -8,7 +8,7 @@ const process = globalThis.process;
|
|
|
8
8
|
const fs = nodeFs;
|
|
9
9
|
function openInBrowser(url) {
|
|
10
10
|
if (!process.stdout.isTTY) {
|
|
11
|
-
process.
|
|
11
|
+
process.stdout.write(url + '\n');
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
14
14
|
try {
|
|
@@ -23,7 +23,7 @@ function openInBrowser(url) {
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
catch {
|
|
26
|
-
process.
|
|
26
|
+
process.stdout.write(url + '\n');
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
export { EventEmitter, fs, openInBrowser, process };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "goke",
|
|
3
|
-
"version": "6.5.
|
|
3
|
+
"version": "6.5.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Simple yet powerful framework for building command-line apps. Inspired by cac.",
|
|
6
6
|
"repository": {
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"types": "./dist/index.d.ts",
|
|
24
24
|
"imports": {
|
|
25
25
|
"#runtime": {
|
|
26
|
-
"types": "./
|
|
26
|
+
"types": "./dist/runtime-node.d.ts",
|
|
27
27
|
"development": "./src/runtime-node.ts",
|
|
28
28
|
"node": "./dist/runtime-node.js",
|
|
29
29
|
"default": "./dist/runtime-browser.js"
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smoke tests that keep README examples and documented APIs executable.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from 'vitest'
|
|
6
|
+
import { z } from 'zod'
|
|
7
|
+
import goke, { openInBrowser } from '../index.js'
|
|
8
|
+
import type { GokeOptions, GokeOutputStream } from '../index.js'
|
|
9
|
+
|
|
10
|
+
const ANSI_RE = /\x1B\[[0-9;]*m/g
|
|
11
|
+
|
|
12
|
+
const stripAnsi = (text: string) => text.replace(ANSI_RE, '')
|
|
13
|
+
|
|
14
|
+
function createTestOutputStream(): GokeOutputStream & { lines: string[]; readonly text: string } {
|
|
15
|
+
const lines: string[] = []
|
|
16
|
+
return {
|
|
17
|
+
lines,
|
|
18
|
+
get text() { return stripAnsi(lines.join('')) },
|
|
19
|
+
write(data: string) { lines.push(data) },
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function gokeTestable(name = '', options?: Partial<GokeOptions>) {
|
|
24
|
+
return goke(name, {
|
|
25
|
+
...options,
|
|
26
|
+
exit: () => {},
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe('README smoke tests', () => {
|
|
31
|
+
test('intro example runs middleware and both command forms', async () => {
|
|
32
|
+
const stdout = createTestOutputStream()
|
|
33
|
+
const cli = gokeTestable('deploy', { stdout })
|
|
34
|
+
|
|
35
|
+
cli
|
|
36
|
+
.option('--env <env>', z.enum(['staging', 'production']).default('staging').describe('Target environment'))
|
|
37
|
+
.use((options, { console }) => {
|
|
38
|
+
console.log(`Environment: ${options.env}`)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
cli
|
|
42
|
+
.command('up', 'Deploy the app')
|
|
43
|
+
.option('--dry-run', 'Preview without deploying')
|
|
44
|
+
.action((options, { console, process }) => {
|
|
45
|
+
console.log(`Deploying from ${process.cwd} dryRun=${String(options.dryRun)}`)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
cli
|
|
49
|
+
.command('logs <deploymentId>', 'Stream logs')
|
|
50
|
+
.option('--lines <n>', z.number().default(100).describe('Lines to tail'))
|
|
51
|
+
.action((deploymentId, options, { console }) => {
|
|
52
|
+
console.log(`logs ${deploymentId} ${options.lines}`)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
cli.parse(['node', 'bin', '--env', 'production', 'up', '--dry-run'], { run: false })
|
|
56
|
+
await cli.runMatchedCommand()
|
|
57
|
+
|
|
58
|
+
expect(stdout.text).toBe(
|
|
59
|
+
`Environment: production\nDeploying from ${process.cwd()} dryRun=true\n`,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
stdout.lines.length = 0
|
|
63
|
+
|
|
64
|
+
cli.parse(['node', 'bin', 'logs', 'dep_123'], { run: false })
|
|
65
|
+
await cli.runMatchedCommand()
|
|
66
|
+
|
|
67
|
+
expect(stdout.text).toBe('Environment: staging\nlogs dep_123 100\n')
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
test('simple parsing example stays executable and keeps examples in help output', async () => {
|
|
71
|
+
const stdout = createTestOutputStream()
|
|
72
|
+
const cli = gokeTestable('mycli', { stdout })
|
|
73
|
+
|
|
74
|
+
cli.option(
|
|
75
|
+
'--type [type]',
|
|
76
|
+
z.string().default('node').describe('Choose a project type'),
|
|
77
|
+
)
|
|
78
|
+
cli.option('--name <name>', 'Provide your name')
|
|
79
|
+
|
|
80
|
+
cli.command('lint [...files]', 'Lint files').action((files, options, { console, process }) => {
|
|
81
|
+
console.log(JSON.stringify({ files, options, cwd: process.cwd }))
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
cli
|
|
85
|
+
.command('build [entry]', 'Build your app')
|
|
86
|
+
.option('--minify', 'Minify output')
|
|
87
|
+
.example('build src/index.ts')
|
|
88
|
+
.example('build src/index.ts --minify')
|
|
89
|
+
.action(async (entry, options, { console, process }) => {
|
|
90
|
+
console.log(JSON.stringify({ entry, options, nodeEnv: process.env.NODE_ENV }))
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
cli.example((bin) => `${bin} lint src/**/*.ts`)
|
|
94
|
+
cli.help()
|
|
95
|
+
cli.version('0.0.0')
|
|
96
|
+
|
|
97
|
+
expect(stripAnsi(cli.helpText())).toContain('mycli lint src/**/*.ts')
|
|
98
|
+
|
|
99
|
+
cli.parse(['node', 'bin', '--type', 'bun', '--name', 'Tommy', 'build', 'src/index.ts', '--minify'], { run: false })
|
|
100
|
+
await cli.runMatchedCommand()
|
|
101
|
+
|
|
102
|
+
expect(stdout.text).toBe(
|
|
103
|
+
`${JSON.stringify({
|
|
104
|
+
entry: 'src/index.ts',
|
|
105
|
+
options: {
|
|
106
|
+
'--': [],
|
|
107
|
+
type: 'bun',
|
|
108
|
+
name: 'Tommy',
|
|
109
|
+
minify: true,
|
|
110
|
+
},
|
|
111
|
+
nodeEnv: process.env.NODE_ENV,
|
|
112
|
+
})}\n`,
|
|
113
|
+
)
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
test('many-commands README example runs root and nested commands', async () => {
|
|
117
|
+
const stdout = createTestOutputStream()
|
|
118
|
+
const cli = gokeTestable('deploy', { stdout })
|
|
119
|
+
|
|
120
|
+
cli
|
|
121
|
+
.command('', 'Deploy the current project')
|
|
122
|
+
.option('--env <env>', z.string().default('production').describe('Target environment'))
|
|
123
|
+
.option('--dry-run', 'Preview without deploying')
|
|
124
|
+
.action((options, { console, process }) => {
|
|
125
|
+
console.log(`Deploying to ${options.env} from ${process.cwd} dryRun=${String(options.dryRun)}`)
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
cli
|
|
129
|
+
.command('logs <deploymentId>', 'Stream logs for a deployment')
|
|
130
|
+
.option('--follow', 'Follow log output')
|
|
131
|
+
.option('--lines <n>', z.number().default(100).describe('Number of lines'))
|
|
132
|
+
.action((deploymentId, options, { console, process }) => {
|
|
133
|
+
console.log(
|
|
134
|
+
`Streaming logs for ${deploymentId} from ${process.cwd} follow=${String(options.follow)} lines=${options.lines}`,
|
|
135
|
+
)
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
cli.parse(['node', 'bin', '--env', 'staging', '--dry-run'], { run: false })
|
|
139
|
+
await cli.runMatchedCommand()
|
|
140
|
+
|
|
141
|
+
expect(stdout.text).toBe(
|
|
142
|
+
`Deploying to staging from ${process.cwd()} dryRun=true\n`,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
stdout.lines.length = 0
|
|
146
|
+
|
|
147
|
+
cli.parse(['node', 'bin', 'logs', 'abc123', '--follow'], { run: false })
|
|
148
|
+
await cli.runMatchedCommand()
|
|
149
|
+
|
|
150
|
+
expect(stdout.text).toBe(
|
|
151
|
+
`Streaming logs for abc123 from ${process.cwd()} follow=true lines=100\n`,
|
|
152
|
+
)
|
|
153
|
+
})
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
describe('documented command APIs', () => {
|
|
157
|
+
test('alias runs the same command through a short name', () => {
|
|
158
|
+
const cli = gokeTestable('mycli')
|
|
159
|
+
let seen = ''
|
|
160
|
+
|
|
161
|
+
cli.command('install', 'Install packages').alias('i').action(() => {
|
|
162
|
+
seen = 'install'
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
cli.parse(['node', 'bin', 'i'], { run: true })
|
|
166
|
+
|
|
167
|
+
expect(seen).toBe('install')
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
test('command helpText returns command-specific help without printing', () => {
|
|
171
|
+
const stdout = createTestOutputStream()
|
|
172
|
+
const cli = goke('mycli', { stdout })
|
|
173
|
+
|
|
174
|
+
const command = cli
|
|
175
|
+
.command('deploy <env>', 'Deploy to an environment')
|
|
176
|
+
.option('--dry-run', 'Preview without deploying')
|
|
177
|
+
.example('# Deploy safely first')
|
|
178
|
+
.example('mycli deploy staging --dry-run')
|
|
179
|
+
|
|
180
|
+
cli.help()
|
|
181
|
+
|
|
182
|
+
const help = stripAnsi(command.helpText())
|
|
183
|
+
|
|
184
|
+
expect(help).toContain('$ mycli deploy <env>')
|
|
185
|
+
expect(help).toContain('--dry-run')
|
|
186
|
+
expect(help).toContain('Deploy safely first')
|
|
187
|
+
expect(stdout.text).toBe('')
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
test('openInBrowser prints the URL to stdout in non-tty environments', () => {
|
|
191
|
+
const url = 'https://example.com/dashboard'
|
|
192
|
+
const originalStdoutWrite = process.stdout.write
|
|
193
|
+
const originalStderrWrite = process.stderr.write
|
|
194
|
+
const originalIsTTY = process.stdout.isTTY
|
|
195
|
+
let stdout = ''
|
|
196
|
+
let stderr = ''
|
|
197
|
+
|
|
198
|
+
Object.defineProperty(process.stdout, 'isTTY', {
|
|
199
|
+
configurable: true,
|
|
200
|
+
value: false,
|
|
201
|
+
})
|
|
202
|
+
process.stdout.write = ((chunk: string | Uint8Array) => {
|
|
203
|
+
stdout += String(chunk)
|
|
204
|
+
return true
|
|
205
|
+
}) as typeof process.stdout.write
|
|
206
|
+
process.stderr.write = ((chunk: string | Uint8Array) => {
|
|
207
|
+
stderr += String(chunk)
|
|
208
|
+
return true
|
|
209
|
+
}) as typeof process.stderr.write
|
|
210
|
+
|
|
211
|
+
try {
|
|
212
|
+
openInBrowser(url)
|
|
213
|
+
} finally {
|
|
214
|
+
process.stdout.write = originalStdoutWrite
|
|
215
|
+
process.stderr.write = originalStderrWrite
|
|
216
|
+
Object.defineProperty(process.stdout, 'isTTY', {
|
|
217
|
+
configurable: true,
|
|
218
|
+
value: originalIsTTY,
|
|
219
|
+
})
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
expect(stdout).toBe(`${url}\n`)
|
|
223
|
+
expect(stderr).toBe('')
|
|
224
|
+
})
|
|
225
|
+
})
|