@testrigor/testrigor-cli 1.0.1 → 2.0.0

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 CHANGED
@@ -4,12 +4,35 @@ This is a command line tool for TestRigor. It allows you to run TestRigor tests
4
4
 
5
5
  ### Installation
6
6
 
7
- 1. Install [Node.js](https://nodejs.org/en/download/) (version 18 or higher)
8
- 2. Install TestRigor CLI: `npm install -g testrigor-cli`
7
+ 1. Install [Node.js](https://nodejs.org/en/download/) (version 20.19+, 22.12+ or 24+)
8
+ 2. Install TestRigor CLI: `npm install -g @testrigor/testrigor-cli`
9
+ 3. Check it: `testrigor --version`
10
+
11
+ > The unscoped `testrigor-cli` package on npm is an old, unmaintained build.
12
+ > Install the scoped `@testrigor/testrigor-cli` package shown above; if you
13
+ > installed the unscoped one, run `npm uninstall -g testrigor-cli` first.
14
+
15
+ ### Authentication
16
+
17
+ Store your token once, interactively:
18
+
19
+ ```
20
+ testrigor authenticate
21
+ ```
22
+
23
+ For CI or any non-interactive shell, pass it in instead of being prompted:
24
+
25
+ ```
26
+ testrigor authenticate --token YOUR_TOKEN
27
+ echo YOUR_TOKEN | testrigor authenticate
28
+ ```
29
+
30
+ Or skip stored credentials entirely and set `TESTRIGOR_API_KEY`, or pass
31
+ `--token` to each command.
9
32
 
10
33
  ### Examples
11
34
 
12
- 1. Basic `testrigor test-suite run <test-suite-id> --token <token>`
35
+ 1. Basic `testrigor test-suite run <test-suite-id> --token <token>`
13
36
  2. With new URL `testrigor test-suite run <test-suite-id> --token <token> --url <url>`
14
37
  3. With file upload `testrigor test-suite run <test-suite-id> --token <token> --file-path <path-to-file>`
15
38
  4. With branch `testrigor test-suite run <test-suite-id> --token <token> --branch <branch> --commit <commit>`
@@ -47,6 +70,7 @@ testrigor test-suite run <test-suite-id> --token <token> --localhost --local-tes
47
70
  ```
48
71
 
49
72
  The CLI will:
73
+
50
74
  - Detect it's a mobile suite
51
75
  - Start the mobile server (Appium) automatically
52
76
  - Open a tunnel to TestRigor cloud
@@ -89,15 +113,6 @@ Every push to `master` runs the CircleCI `publish` workflow. It builds the tarba
89
113
  This updates the version in `package.json` and in both root entries of `package-lock.json` (`version` and `packages[""].version`). `--no-git-tag-version` stops npm from creating its own commit and `v*` tag. npm also runs the `version` script (`oclif readme && git add README.md`). That script loads the commands from `dist`, which is why you build first. It only rewrites README sections between oclif markers such as `<!-- commands -->
90
114
  * [`testrigor authenticate`](#testrigor-authenticate)
91
115
  * [`testrigor help [COMMANDS]`](#testrigor-help-commands)
92
- * [`testrigor plugins`](#testrigor-plugins)
93
- * [`testrigor plugins:install PLUGIN...`](#testrigor-pluginsinstall-plugin)
94
- * [`testrigor plugins:inspect PLUGIN...`](#testrigor-pluginsinspect-plugin)
95
- * [`testrigor plugins:install PLUGIN...`](#testrigor-pluginsinstall-plugin-1)
96
- * [`testrigor plugins:link PLUGIN`](#testrigor-pluginslink-plugin)
97
- * [`testrigor plugins:uninstall PLUGIN...`](#testrigor-pluginsuninstall-plugin)
98
- * [`testrigor plugins:uninstall PLUGIN...`](#testrigor-pluginsuninstall-plugin-1)
99
- * [`testrigor plugins:uninstall PLUGIN...`](#testrigor-pluginsuninstall-plugin-2)
100
- * [`testrigor plugins update`](#testrigor-plugins-update)
101
116
  * [`testrigor test-suite config`](#testrigor-test-suite-config)
102
117
  * [`testrigor test-suite run [TESTSUITEID]`](#testrigor-test-suite-run-testsuiteid)
103
118
  * [`testrigor test-suite validate-syntax [TESTSUITEID]`](#testrigor-test-suite-validate-syntax-testsuiteid)
@@ -108,7 +123,10 @@ Set your testRigor authentication token
108
123
 
109
124
  ```
110
125
  USAGE
111
- $ testrigor authenticate
126
+ $ testrigor authenticate [--token <value>]
127
+
128
+ FLAGS
129
+ --token=<value> API authentication token to store, instead of prompting for it
112
130
 
113
131
  DESCRIPTION
114
132
  Set your testRigor authentication token
@@ -118,12 +136,16 @@ EXAMPLES
118
136
 
119
137
  Prompts for your API authentication token
120
138
 
139
+ $ testrigor authenticate --token YOUR_TOKEN
140
+
141
+ Sets the token without prompting (for CI and scripts)
142
+
121
143
  Use 'testrigor test-suite config' to set default test suite ID separately
122
144
 
123
145
  Config will be stored in ~/.testrigor/testrigor.yml
124
146
  ```
125
147
 
126
- _See code: [src/commands/authenticate.ts](https://github.com/TestRigor/testrigor-cli/blob/v1.0.1/src/commands/authenticate.ts)_
148
+ _See code: [src/commands/authenticate.ts](https://github.com/TestRigor/testrigor-cli/blob/v2.0.0/src/commands/authenticate.ts)_
127
149
 
128
150
  ## `testrigor help [COMMANDS]`
129
151
 
@@ -131,10 +153,10 @@ Display help for testrigor.
131
153
 
132
154
  ```
133
155
  USAGE
134
- $ testrigor help [COMMANDS] [-n]
156
+ $ testrigor help [COMMANDS...] [-n]
135
157
 
136
158
  ARGUMENTS
137
- COMMANDS Command to show help for.
159
+ [COMMANDS...] Command to show help for.
138
160
 
139
161
  FLAGS
140
162
  -n, --nested-commands Include all nested commands in the output.
@@ -145,253 +167,6 @@ DESCRIPTION
145
167
 
146
168
  _See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v5.2.20/src/commands/help.ts)_
147
169
 
148
- ## `testrigor plugins`
149
-
150
- List installed plugins.
151
-
152
- ```
153
- USAGE
154
- $ testrigor plugins [--json] [--core]
155
-
156
- FLAGS
157
- --core Show core plugins.
158
-
159
- GLOBAL FLAGS
160
- --json Format output as json.
161
-
162
- DESCRIPTION
163
- List installed plugins.
164
-
165
- EXAMPLES
166
- $ testrigor plugins
167
- ```
168
-
169
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v3.10.1/src/commands/plugins/index.ts)_
170
-
171
- ## `testrigor plugins:install PLUGIN...`
172
-
173
- Installs a plugin into the CLI.
174
-
175
- ```
176
- USAGE
177
- $ testrigor plugins:install PLUGIN...
178
-
179
- ARGUMENTS
180
- PLUGIN Plugin to install.
181
-
182
- FLAGS
183
- -f, --force Run yarn install with force flag.
184
- -h, --help Show CLI help.
185
- -v, --verbose
186
-
187
- DESCRIPTION
188
- Installs a plugin into the CLI.
189
- Can be installed from npm or a git url.
190
-
191
- Installation of a user-installed plugin will override a core plugin.
192
-
193
- e.g. If you have a core plugin that has a 'hello' command, installing a user-installed plugin with a 'hello' command
194
- will override the core plugin implementation. This is useful if a user needs to update core plugin functionality in
195
- the CLI without the need to patch and update the whole CLI.
196
-
197
-
198
- ALIASES
199
- $ testrigor plugins add
200
-
201
- EXAMPLES
202
- $ testrigor plugins:install myplugin
203
-
204
- $ testrigor plugins:install https://github.com/someuser/someplugin
205
-
206
- $ testrigor plugins:install someuser/someplugin
207
- ```
208
-
209
- ## `testrigor plugins:inspect PLUGIN...`
210
-
211
- Displays installation properties of a plugin.
212
-
213
- ```
214
- USAGE
215
- $ testrigor plugins:inspect PLUGIN...
216
-
217
- ARGUMENTS
218
- PLUGIN [default: .] Plugin to inspect.
219
-
220
- FLAGS
221
- -h, --help Show CLI help.
222
- -v, --verbose
223
-
224
- GLOBAL FLAGS
225
- --json Format output as json.
226
-
227
- DESCRIPTION
228
- Displays installation properties of a plugin.
229
-
230
- EXAMPLES
231
- $ testrigor plugins:inspect myplugin
232
- ```
233
-
234
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v3.10.1/src/commands/plugins/inspect.ts)_
235
-
236
- ## `testrigor plugins:install PLUGIN...`
237
-
238
- Installs a plugin into the CLI.
239
-
240
- ```
241
- USAGE
242
- $ testrigor plugins:install PLUGIN...
243
-
244
- ARGUMENTS
245
- PLUGIN Plugin to install.
246
-
247
- FLAGS
248
- -f, --force Run yarn install with force flag.
249
- -h, --help Show CLI help.
250
- -v, --verbose
251
-
252
- DESCRIPTION
253
- Installs a plugin into the CLI.
254
- Can be installed from npm or a git url.
255
-
256
- Installation of a user-installed plugin will override a core plugin.
257
-
258
- e.g. If you have a core plugin that has a 'hello' command, installing a user-installed plugin with a 'hello' command
259
- will override the core plugin implementation. This is useful if a user needs to update core plugin functionality in
260
- the CLI without the need to patch and update the whole CLI.
261
-
262
-
263
- ALIASES
264
- $ testrigor plugins add
265
-
266
- EXAMPLES
267
- $ testrigor plugins:install myplugin
268
-
269
- $ testrigor plugins:install https://github.com/someuser/someplugin
270
-
271
- $ testrigor plugins:install someuser/someplugin
272
- ```
273
-
274
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v3.10.1/src/commands/plugins/install.ts)_
275
-
276
- ## `testrigor plugins:link PLUGIN`
277
-
278
- Links a plugin into the CLI for development.
279
-
280
- ```
281
- USAGE
282
- $ testrigor plugins:link PLUGIN
283
-
284
- ARGUMENTS
285
- PATH [default: .] path to plugin
286
-
287
- FLAGS
288
- -h, --help Show CLI help.
289
- -v, --verbose
290
- --[no-]install Install dependencies after linking the plugin.
291
-
292
- DESCRIPTION
293
- Links a plugin into the CLI for development.
294
- Installation of a linked plugin will override a user-installed or core plugin.
295
-
296
- e.g. If you have a user-installed or core plugin that has a 'hello' command, installing a linked plugin with a 'hello'
297
- command will override the user-installed or core plugin implementation. This is useful for development work.
298
-
299
-
300
- EXAMPLES
301
- $ testrigor plugins:link myplugin
302
- ```
303
-
304
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v3.10.1/src/commands/plugins/link.ts)_
305
-
306
- ## `testrigor plugins:uninstall PLUGIN...`
307
-
308
- Removes a plugin from the CLI.
309
-
310
- ```
311
- USAGE
312
- $ testrigor plugins:uninstall PLUGIN...
313
-
314
- ARGUMENTS
315
- PLUGIN plugin to uninstall
316
-
317
- FLAGS
318
- -h, --help Show CLI help.
319
- -v, --verbose
320
-
321
- DESCRIPTION
322
- Removes a plugin from the CLI.
323
-
324
- ALIASES
325
- $ testrigor plugins unlink
326
- $ testrigor plugins remove
327
- ```
328
-
329
- ## `testrigor plugins:uninstall PLUGIN...`
330
-
331
- Removes a plugin from the CLI.
332
-
333
- ```
334
- USAGE
335
- $ testrigor plugins:uninstall PLUGIN...
336
-
337
- ARGUMENTS
338
- PLUGIN plugin to uninstall
339
-
340
- FLAGS
341
- -h, --help Show CLI help.
342
- -v, --verbose
343
-
344
- DESCRIPTION
345
- Removes a plugin from the CLI.
346
-
347
- ALIASES
348
- $ testrigor plugins unlink
349
- $ testrigor plugins remove
350
- ```
351
-
352
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v3.10.1/src/commands/plugins/uninstall.ts)_
353
-
354
- ## `testrigor plugins:uninstall PLUGIN...`
355
-
356
- Removes a plugin from the CLI.
357
-
358
- ```
359
- USAGE
360
- $ testrigor plugins:uninstall PLUGIN...
361
-
362
- ARGUMENTS
363
- PLUGIN plugin to uninstall
364
-
365
- FLAGS
366
- -h, --help Show CLI help.
367
- -v, --verbose
368
-
369
- DESCRIPTION
370
- Removes a plugin from the CLI.
371
-
372
- ALIASES
373
- $ testrigor plugins unlink
374
- $ testrigor plugins remove
375
- ```
376
-
377
- ## `testrigor plugins update`
378
-
379
- Update installed plugins.
380
-
381
- ```
382
- USAGE
383
- $ testrigor plugins update [-h] [-v]
384
-
385
- FLAGS
386
- -h, --help Show CLI help.
387
- -v, --verbose
388
-
389
- DESCRIPTION
390
- Update installed plugins.
391
- ```
392
-
393
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v3.10.1/src/commands/plugins/update.ts)_
394
-
395
170
  ## `testrigor test-suite config`
396
171
 
397
172
  Configure test suite settings and default test suite ID
@@ -416,7 +191,7 @@ EXAMPLES
416
191
  $ testrigor test-suite config --delete
417
192
  ```
418
193
 
419
- _See code: [src/commands/test-suite/config.ts](https://github.com/TestRigor/testrigor-cli/blob/v1.0.1/src/commands/test-suite/config.ts)_
194
+ _See code: [src/commands/test-suite/config.ts](https://github.com/TestRigor/testrigor-cli/blob/v2.0.0/src/commands/test-suite/config.ts)_
420
195
 
421
196
  ## `testrigor test-suite run [TESTSUITEID]`
422
197
 
@@ -427,54 +202,54 @@ USAGE
427
202
  $ testrigor test-suite run [TESTSUITEID] [--auth-token <value>] [-t <value>] [--min-port <value>] [--max-port
428
203
  <value>] [--verbose] [-w] [--branch <value> --commit <value>] [--localhost] [--url <value>]
429
204
  [--junit-report-save-path <value>] [--variables-path <value>] [--test-cases-path <value>] [--rules-path <value>]
430
- [--settings-path <value>] [--local-test-nodes-path <value>] [--test-case-uuid <value>] [--auto-create-ai-rules]
431
- [--explicit-mutations] [--labels <value>] [--excluded-labels <value>] [--base-url-web <value>] [--base-url-api
432
- <value>] [--chrome-extension <value> | --file-path <value>] [--xray-execution-key <value>]
205
+ [--settings-path <value>] [--local-test-nodes-path <value>] [--test-case-uuid <value>...] [--auto-create-ai-rules]
206
+ [--explicit-mutations] [--labels <value>...] [--excluded-labels <value>...] [--base-url-web <value>] [--base-url-api
207
+ <value>] [--chrome-extension <value>... | --file-path <value>] [--xray-execution-key <value>]
433
208
 
434
209
  ARGUMENTS
435
- TESTSUITEID The test suite id (optional if set in config)
210
+ [TESTSUITEID] The test suite id (optional if set in config)
436
211
 
437
212
  FLAGS
438
- -w, --async Don't wait for the test suite to finish
439
- --auto-create-ai-rules Enable auto create AI based rules
440
- --base-url-api=<value> Base URL for API2 (e.g., https://api2.testrigor.com)
441
- --base-url-web=<value> Base URL for web interface (e.g., https://app.testrigor.com)
442
- --branch=<value> The branch name
443
- --chrome-extension=<value>... Chrome extension: "name=EXT_NAME file=PATH_TO_CRX"
444
- --commit=<value> The commit
445
- --excluded-labels=<value>... Not run tests of specific labels
446
- --explicit-mutations In cases where you are always using mutations, such as storing test cases in your
447
- own repository, and you always send us the set of test cases you have through our
448
- API you should send "--explicit-mutations"
449
- --file-path=<value> Path to the file stored locally. It will upload the new file to be used. File type
450
- should be according to the file type accepted for the Test Suite type of testing. If
451
- the parameter --url is used, this parameter will be ignored.
452
- --junit-report-save-path=<value> JUnit report save path
453
- --labels=<value>... Run tests of specific labels
454
- --local-test-nodes-path=<value> Path to a YAML or JSON file with local test nodes configuration
455
- --localhost Localhost run (auto-detects web vs mobile)
456
- --max-port=<value> [default: 50000] Max port for tunnel
457
- --min-port=<value> [default: 40000] Min port for tunnel
458
- --rules-path=<value> Rules path
459
- --settings-path=<value> Settings path
460
- --test-case-uuid=<value>... Test case uuid (can be repeated). Requires --url (web) or --file-path (mobile app
461
- upload).
462
- --test-cases-path=<value> Test cases files
463
- --url=<value> The url
464
- --variables-path=<value> Variables path
465
- --xray-execution-key=<value> Reuse an existing Xray Cloud Test Execution by key (e.g. XR-123) instead of creating
466
- a new one. Optional; leave blank to create a new execution.
213
+ -w, --async Don't wait for the test suite to finish
214
+ --auto-create-ai-rules Enable auto create AI based rules
215
+ --base-url-api=<value> Base URL for API2 (e.g., https://api2.testrigor.com)
216
+ --base-url-web=<value> Base URL for web interface (e.g., https://app.testrigor.com)
217
+ --branch=<value> [env: TR_BRANCH] The branch name
218
+ --chrome-extension=<value>... Chrome extension: "name=EXT_NAME file=PATH_TO_CRX"
219
+ --commit=<value> [env: TR_COMMIT] The commit
220
+ --excluded-labels=<value>... Not run tests of specific labels
221
+ --explicit-mutations In cases where you are always using mutations, such as storing test cases in
222
+ your own repository, and you always send us the set of test cases you have
223
+ through our API you should send "--explicit-mutations"
224
+ --file-path=<value> Path to the file stored locally. It will upload the new file to be used. File
225
+ type should be according to the file type accepted for the Test Suite type of
226
+ testing. If the parameter --url is used, this parameter will be ignored.
227
+ --junit-report-save-path=<value> JUnit report save path
228
+ --labels=<value>... Run tests of specific labels
229
+ --local-test-nodes-path=<value> Path to a YAML or JSON file with local test nodes configuration
230
+ --localhost Localhost run (auto-detects web vs mobile)
231
+ --max-port=<value> [default: 50000] Max port for tunnel
232
+ --min-port=<value> [default: 40000] Min port for tunnel
233
+ --rules-path=<value> Rules path
234
+ --settings-path=<value> Settings path
235
+ --test-case-uuid=<value>... Test case uuid (can be repeated). Requires --url (web) or --file-path (mobile
236
+ app upload).
237
+ --test-cases-path=<value> Test cases files
238
+ --url=<value> The url
239
+ --variables-path=<value> Variables path
240
+ --xray-execution-key=<value> Reuse an existing Xray Cloud Test Execution by key (e.g. XR-123) instead of
241
+ creating a new one. Optional; leave blank to create a new execution.
467
242
 
468
243
  GLOBAL FLAGS
469
- -t, --token=<value> Suite authentication token
470
- --auth-token=<value> Personal authentication token
471
- --verbose Verbose output
244
+ -t, --token=<value> Suite authentication token
245
+ --auth-token=<value> Personal authentication token
246
+ --verbose Verbose output
472
247
 
473
248
  DESCRIPTION
474
249
  Run all tests of a Test Suite
475
250
  ```
476
251
 
477
- _See code: [src/commands/test-suite/run.ts](https://github.com/TestRigor/testrigor-cli/blob/v1.0.1/src/commands/test-suite/run.ts)_
252
+ _See code: [src/commands/test-suite/run.ts](https://github.com/TestRigor/testrigor-cli/blob/v2.0.0/src/commands/test-suite/run.ts)_
478
253
 
479
254
  ## `testrigor test-suite validate-syntax [TESTSUITEID]`
480
255
 
@@ -487,7 +262,7 @@ USAGE
487
262
  [--explicit-mutations]
488
263
 
489
264
  ARGUMENTS
490
- TESTSUITEID The test suite id (optional if set in config)
265
+ [TESTSUITEID] The test suite id (optional if set in config)
491
266
 
492
267
  FLAGS
493
268
  --base-url-api=<value> Base URL for API2 (e.g., https://api2.testrigor.com)
@@ -500,9 +275,9 @@ FLAGS
500
275
  --test-cases-path=<value> Test case files to validate (same glob format as `test-suite run --test-cases-path`)
501
276
 
502
277
  GLOBAL FLAGS
503
- -t, --token=<value> Suite authentication token
504
- --auth-token=<value> Personal authentication token
505
- --verbose Verbose output
278
+ -t, --token=<value> Suite authentication token
279
+ --auth-token=<value> Personal authentication token
280
+ --verbose Verbose output
506
281
 
507
282
  DESCRIPTION
508
283
  Validate step syntax against a test suite's reusable rules, without running the steps
@@ -513,7 +288,7 @@ EXAMPLES
513
288
  $ testrigor test-suite validate-syntax <test-suite-id> --test-cases-path "test_cases/**/*.{yaml,txt}"
514
289
  ```
515
290
 
516
- _See code: [src/commands/test-suite/validate-syntax.ts](https://github.com/TestRigor/testrigor-cli/blob/v1.0.1/src/commands/test-suite/validate-syntax.ts)_
291
+ _See code: [src/commands/test-suite/validate-syntax.ts](https://github.com/TestRigor/testrigor-cli/blob/v2.0.0/src/commands/test-suite/validate-syntax.ts)_
517
292
  <!-- commandsstop -->`, so this README currently stays unchanged.
518
293
  3. Check that the diff only touches the version fields, then build and test from the lockfile:
519
294
 
@@ -2,5 +2,19 @@ import { Command } from "@oclif/core";
2
2
  export default class Authenticate extends Command {
3
3
  static description: string;
4
4
  static examples: string[];
5
+ static flags: {
6
+ token: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
7
+ };
5
8
  run(): Promise<void>;
9
+ /**
10
+ * Where the token comes from, in order: the --token flag, an interactive
11
+ * hidden prompt, or piped stdin.
12
+ *
13
+ * The hidden prompt is only usable on a TTY. Without one, @oclif/core falls
14
+ * back to `sh -c 'read -s ...'`, which fails on any system where /bin/sh is
15
+ * dash (the Debian and Ubuntu default) with "read: Illegal option -s" and
16
+ * then silently skips the setup.
17
+ */
18
+ private resolveToken;
19
+ private readStdin;
6
20
  }
@@ -3,25 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const core_1 = require("@oclif/core");
4
4
  const core_2 = require("@oclif/core");
5
5
  const config_1 = require("../util/config");
6
+ // Time to wait for a token on a piped stdin before giving up. Stdin that is
7
+ // neither a TTY nor a closed/redirected stream would otherwise hang forever.
8
+ const STDIN_TIMEOUT_MS = 5000;
6
9
  class Authenticate extends core_2.Command {
7
10
  async run() {
11
+ const { flags } = await this.parse(Authenticate);
12
+ // readConfig reports parse problems itself and falls back to an empty
13
+ // config, so it needs no wrapping here.
14
+ const config = await (0, config_1.readConfig)();
15
+ // Resolved outside the try below so that "no terminal to prompt on" is
16
+ // reported as itself, not as a failure to save the configuration.
17
+ const token = await this.resolveToken(flags.token, !!config.authToken);
8
18
  try {
9
- // Load existing config (readConfig handles parse errors gracefully)
10
- const config = await (0, config_1.readConfig)();
11
- // Handle authentication token
12
- let tokenPromptText;
13
- if (config.authToken) {
14
- tokenPromptText =
15
- "Enter your testRigor API token (press enter to remove)";
16
- }
17
- else {
18
- tokenPromptText =
19
- "Enter your testRigor API token (press enter to skip)";
20
- }
21
- const token = await core_1.ux.prompt(tokenPromptText, {
22
- type: "hide",
23
- required: false,
24
- });
25
19
  if (!token || token.trim() === "") {
26
20
  if (config.authToken) {
27
21
  delete config.authToken;
@@ -31,29 +25,96 @@ class Authenticate extends core_2.Command {
31
25
  else {
32
26
  core_1.ux.info("Authentication token setup skipped");
33
27
  }
28
+ return;
29
+ }
30
+ config.authToken = token.trim();
31
+ await (0, config_1.writeConfig)(config);
32
+ core_1.ux.info("Authentication token successfully saved");
33
+ if (config.defaultTestSuiteId) {
34
+ core_1.ux.info("You can now use 'testrigor run' to run your default test suite");
34
35
  }
35
36
  else {
36
- config.authToken = token.trim();
37
- await (0, config_1.writeConfig)(config);
38
- core_1.ux.info("Authentication token successfully saved");
39
- if (config.defaultTestSuiteId) {
40
- core_1.ux.info("You can now use 'testrigor run' to run your default test suite");
41
- }
42
- else {
43
- core_1.ux.info("Use 'testrigor test-suite config --default TEST_SUITE_ID' to set your default test suite ID, then use 'testrigor run'");
44
- }
37
+ core_1.ux.info("Use 'testrigor test-suite config --default TEST_SUITE_ID' to set your default test suite ID, then use 'testrigor run'");
45
38
  }
46
39
  }
47
40
  catch (error) {
48
41
  core_1.ux.error(`Failed to save configuration: ${error instanceof Error ? error.message : String(error)}`);
49
42
  }
50
43
  }
44
+ /**
45
+ * Where the token comes from, in order: the --token flag, an interactive
46
+ * hidden prompt, or piped stdin.
47
+ *
48
+ * The hidden prompt is only usable on a TTY. Without one, @oclif/core falls
49
+ * back to `sh -c 'read -s ...'`, which fails on any system where /bin/sh is
50
+ * dash (the Debian and Ubuntu default) with "read: Illegal option -s" and
51
+ * then silently skips the setup.
52
+ */
53
+ async resolveToken(flagToken, hasExistingToken) {
54
+ if (flagToken !== undefined) {
55
+ return flagToken;
56
+ }
57
+ if (process.stdin.isTTY) {
58
+ return core_1.ux.prompt(hasExistingToken
59
+ ? "Enter your testRigor API token (press enter to remove)"
60
+ : "Enter your testRigor API token (press enter to skip)", { type: "hide", required: false });
61
+ }
62
+ const piped = await this.readStdin();
63
+ if (piped) {
64
+ return piped;
65
+ }
66
+ this.error("No interactive terminal available to prompt for a token.\n" +
67
+ "Provide it another way:\n" +
68
+ " testrigor authenticate --token YOUR_TOKEN\n" +
69
+ " echo YOUR_TOKEN | testrigor authenticate\n" +
70
+ "Or skip this command and set the TESTRIGOR_API_KEY environment variable instead.");
71
+ }
72
+ readStdin() {
73
+ return new Promise((resolve) => {
74
+ let data = "";
75
+ // resolve() past the first call is a no-op, so no "settled" guard is
76
+ // needed for whichever of the timeout or the stream gets there first.
77
+ const cleanup = () => {
78
+ process.stdin.removeAllListeners("data");
79
+ process.stdin.pause();
80
+ };
81
+ const timer = setTimeout(() => {
82
+ cleanup();
83
+ resolve("");
84
+ }, STDIN_TIMEOUT_MS);
85
+ const finish = () => {
86
+ clearTimeout(timer);
87
+ cleanup();
88
+ resolve(data.trim());
89
+ };
90
+ process.stdin.setEncoding("utf8");
91
+ process.stdin.on("data", (chunk) => {
92
+ data += chunk;
93
+ // A token is a single line; stop as soon as one arrives.
94
+ const newlineIndex = data.indexOf("\n");
95
+ if (newlineIndex !== -1) {
96
+ data = data.slice(0, newlineIndex);
97
+ finish();
98
+ }
99
+ });
100
+ process.stdin.once("end", finish);
101
+ process.stdin.once("error", finish);
102
+ process.stdin.resume();
103
+ });
104
+ }
51
105
  }
52
106
  Authenticate.description = "Set your testRigor authentication token";
53
107
  Authenticate.examples = [
54
108
  "testrigor authenticate",
55
109
  "Prompts for your API authentication token",
110
+ "testrigor authenticate --token YOUR_TOKEN",
111
+ "Sets the token without prompting (for CI and scripts)",
56
112
  "Use 'testrigor test-suite config' to set default test suite ID separately",
57
113
  "Config will be stored in ~/.testrigor/testrigor.yml",
58
114
  ];
115
+ Authenticate.flags = {
116
+ token: core_2.Flags.string({
117
+ description: "API authentication token to store, instead of prompting for it",
118
+ }),
119
+ };
59
120
  exports.default = Authenticate;