@devicecloud.dev/dcd 3.6.5 → 3.6.6

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,34 @@ 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;
86
96
  try {
87
97
  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;
98
+ 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;
99
+ // Store debug flag for use in catch block
100
+ debugFlag = debug === true;
101
+ if (debug) {
102
+ this.log('DEBUG: Starting command execution with debug logging enabled');
103
+ this.log(`DEBUG: CLI Version: ${this.config.version}`);
104
+ this.log(`DEBUG: Node version: ${process.versions.node}`);
105
+ this.log(`DEBUG: OS: ${process.platform} ${process.arch}`);
106
+ }
107
+ if (flags['json-file']) {
108
+ quiet = true;
109
+ this.log('--json-file is true: JSON output will be written to file, forcing --quiet flag for better CI output');
110
+ }
89
111
  if (json) {
90
112
  const originalStdoutWrite = process.stdout.write;
91
113
  process.stdout.write = function (chunk, encodingOrCallback, cb) {
@@ -104,6 +126,10 @@ class Cloud extends core_1.Command {
104
126
  const apiKey = apiKeyFlag || process.env.DEVICE_CLOUD_API_KEY;
105
127
  if (!apiKey)
106
128
  throw new Error('You must provide an API key via --api-key flag or DEVICE_CLOUD_API_KEY environment variable');
129
+ if (debug) {
130
+ this.log(`DEBUG: API URL: ${apiUrl}`);
131
+ this.log(`DEBUG: API Key provided: ${apiKey ? 'Yes' : 'No'}`);
132
+ }
107
133
  const [maestroMajorString, maestroMinorString] = maestroVersion.split('.');
108
134
  if (report === 'html' &&
109
135
  maestroMajorString === '1' &&
@@ -128,6 +154,15 @@ class Cloud extends core_1.Command {
128
154
  let finalAdditionalBinaryIds = additionalAppBinaryIds;
129
155
  const finalAppFile = appFile ?? firstFile;
130
156
  let flowFile = flows ?? secondFile;
157
+ if (debug) {
158
+ this.log(`DEBUG: First file argument: ${firstFile || 'not provided'}`);
159
+ this.log(`DEBUG: Second file argument: ${secondFile || 'not provided'}`);
160
+ this.log(`DEBUG: App binary ID: ${appBinaryId || 'not provided'}`);
161
+ this.log(`DEBUG: App file: ${finalAppFile || 'not provided'}`);
162
+ this.log(`DEBUG: Flow file: ${flowFile || 'not provided'}`);
163
+ this.log(`DEBUG: Additional app binary IDs: ${additionalAppBinaryIds?.join(', ') || 'none'}`);
164
+ this.log(`DEBUG: Additional app files: ${additionalAppFiles?.join(', ') || 'none'}`);
165
+ }
131
166
  if (appBinaryId) {
132
167
  if (secondFile) {
133
168
  throw new Error('You cannot provide both an appBinaryId and a binary file');
@@ -144,6 +179,11 @@ class Cloud extends core_1.Command {
144
179
  if (!supportediOSVersions.includes(version)) {
145
180
  throw new Error(`${iOSDeviceID} only supports these iOS versions: ${supportediOSVersions.join(', ')}`);
146
181
  }
182
+ if (debug) {
183
+ this.log(`DEBUG: iOS device: ${iOSDeviceID}`);
184
+ this.log(`DEBUG: iOS version: ${version}`);
185
+ this.log(`DEBUG: Supported iOS versions: ${supportediOSVersions.join(', ')}`);
186
+ }
147
187
  }
148
188
  if (androidApiLevel || androidDevice) {
149
189
  const androidDeviceID = androidDevice || 'pixel-7';
@@ -158,6 +198,12 @@ class Cloud extends core_1.Command {
158
198
  if (!supportedAndroidVersions.includes(version)) {
159
199
  throw new Error(`${androidDeviceID} ${googlePlay ? '(Play Store) ' : ''}only supports these Android API levels: ${supportedAndroidVersions.join(', ')}`);
160
200
  }
201
+ if (debug) {
202
+ this.log(`DEBUG: Android device: ${androidDeviceID}`);
203
+ this.log(`DEBUG: Android API level: ${version}`);
204
+ this.log(`DEBUG: Google Play enabled: ${googlePlay}`);
205
+ this.log(`DEBUG: Supported Android versions: ${supportedAndroidVersions.join(', ')}`);
206
+ }
161
207
  }
162
208
  flowFile = path.resolve(flowFile);
163
209
  if (!flowFile?.endsWith('.yaml') &&
@@ -165,14 +211,35 @@ class Cloud extends core_1.Command {
165
211
  !flowFile?.endsWith('/')) {
166
212
  flowFile += '/';
167
213
  }
214
+ if (debug) {
215
+ this.log(`DEBUG: Resolved flow file path: ${flowFile}`);
216
+ }
168
217
  let executionPlan;
169
218
  try {
219
+ if (debug) {
220
+ this.log('DEBUG: Generating execution plan...');
221
+ }
170
222
  executionPlan = await (0, plan_1.plan)(flowFile, includeTags.flat(), excludeTags.flat(), excludeFlows.flat(), configFile);
223
+ if (debug) {
224
+ this.log(`DEBUG: Execution plan generated`);
225
+ this.log(`DEBUG: Total flow files: ${executionPlan.totalFlowFiles}`);
226
+ this.log(`DEBUG: Flows to run: ${executionPlan.flowsToRun.length}`);
227
+ this.log(`DEBUG: Referenced files: ${executionPlan.referencedFiles.length}`);
228
+ this.log(`DEBUG: Sequential flows: ${executionPlan.sequence?.flows.length || 0}`);
229
+ }
171
230
  }
172
231
  catch (error) {
232
+ if (debug) {
233
+ this.log(`DEBUG: Error generating execution plan: ${error}`);
234
+ }
173
235
  throw error;
174
236
  }
175
237
  const { allExcludeTags, allIncludeTags, flowsToRun: testFileNames, referencedFiles, sequence, workspaceConfig, } = executionPlan;
238
+ if (debug) {
239
+ this.log(`DEBUG: All include tags: ${allIncludeTags?.join(', ') || 'none'}`);
240
+ this.log(`DEBUG: All exclude tags: ${allExcludeTags?.join(', ') || 'none'}`);
241
+ this.log(`DEBUG: Test file names: ${testFileNames.join(', ')}`);
242
+ }
176
243
  const pathsShortestToLongest = [
177
244
  ...testFileNames,
178
245
  ...referencedFiles,
@@ -185,7 +252,14 @@ class Cloud extends core_1.Command {
185
252
  if (isRoot)
186
253
  commonRoot = folderPath;
187
254
  }
255
+ if (debug) {
256
+ this.log(`DEBUG: Common root directory: ${commonRoot}`);
257
+ }
188
258
  const { continueOnFailure = true, flows: sequentialFlows = [] } = sequence ?? {};
259
+ if (debug && sequentialFlows.length > 0) {
260
+ this.log(`DEBUG: Sequential flows: ${sequentialFlows.join(', ')}`);
261
+ this.log(`DEBUG: Continue on failure: ${continueOnFailure}`);
262
+ }
189
263
  if (!appBinaryId) {
190
264
  if (!(flowFile && finalAppFile)) {
191
265
  throw new Error('You must provide a flow file and an app binary id');
@@ -194,9 +268,15 @@ class Cloud extends core_1.Command {
194
268
  throw new Error('App file must be a .apk for android or .app/.zip file for iOS');
195
269
  }
196
270
  if (finalAppFile.endsWith('.zip')) {
271
+ if (debug) {
272
+ this.log(`DEBUG: Verifying iOS app zip file: ${finalAppFile}`);
273
+ }
197
274
  await (0, methods_1.verifyAppZip)(finalAppFile);
198
275
  }
199
276
  }
277
+ if (debug && additionalAppFiles?.length) {
278
+ this.log(`DEBUG: Verifying additional app files: ${additionalAppFiles.join(', ')}`);
279
+ }
200
280
  await (0, methods_1.verifyAdditionalAppFiles)(additionalAppFiles);
201
281
  const flagLogs = [];
202
282
  for (const [k, v] of Object.entries(flags)) {
@@ -221,16 +301,29 @@ class Cloud extends core_1.Command {
221
301
  if (!finalBinaryId) {
222
302
  if (!finalAppFile)
223
303
  throw new Error('You must provide either an app binary id or an app file');
304
+ if (debug) {
305
+ this.log(`DEBUG: Uploading binary file: ${finalAppFile}`);
306
+ }
224
307
  const binaryId = await (0, methods_1.uploadBinary)(finalAppFile, apiUrl, apiKey, ignoreShaCheck, !json);
225
308
  finalBinaryId = binaryId;
309
+ if (debug) {
310
+ this.log(`DEBUG: Binary uploaded with ID: ${binaryId}`);
311
+ }
226
312
  }
227
313
  let uploadedBinaryIds = [];
228
314
  if (additionalAppFiles?.length) {
315
+ if (debug) {
316
+ this.log(`DEBUG: Uploading additional binary files: ${additionalAppFiles.join(', ')}`);
317
+ }
229
318
  uploadedBinaryIds = await (0, methods_1.uploadBinaries)(additionalAppFiles, apiUrl, apiKey, ignoreShaCheck, !json);
230
319
  finalAdditionalBinaryIds = [
231
320
  ...finalAdditionalBinaryIds,
232
321
  ...uploadedBinaryIds,
233
322
  ];
323
+ if (debug) {
324
+ this.log(`DEBUG: Additional binaries uploaded with IDs: ${uploadedBinaryIds.join(', ')}`);
325
+ this.log(`DEBUG: Final additional binary IDs: ${finalAdditionalBinaryIds.join(', ')}`);
326
+ }
234
327
  }
235
328
  const testFormData = new FormData();
236
329
  // eslint-disable-next-line unicorn/no-array-reduce
@@ -240,6 +333,12 @@ class Cloud extends core_1.Command {
240
333
  acc[key] = value.join('=');
241
334
  return acc;
242
335
  }, {});
336
+ if (debug && Object.keys(envObject).length > 0) {
337
+ this.log(`DEBUG: Environment variables: ${JSON.stringify(envObject)}`);
338
+ }
339
+ if (debug) {
340
+ this.log(`DEBUG: Compressing files from path: ${flowFile}`);
341
+ }
243
342
  const buffer = await (0, methods_1.compressFilesFromRelativePath)(flowFile?.endsWith('.yaml') || flowFile?.endsWith('.yml')
244
343
  ? path.dirname(flowFile)
245
344
  : flowFile, [
@@ -249,6 +348,9 @@ class Cloud extends core_1.Command {
249
348
  ...sequentialFlows,
250
349
  ]),
251
350
  ], commonRoot);
351
+ if (debug) {
352
+ this.log(`DEBUG: Compressed file size: ${buffer.length} bytes`);
353
+ }
252
354
  const blob = new Blob([buffer], {
253
355
  type: exports.mimeTypeLookupByExtension.zip,
254
356
  });
@@ -299,11 +401,19 @@ class Cloud extends core_1.Command {
299
401
  testFormData.set(key, value);
300
402
  }
301
403
  }
404
+ if (debug) {
405
+ this.log(`DEBUG: Submitting flow upload request to ${apiUrl}/uploads/flow`);
406
+ }
302
407
  const options = {
303
408
  body: testFormData,
304
409
  headers: { 'x-app-api-key': apiKey },
305
410
  };
306
411
  const { message, results } = await (0, methods_1.typeSafePost)(apiUrl, '/uploads/flow', options);
412
+ if (debug) {
413
+ this.log(`DEBUG: Flow upload response received`);
414
+ this.log(`DEBUG: Message: ${message}`);
415
+ this.log(`DEBUG: Results count: ${results?.length || 0}`);
416
+ }
307
417
  if (!results?.length)
308
418
  (0, errors_1.error)('No tests created: ' + message);
309
419
  this.log(message);
@@ -318,6 +428,9 @@ class Cloud extends core_1.Command {
318
428
  this.log(`Your upload ID is: ${results[0].test_upload_id}`);
319
429
  this.log(`Poll upload status using: dcd status --api-key ... --upload-id ${results[0].test_upload_id}`);
320
430
  if (async) {
431
+ if (debug) {
432
+ this.log(`DEBUG: Async flag is set, not waiting for results`);
433
+ }
321
434
  const jsonOutput = {
322
435
  uploadId: results[0].test_upload_id,
323
436
  consoleUrl: url,
@@ -328,11 +441,8 @@ class Cloud extends core_1.Command {
328
441
  })),
329
442
  };
330
443
  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)}`);
444
+ const jsonFilePath = this.getJsonOutputPath(name, results[0].test_upload_id);
445
+ (0, methods_1.writeJSONFile)(jsonFilePath, jsonOutput, this);
336
446
  }
337
447
  if (json) {
338
448
  return jsonOutput;
@@ -348,15 +458,27 @@ class Cloud extends core_1.Command {
348
458
  this.log('\nYou can safely close this terminal and the tests will continue\n');
349
459
  }
350
460
  let sequentialPollFaillures = 0;
461
+ if (debug) {
462
+ this.log(`DEBUG: Starting polling loop for results`);
463
+ }
351
464
  await new Promise((resolve, reject) => {
352
465
  const intervalId = setInterval(async () => {
353
466
  try {
467
+ if (debug) {
468
+ this.log(`DEBUG: Polling for results: ${results[0].test_upload_id}`);
469
+ }
354
470
  const { results: updatedResults } = await (0, methods_1.typeSafeGet)(apiUrl, `/results/${results[0].test_upload_id}`, {
355
471
  headers: { 'x-app-api-key': apiKey },
356
472
  });
357
473
  if (!updatedResults) {
358
474
  throw new Error('no results');
359
475
  }
476
+ if (debug) {
477
+ this.log(`DEBUG: Poll received ${updatedResults.length} results`);
478
+ for (const result of updatedResults) {
479
+ this.log(`DEBUG: Result status: ${result.test_file_name} - ${result.status}`);
480
+ }
481
+ }
360
482
  if (!quiet && !json) {
361
483
  core_1.ux.action.status =
362
484
  '\nStatus Test\n─────────── ───────────────';
@@ -365,6 +487,9 @@ class Cloud extends core_1.Command {
365
487
  }
366
488
  }
367
489
  if (updatedResults.every((result) => !['PENDING', 'RUNNING'].includes(result.status))) {
490
+ if (debug) {
491
+ this.log(`DEBUG: All tests completed, stopping poll`);
492
+ }
368
493
  if (!json) {
369
494
  core_1.ux.action.stop('completed');
370
495
  this.log('\n');
@@ -382,6 +507,9 @@ class Cloud extends core_1.Command {
382
507
  clearInterval(intervalId);
383
508
  if (downloadArtifacts) {
384
509
  try {
510
+ if (debug) {
511
+ this.log(`DEBUG: Downloading artifacts: ${downloadArtifacts}`);
512
+ }
385
513
  await (0, methods_1.typeSafePostDownload)(apiUrl, `/results/${results[0].test_upload_id}/download`, {
386
514
  body: JSON.stringify({ results: downloadArtifacts }),
387
515
  headers: {
@@ -392,7 +520,10 @@ class Cloud extends core_1.Command {
392
520
  this.log('\n');
393
521
  this.log(`Test artifacts have been downloaded to ${artifactsPath || './artifacts.zip'}`);
394
522
  }
395
- catch {
523
+ catch (error) {
524
+ if (debug) {
525
+ this.log(`DEBUG: Error downloading artifacts: ${error}`);
526
+ }
396
527
  this.warn('Failed to download artifacts');
397
528
  }
398
529
  }
@@ -402,6 +533,9 @@ class Cloud extends core_1.Command {
402
533
  return result.id === Math.max(...tries.map((t) => t.id));
403
534
  });
404
535
  if (resultsWithoutEarlierTries.some((result) => result.status === 'FAILED')) {
536
+ if (debug) {
537
+ this.log(`DEBUG: Some tests failed, returning failed status`);
538
+ }
405
539
  const jsonOutput = {
406
540
  uploadId: results[0].test_upload_id,
407
541
  consoleUrl: url,
@@ -412,11 +546,8 @@ class Cloud extends core_1.Command {
412
546
  })),
413
547
  };
414
548
  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)}`);
549
+ const jsonFilePath = this.getJsonOutputPath(name, results[0].test_upload_id);
550
+ (0, methods_1.writeJSONFile)(jsonFilePath, jsonOutput, this);
420
551
  }
421
552
  if (json) {
422
553
  output = jsonOutput;
@@ -424,6 +555,9 @@ class Cloud extends core_1.Command {
424
555
  reject(new Error('RUN_FAILED'));
425
556
  }
426
557
  else {
558
+ if (debug) {
559
+ this.log(`DEBUG: All tests passed, returning success status`);
560
+ }
427
561
  const jsonOutput = {
428
562
  uploadId: results[0].test_upload_id,
429
563
  consoleUrl: url,
@@ -434,11 +568,8 @@ class Cloud extends core_1.Command {
434
568
  })),
435
569
  };
436
570
  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)}`);
571
+ const jsonFilePath = this.getJsonOutputPath(name, results[0].test_upload_id);
572
+ (0, methods_1.writeJSONFile)(jsonFilePath, jsonOutput, this);
442
573
  }
443
574
  if (json) {
444
575
  output = jsonOutput;
@@ -450,10 +581,14 @@ class Cloud extends core_1.Command {
450
581
  }
451
582
  catch (error) {
452
583
  sequentialPollFaillures++;
453
- if (sequentialPollFaillures > 5) {
584
+ if (debug) {
585
+ this.log(`DEBUG: Error polling for results: ${error}`);
586
+ this.log(`DEBUG: Sequential poll failures: ${sequentialPollFaillures}`);
587
+ }
588
+ if (sequentialPollFaillures > 10) {
454
589
  // dropped poll requests shouldn't err user CI
455
590
  clearInterval(intervalId);
456
- throw new Error('unable to fetch results after 5 attempts');
591
+ throw new Error('unable to fetch results after 10 attempts');
457
592
  }
458
593
  this.log('unable to fetch results, trying again...');
459
594
  }
@@ -461,6 +596,10 @@ class Cloud extends core_1.Command {
461
596
  });
462
597
  }
463
598
  catch (error) {
599
+ if (debugFlag && error instanceof Error) {
600
+ this.log(`DEBUG: Error in command execution: ${error.message}`);
601
+ this.log(`DEBUG: Error stack: ${error.stack}`);
602
+ }
464
603
  if (error instanceof Error && error.message === 'RUN_FAILED') {
465
604
  this.exit(2);
466
605
  }
@@ -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',
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",
@@ -514,5 +520,5 @@
514
520
  ]
515
521
  }
516
522
  },
517
- "version": "3.6.5"
523
+ "version": "3.6.6"
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.6",
83
83
  "bugs": {
84
84
  "url": "https://discord.gg/gm3mJwcNw8"
85
85
  },