@devicecloud.dev/dcd 3.6.5 → 3.6.7

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.
@@ -44,6 +44,7 @@ export default class Cloud extends Command {
44
44
  'device-locale': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
45
45
  'download-artifacts': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
46
46
  'artifacts-path': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
47
+ debug: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
47
48
  env: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
48
49
  'exclude-flows': import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
49
50
  'exclude-tags': import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
@@ -66,6 +67,13 @@ export default class Cloud extends Command {
66
67
  };
67
68
  static enableJsonFlag: boolean;
68
69
  private versionCheck;
70
+ /**
71
+ * Generate the JSON output file path based on name or upload ID
72
+ * @param name - Optional custom name for the file
73
+ * @param uploadId - Upload ID to use if name is not provided
74
+ * @returns Path to the JSON output file
75
+ */
76
+ private getJsonOutputPath;
69
77
  run(): Promise<{
70
78
  uploadId: string;
71
79
  consoleUrl: string;
@@ -6,7 +6,6 @@ const core_1 = require("@oclif/core");
6
6
  const cli_ux_1 = require("@oclif/core/lib/cli-ux");
7
7
  const errors_1 = require("@oclif/core/lib/errors");
8
8
  const path = require("node:path");
9
- const fs = require("node:fs");
10
9
  const constants_1 = require("../constants");
11
10
  const methods_1 = require("../methods");
12
11
  const plan_1 = require("../plan");
@@ -81,11 +80,36 @@ class Cloud extends core_1.Command {
81
80
  `);
82
81
  }
83
82
  };
83
+ /**
84
+ * Generate the JSON output file path based on name or upload ID
85
+ * @param name - Optional custom name for the file
86
+ * @param uploadId - Upload ID to use if name is not provided
87
+ * @returns Path to the JSON output file
88
+ */
89
+ getJsonOutputPath(name, uploadId) {
90
+ return name ? `${name}_dcd.json` : `${uploadId}_dcd.json`;
91
+ }
84
92
  async run() {
85
93
  let output = null;
94
+ // Store debug flag outside try/catch to access it in catch block
95
+ let debugFlag = false;
96
+ let jsonFile = false;
86
97
  try {
87
98
  const { args, flags, raw } = await this.parse(Cloud);
88
- let { 'additional-app-binary-ids': nonFlatAdditionalAppBinaryIds, 'additional-app-files': nonFlatAdditionalAppFiles, 'android-api-level': androidApiLevel, 'android-device': androidDevice, apiKey: apiKeyFlag, apiUrl, 'app-binary-id': appBinaryId, 'app-file': appFile, 'artifacts-path': artifactsPath, async, config: configFile, 'device-locale': deviceLocale, 'download-artifacts': downloadArtifacts, env, 'exclude-flows': excludeFlows, 'exclude-tags': excludeTags, flows, 'google-play': googlePlay, 'include-tags': includeTags, 'ignore-sha-check': ignoreShaCheck, 'ios-device': iOSDevice, 'ios-version': iOSVersion, 'maestro-version': maestroVersion, name, orientation, quiet, retry, report, 'runner-type': runnerType, 'x86-arch': x86Arch, json, ...rest } = flags;
99
+ let { 'additional-app-binary-ids': nonFlatAdditionalAppBinaryIds, 'additional-app-files': nonFlatAdditionalAppFiles, 'android-api-level': androidApiLevel, 'android-device': androidDevice, apiKey: apiKeyFlag, apiUrl, 'app-binary-id': appBinaryId, 'app-file': appFile, 'artifacts-path': artifactsPath, async, config: configFile, debug, 'device-locale': deviceLocale, 'download-artifacts': downloadArtifacts, env, 'exclude-flows': excludeFlows, 'exclude-tags': excludeTags, flows, 'google-play': googlePlay, 'include-tags': includeTags, 'ignore-sha-check': ignoreShaCheck, 'ios-device': iOSDevice, 'ios-version': iOSVersion, 'maestro-version': maestroVersion, name, orientation, quiet, retry, report, 'runner-type': runnerType, 'x86-arch': x86Arch, json, ...rest } = flags;
100
+ // Store debug flag for use in catch block
101
+ debugFlag = debug === true;
102
+ jsonFile = flags['json-file'] === true;
103
+ if (debug) {
104
+ this.log('DEBUG: Starting command execution with debug logging enabled');
105
+ this.log(`DEBUG: CLI Version: ${this.config.version}`);
106
+ this.log(`DEBUG: Node version: ${process.versions.node}`);
107
+ this.log(`DEBUG: OS: ${process.platform} ${process.arch}`);
108
+ }
109
+ if (flags['json-file']) {
110
+ quiet = true;
111
+ this.log('--json-file is true: JSON output will be written to file, forcing --quiet flag for better CI output');
112
+ }
89
113
  if (json) {
90
114
  const originalStdoutWrite = process.stdout.write;
91
115
  process.stdout.write = function (chunk, encodingOrCallback, cb) {
@@ -104,6 +128,10 @@ class Cloud extends core_1.Command {
104
128
  const apiKey = apiKeyFlag || process.env.DEVICE_CLOUD_API_KEY;
105
129
  if (!apiKey)
106
130
  throw new Error('You must provide an API key via --api-key flag or DEVICE_CLOUD_API_KEY environment variable');
131
+ if (debug) {
132
+ this.log(`DEBUG: API URL: ${apiUrl}`);
133
+ this.log(`DEBUG: API Key provided: ${apiKey ? 'Yes' : 'No'}`);
134
+ }
107
135
  const [maestroMajorString, maestroMinorString] = maestroVersion.split('.');
108
136
  if (report === 'html' &&
109
137
  maestroMajorString === '1' &&
@@ -128,6 +156,15 @@ class Cloud extends core_1.Command {
128
156
  let finalAdditionalBinaryIds = additionalAppBinaryIds;
129
157
  const finalAppFile = appFile ?? firstFile;
130
158
  let flowFile = flows ?? secondFile;
159
+ if (debug) {
160
+ this.log(`DEBUG: First file argument: ${firstFile || 'not provided'}`);
161
+ this.log(`DEBUG: Second file argument: ${secondFile || 'not provided'}`);
162
+ this.log(`DEBUG: App binary ID: ${appBinaryId || 'not provided'}`);
163
+ this.log(`DEBUG: App file: ${finalAppFile || 'not provided'}`);
164
+ this.log(`DEBUG: Flow file: ${flowFile || 'not provided'}`);
165
+ this.log(`DEBUG: Additional app binary IDs: ${additionalAppBinaryIds?.join(', ') || 'none'}`);
166
+ this.log(`DEBUG: Additional app files: ${additionalAppFiles?.join(', ') || 'none'}`);
167
+ }
131
168
  if (appBinaryId) {
132
169
  if (secondFile) {
133
170
  throw new Error('You cannot provide both an appBinaryId and a binary file');
@@ -144,6 +181,11 @@ class Cloud extends core_1.Command {
144
181
  if (!supportediOSVersions.includes(version)) {
145
182
  throw new Error(`${iOSDeviceID} only supports these iOS versions: ${supportediOSVersions.join(', ')}`);
146
183
  }
184
+ if (debug) {
185
+ this.log(`DEBUG: iOS device: ${iOSDeviceID}`);
186
+ this.log(`DEBUG: iOS version: ${version}`);
187
+ this.log(`DEBUG: Supported iOS versions: ${supportediOSVersions.join(', ')}`);
188
+ }
147
189
  }
148
190
  if (androidApiLevel || androidDevice) {
149
191
  const androidDeviceID = androidDevice || 'pixel-7';
@@ -158,6 +200,12 @@ class Cloud extends core_1.Command {
158
200
  if (!supportedAndroidVersions.includes(version)) {
159
201
  throw new Error(`${androidDeviceID} ${googlePlay ? '(Play Store) ' : ''}only supports these Android API levels: ${supportedAndroidVersions.join(', ')}`);
160
202
  }
203
+ if (debug) {
204
+ this.log(`DEBUG: Android device: ${androidDeviceID}`);
205
+ this.log(`DEBUG: Android API level: ${version}`);
206
+ this.log(`DEBUG: Google Play enabled: ${googlePlay}`);
207
+ this.log(`DEBUG: Supported Android versions: ${supportedAndroidVersions.join(', ')}`);
208
+ }
161
209
  }
162
210
  flowFile = path.resolve(flowFile);
163
211
  if (!flowFile?.endsWith('.yaml') &&
@@ -165,14 +213,35 @@ class Cloud extends core_1.Command {
165
213
  !flowFile?.endsWith('/')) {
166
214
  flowFile += '/';
167
215
  }
216
+ if (debug) {
217
+ this.log(`DEBUG: Resolved flow file path: ${flowFile}`);
218
+ }
168
219
  let executionPlan;
169
220
  try {
221
+ if (debug) {
222
+ this.log('DEBUG: Generating execution plan...');
223
+ }
170
224
  executionPlan = await (0, plan_1.plan)(flowFile, includeTags.flat(), excludeTags.flat(), excludeFlows.flat(), configFile);
225
+ if (debug) {
226
+ this.log(`DEBUG: Execution plan generated`);
227
+ this.log(`DEBUG: Total flow files: ${executionPlan.totalFlowFiles}`);
228
+ this.log(`DEBUG: Flows to run: ${executionPlan.flowsToRun.length}`);
229
+ this.log(`DEBUG: Referenced files: ${executionPlan.referencedFiles.length}`);
230
+ this.log(`DEBUG: Sequential flows: ${executionPlan.sequence?.flows.length || 0}`);
231
+ }
171
232
  }
172
233
  catch (error) {
234
+ if (debug) {
235
+ this.log(`DEBUG: Error generating execution plan: ${error}`);
236
+ }
173
237
  throw error;
174
238
  }
175
239
  const { allExcludeTags, allIncludeTags, flowsToRun: testFileNames, referencedFiles, sequence, workspaceConfig, } = executionPlan;
240
+ if (debug) {
241
+ this.log(`DEBUG: All include tags: ${allIncludeTags?.join(', ') || 'none'}`);
242
+ this.log(`DEBUG: All exclude tags: ${allExcludeTags?.join(', ') || 'none'}`);
243
+ this.log(`DEBUG: Test file names: ${testFileNames.join(', ')}`);
244
+ }
176
245
  const pathsShortestToLongest = [
177
246
  ...testFileNames,
178
247
  ...referencedFiles,
@@ -185,7 +254,14 @@ class Cloud extends core_1.Command {
185
254
  if (isRoot)
186
255
  commonRoot = folderPath;
187
256
  }
257
+ if (debug) {
258
+ this.log(`DEBUG: Common root directory: ${commonRoot}`);
259
+ }
188
260
  const { continueOnFailure = true, flows: sequentialFlows = [] } = sequence ?? {};
261
+ if (debug && sequentialFlows.length > 0) {
262
+ this.log(`DEBUG: Sequential flows: ${sequentialFlows.join(', ')}`);
263
+ this.log(`DEBUG: Continue on failure: ${continueOnFailure}`);
264
+ }
189
265
  if (!appBinaryId) {
190
266
  if (!(flowFile && finalAppFile)) {
191
267
  throw new Error('You must provide a flow file and an app binary id');
@@ -194,9 +270,15 @@ class Cloud extends core_1.Command {
194
270
  throw new Error('App file must be a .apk for android or .app/.zip file for iOS');
195
271
  }
196
272
  if (finalAppFile.endsWith('.zip')) {
273
+ if (debug) {
274
+ this.log(`DEBUG: Verifying iOS app zip file: ${finalAppFile}`);
275
+ }
197
276
  await (0, methods_1.verifyAppZip)(finalAppFile);
198
277
  }
199
278
  }
279
+ if (debug && additionalAppFiles?.length) {
280
+ this.log(`DEBUG: Verifying additional app files: ${additionalAppFiles.join(', ')}`);
281
+ }
200
282
  await (0, methods_1.verifyAdditionalAppFiles)(additionalAppFiles);
201
283
  const flagLogs = [];
202
284
  for (const [k, v] of Object.entries(flags)) {
@@ -221,16 +303,29 @@ class Cloud extends core_1.Command {
221
303
  if (!finalBinaryId) {
222
304
  if (!finalAppFile)
223
305
  throw new Error('You must provide either an app binary id or an app file');
306
+ if (debug) {
307
+ this.log(`DEBUG: Uploading binary file: ${finalAppFile}`);
308
+ }
224
309
  const binaryId = await (0, methods_1.uploadBinary)(finalAppFile, apiUrl, apiKey, ignoreShaCheck, !json);
225
310
  finalBinaryId = binaryId;
311
+ if (debug) {
312
+ this.log(`DEBUG: Binary uploaded with ID: ${binaryId}`);
313
+ }
226
314
  }
227
315
  let uploadedBinaryIds = [];
228
316
  if (additionalAppFiles?.length) {
317
+ if (debug) {
318
+ this.log(`DEBUG: Uploading additional binary files: ${additionalAppFiles.join(', ')}`);
319
+ }
229
320
  uploadedBinaryIds = await (0, methods_1.uploadBinaries)(additionalAppFiles, apiUrl, apiKey, ignoreShaCheck, !json);
230
321
  finalAdditionalBinaryIds = [
231
322
  ...finalAdditionalBinaryIds,
232
323
  ...uploadedBinaryIds,
233
324
  ];
325
+ if (debug) {
326
+ this.log(`DEBUG: Additional binaries uploaded with IDs: ${uploadedBinaryIds.join(', ')}`);
327
+ this.log(`DEBUG: Final additional binary IDs: ${finalAdditionalBinaryIds.join(', ')}`);
328
+ }
234
329
  }
235
330
  const testFormData = new FormData();
236
331
  // eslint-disable-next-line unicorn/no-array-reduce
@@ -240,6 +335,12 @@ class Cloud extends core_1.Command {
240
335
  acc[key] = value.join('=');
241
336
  return acc;
242
337
  }, {});
338
+ if (debug && Object.keys(envObject).length > 0) {
339
+ this.log(`DEBUG: Environment variables: ${JSON.stringify(envObject)}`);
340
+ }
341
+ if (debug) {
342
+ this.log(`DEBUG: Compressing files from path: ${flowFile}`);
343
+ }
243
344
  const buffer = await (0, methods_1.compressFilesFromRelativePath)(flowFile?.endsWith('.yaml') || flowFile?.endsWith('.yml')
244
345
  ? path.dirname(flowFile)
245
346
  : flowFile, [
@@ -249,6 +350,9 @@ class Cloud extends core_1.Command {
249
350
  ...sequentialFlows,
250
351
  ]),
251
352
  ], commonRoot);
353
+ if (debug) {
354
+ this.log(`DEBUG: Compressed file size: ${buffer.length} bytes`);
355
+ }
252
356
  const blob = new Blob([buffer], {
253
357
  type: exports.mimeTypeLookupByExtension.zip,
254
358
  });
@@ -299,11 +403,19 @@ class Cloud extends core_1.Command {
299
403
  testFormData.set(key, value);
300
404
  }
301
405
  }
406
+ if (debug) {
407
+ this.log(`DEBUG: Submitting flow upload request to ${apiUrl}/uploads/flow`);
408
+ }
302
409
  const options = {
303
410
  body: testFormData,
304
411
  headers: { 'x-app-api-key': apiKey },
305
412
  };
306
413
  const { message, results } = await (0, methods_1.typeSafePost)(apiUrl, '/uploads/flow', options);
414
+ if (debug) {
415
+ this.log(`DEBUG: Flow upload response received`);
416
+ this.log(`DEBUG: Message: ${message}`);
417
+ this.log(`DEBUG: Results count: ${results?.length || 0}`);
418
+ }
307
419
  if (!results?.length)
308
420
  (0, errors_1.error)('No tests created: ' + message);
309
421
  this.log(message);
@@ -318,6 +430,9 @@ class Cloud extends core_1.Command {
318
430
  this.log(`Your upload ID is: ${results[0].test_upload_id}`);
319
431
  this.log(`Poll upload status using: dcd status --api-key ... --upload-id ${results[0].test_upload_id}`);
320
432
  if (async) {
433
+ if (debug) {
434
+ this.log(`DEBUG: Async flag is set, not waiting for results`);
435
+ }
321
436
  const jsonOutput = {
322
437
  uploadId: results[0].test_upload_id,
323
438
  consoleUrl: url,
@@ -328,11 +443,8 @@ class Cloud extends core_1.Command {
328
443
  })),
329
444
  };
330
445
  if (flags['json-file']) {
331
- const jsonFilePath = name
332
- ? `${name}_dcd.json`
333
- : `${results[0].test_upload_id}_dcd.json`;
334
- fs.writeFileSync(jsonFilePath, JSON.stringify(jsonOutput, null, 2));
335
- this.log(`JSON output written to: ${path.resolve(jsonFilePath)}`);
446
+ const jsonFilePath = this.getJsonOutputPath(name, results[0].test_upload_id);
447
+ (0, methods_1.writeJSONFile)(jsonFilePath, jsonOutput, this);
336
448
  }
337
449
  if (json) {
338
450
  return jsonOutput;
@@ -348,15 +460,27 @@ class Cloud extends core_1.Command {
348
460
  this.log('\nYou can safely close this terminal and the tests will continue\n');
349
461
  }
350
462
  let sequentialPollFaillures = 0;
463
+ if (debug) {
464
+ this.log(`DEBUG: Starting polling loop for results`);
465
+ }
351
466
  await new Promise((resolve, reject) => {
352
467
  const intervalId = setInterval(async () => {
353
468
  try {
469
+ if (debug) {
470
+ this.log(`DEBUG: Polling for results: ${results[0].test_upload_id}`);
471
+ }
354
472
  const { results: updatedResults } = await (0, methods_1.typeSafeGet)(apiUrl, `/results/${results[0].test_upload_id}`, {
355
473
  headers: { 'x-app-api-key': apiKey },
356
474
  });
357
475
  if (!updatedResults) {
358
476
  throw new Error('no results');
359
477
  }
478
+ if (debug) {
479
+ this.log(`DEBUG: Poll received ${updatedResults.length} results`);
480
+ for (const result of updatedResults) {
481
+ this.log(`DEBUG: Result status: ${result.test_file_name} - ${result.status}`);
482
+ }
483
+ }
360
484
  if (!quiet && !json) {
361
485
  core_1.ux.action.status =
362
486
  '\nStatus Test\n─────────── ───────────────';
@@ -365,6 +489,9 @@ class Cloud extends core_1.Command {
365
489
  }
366
490
  }
367
491
  if (updatedResults.every((result) => !['PENDING', 'RUNNING'].includes(result.status))) {
492
+ if (debug) {
493
+ this.log(`DEBUG: All tests completed, stopping poll`);
494
+ }
368
495
  if (!json) {
369
496
  core_1.ux.action.stop('completed');
370
497
  this.log('\n');
@@ -382,6 +509,9 @@ class Cloud extends core_1.Command {
382
509
  clearInterval(intervalId);
383
510
  if (downloadArtifacts) {
384
511
  try {
512
+ if (debug) {
513
+ this.log(`DEBUG: Downloading artifacts: ${downloadArtifacts}`);
514
+ }
385
515
  await (0, methods_1.typeSafePostDownload)(apiUrl, `/results/${results[0].test_upload_id}/download`, {
386
516
  body: JSON.stringify({ results: downloadArtifacts }),
387
517
  headers: {
@@ -392,7 +522,10 @@ class Cloud extends core_1.Command {
392
522
  this.log('\n');
393
523
  this.log(`Test artifacts have been downloaded to ${artifactsPath || './artifacts.zip'}`);
394
524
  }
395
- catch {
525
+ catch (error) {
526
+ if (debug) {
527
+ this.log(`DEBUG: Error downloading artifacts: ${error}`);
528
+ }
396
529
  this.warn('Failed to download artifacts');
397
530
  }
398
531
  }
@@ -402,6 +535,9 @@ class Cloud extends core_1.Command {
402
535
  return result.id === Math.max(...tries.map((t) => t.id));
403
536
  });
404
537
  if (resultsWithoutEarlierTries.some((result) => result.status === 'FAILED')) {
538
+ if (debug) {
539
+ this.log(`DEBUG: Some tests failed, returning failed status`);
540
+ }
405
541
  const jsonOutput = {
406
542
  uploadId: results[0].test_upload_id,
407
543
  consoleUrl: url,
@@ -412,11 +548,8 @@ class Cloud extends core_1.Command {
412
548
  })),
413
549
  };
414
550
  if (flags['json-file']) {
415
- const jsonFilePath = name
416
- ? `${name}_dcd.json`
417
- : `${results[0].test_upload_id}_dcd.json`;
418
- fs.writeFileSync(jsonFilePath, JSON.stringify(jsonOutput, null, 2));
419
- this.log(`JSON output written to: ${path.resolve(jsonFilePath)}`);
551
+ const jsonFilePath = this.getJsonOutputPath(name, results[0].test_upload_id);
552
+ (0, methods_1.writeJSONFile)(jsonFilePath, jsonOutput, this);
420
553
  }
421
554
  if (json) {
422
555
  output = jsonOutput;
@@ -424,6 +557,9 @@ class Cloud extends core_1.Command {
424
557
  reject(new Error('RUN_FAILED'));
425
558
  }
426
559
  else {
560
+ if (debug) {
561
+ this.log(`DEBUG: All tests passed, returning success status`);
562
+ }
427
563
  const jsonOutput = {
428
564
  uploadId: results[0].test_upload_id,
429
565
  consoleUrl: url,
@@ -434,11 +570,8 @@ class Cloud extends core_1.Command {
434
570
  })),
435
571
  };
436
572
  if (flags['json-file']) {
437
- const jsonFilePath = name
438
- ? `${name}_dcd.json`
439
- : `${results[0].test_upload_id}_dcd.json`;
440
- fs.writeFileSync(jsonFilePath, JSON.stringify(jsonOutput, null, 2));
441
- this.log(`JSON output written to: ${path.resolve(jsonFilePath)}`);
573
+ const jsonFilePath = this.getJsonOutputPath(name, results[0].test_upload_id);
574
+ (0, methods_1.writeJSONFile)(jsonFilePath, jsonOutput, this);
442
575
  }
443
576
  if (json) {
444
577
  output = jsonOutput;
@@ -450,10 +583,14 @@ class Cloud extends core_1.Command {
450
583
  }
451
584
  catch (error) {
452
585
  sequentialPollFaillures++;
453
- if (sequentialPollFaillures > 5) {
586
+ if (debug) {
587
+ this.log(`DEBUG: Error polling for results: ${error}`);
588
+ this.log(`DEBUG: Sequential poll failures: ${sequentialPollFaillures}`);
589
+ }
590
+ if (sequentialPollFaillures > 10) {
454
591
  // dropped poll requests shouldn't err user CI
455
592
  clearInterval(intervalId);
456
- throw new Error('unable to fetch results after 5 attempts');
593
+ throw new Error('unable to fetch results after 10 attempts');
457
594
  }
458
595
  this.log('unable to fetch results, trying again...');
459
596
  }
@@ -461,7 +598,15 @@ class Cloud extends core_1.Command {
461
598
  });
462
599
  }
463
600
  catch (error) {
601
+ if (debugFlag && error instanceof Error) {
602
+ this.log(`DEBUG: Error in command execution: ${error.message}`);
603
+ this.log(`DEBUG: Error stack: ${error.stack}`);
604
+ }
464
605
  if (error instanceof Error && error.message === 'RUN_FAILED') {
606
+ if (jsonFile) {
607
+ // mimic oclif's json functionality
608
+ this.exit(0);
609
+ }
465
610
  this.exit(2);
466
611
  }
467
612
  else {
@@ -14,6 +14,7 @@ export declare const flags: {
14
14
  'device-locale': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
15
15
  'download-artifacts': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
16
16
  'artifacts-path': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
17
+ debug: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
17
18
  env: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
18
19
  'exclude-flows': import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
19
20
  'exclude-tags': import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
package/dist/constants.js CHANGED
@@ -70,6 +70,10 @@ exports.flags = {
70
70
  description: 'Custom file path for downloaded artifacts (default: ./artifacts.zip)',
71
71
  dependsOn: ['download-artifacts'],
72
72
  }),
73
+ debug: core_1.Flags.boolean({
74
+ description: 'Enable detailed debug logging for troubleshooting issues',
75
+ default: false,
76
+ }),
73
77
  env: core_1.Flags.file({
74
78
  char: 'e',
75
79
  description: 'One or more environment variables to inject into your flows',
@@ -186,7 +190,7 @@ exports.flags = {
186
190
  description: 'Output results in JSON format - note: will always provide exit code 0',
187
191
  }),
188
192
  'json-file': core_1.Flags.boolean({
189
- description: 'Write JSON output to a file with name <run_name>_dcd.json or <upload_id>_dcd.json if no name is provided',
193
+ description: 'Write JSON output to a file with name <run_name>_dcd.json or <upload_id>_dcd.json if no name is provided - note: will always provide exit code 0',
190
194
  required: false,
191
195
  }),
192
196
  };
package/dist/methods.d.ts CHANGED
@@ -34,3 +34,14 @@ export declare const getUploadStatus: (apiUrl: string, apiKey: string, options:
34
34
  status: "PASSED" | "FAILED" | "CANCELLED" | "PENDING";
35
35
  }>;
36
36
  }>;
37
+ /**
38
+ * Writes JSON data to a file with error handling
39
+ * @param filePath - Path to the output JSON file
40
+ * @param data - Data to be serialized to JSON
41
+ * @param logger - Logger object with log and warn methods
42
+ * @returns true if successful, false if an error occurred
43
+ */
44
+ export declare const writeJSONFile: (filePath: string, data: any, logger: {
45
+ log: (message: string) => void;
46
+ warn: (message: string) => void;
47
+ }) => void;
package/dist/methods.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getUploadStatus = exports.verifyAdditionalAppFiles = exports.uploadBinaries = exports.uploadBinary = exports.extractAppMetadataIos = exports.extractAppMetadataIosZip = exports.extractAppMetadataAndroid = exports.verifyAppZip = exports.compressFilesFromRelativePath = exports.compressFolderToBlob = exports.compressDir = exports.toBuffer = exports.typeSafeGet = exports.typeSafePostDownload = exports.typeSafePost = void 0;
3
+ exports.writeJSONFile = exports.getUploadStatus = exports.verifyAdditionalAppFiles = exports.uploadBinaries = exports.uploadBinary = exports.extractAppMetadataIos = exports.extractAppMetadataIosZip = exports.extractAppMetadataAndroid = exports.verifyAppZip = exports.compressFilesFromRelativePath = exports.compressFolderToBlob = exports.compressDir = exports.toBuffer = exports.typeSafeGet = exports.typeSafePostDownload = exports.typeSafePost = void 0;
4
4
  const core_1 = require("@oclif/core");
5
5
  const supabase_js_1 = require("@supabase/supabase-js");
6
6
  // required polyfill for node 18
@@ -370,3 +370,22 @@ const getUploadStatus = async (apiUrl, apiKey, options) => {
370
370
  return response.json();
371
371
  };
372
372
  exports.getUploadStatus = getUploadStatus;
373
+ /**
374
+ * Writes JSON data to a file with error handling
375
+ * @param filePath - Path to the output JSON file
376
+ * @param data - Data to be serialized to JSON
377
+ * @param logger - Logger object with log and warn methods
378
+ * @returns true if successful, false if an error occurred
379
+ */
380
+ const writeJSONFile = (filePath, data, logger) => {
381
+ try {
382
+ (0, node_fs_1.writeFileSync)(filePath, JSON.stringify(data, null, 2));
383
+ logger.log(`JSON output written to: ${path.resolve(filePath)}`);
384
+ }
385
+ catch (error) {
386
+ logger.warn(`Failed to write JSON output to file: ${filePath}`);
387
+ // Use console.debug instead of logger.debug since debug is protected in Command
388
+ logger.warn(`Error details: ${error instanceof Error ? error.message : String(error)}`);
389
+ }
390
+ };
391
+ exports.writeJSONFile = writeJSONFile;
@@ -161,6 +161,12 @@
161
161
  "multiple": false,
162
162
  "type": "option"
163
163
  },
164
+ "debug": {
165
+ "description": "Enable detailed debug logging for troubleshooting issues",
166
+ "name": "debug",
167
+ "allowNo": false,
168
+ "type": "boolean"
169
+ },
164
170
  "env": {
165
171
  "char": "e",
166
172
  "description": "One or more environment variables to inject into your flows",
@@ -350,7 +356,7 @@
350
356
  "type": "option"
351
357
  },
352
358
  "json-file": {
353
- "description": "Write JSON output to a file with name <run_name>_dcd.json or <upload_id>_dcd.json if no name is provided",
359
+ "description": "Write JSON output to a file with name <run_name>_dcd.json or <upload_id>_dcd.json if no name is provided - note: will always provide exit code 0",
354
360
  "name": "json-file",
355
361
  "required": false,
356
362
  "allowNo": false,
@@ -514,5 +520,5 @@
514
520
  ]
515
521
  }
516
522
  },
517
- "version": "3.6.5"
523
+ "version": "3.6.7"
518
524
  }
package/package.json CHANGED
@@ -79,7 +79,7 @@
79
79
  "prepare": "yarn build",
80
80
  "version": "oclif readme && git add README.md"
81
81
  },
82
- "version": "3.6.5",
82
+ "version": "3.6.7",
83
83
  "bugs": {
84
84
  "url": "https://discord.gg/gm3mJwcNw8"
85
85
  },