@devicecloud.dev/dcd 0.0.1-alpha.8 → 0.0.1

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.
@@ -8,18 +8,21 @@ export default class Cloud extends Command {
8
8
  static examples: string[];
9
9
  static flags: {
10
10
  'android-api-level': import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
- 'api-key': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
12
- 'api-url': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ 'android-device': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
12
+ apiKey: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
13
+ apiUrl: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
13
14
  'app-binary-id': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
14
15
  'app-file': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
15
16
  arm64: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
16
- async: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
17
+ async: 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-tags': import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
19
20
  flows: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
20
21
  'google-play': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
21
22
  'include-tags': import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
23
+ 'ios-device': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
22
24
  'ios-version': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
25
+ name: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
23
26
  orientation: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
24
27
  };
25
28
  run(): Promise<void>;
@@ -80,6 +80,24 @@ const compressFile = async (sourceFile) => {
80
80
  // await writeFile('./my-zip.zip', buffer);
81
81
  return buffer;
82
82
  };
83
+ var EiOSDevices;
84
+ (function (EiOSDevices) {
85
+ EiOSDevices["ipad-pro-6th-gen"] = "ipad-pro-6th-gen";
86
+ EiOSDevices["iphone-12"] = "iphone-12";
87
+ EiOSDevices["iphone-12-mini"] = "iphone-12-mini";
88
+ EiOSDevices["iphone-12-pro-max"] = "iphone-12-pro-max";
89
+ EiOSDevices["iphone-13"] = "iphone-13";
90
+ EiOSDevices["iphone-13-mini"] = "iphone-13-mini";
91
+ EiOSDevices["iphone-13-pro-max"] = "iphone-13-pro-max";
92
+ EiOSDevices["iphone-14"] = "iphone-14";
93
+ EiOSDevices["iphone-14-plus"] = "iphone-14-plus";
94
+ EiOSDevices["iphone-14-pro"] = "iphone-14-pro";
95
+ EiOSDevices["iphone-14-pro-max"] = "iphone-14-pro-max";
96
+ EiOSDevices["iphone-15"] = "iphone-15";
97
+ EiOSDevices["iphone-15-plus"] = "iphone-15-plus";
98
+ EiOSDevices["iphone-15-pro"] = "iphone-15-pro";
99
+ EiOSDevices["iphone-15-pro-max"] = "iphone-15-pro-max";
100
+ })(EiOSDevices || (EiOSDevices = {}));
83
101
  class Cloud extends core_1.Command {
84
102
  static args = {
85
103
  firstFile: core_1.Args.string({
@@ -97,16 +115,26 @@ class Cloud extends core_1.Command {
97
115
  static examples = ['<%= config.bin %> <%= command.id %>'];
98
116
  static flags = {
99
117
  'android-api-level': core_1.Flags.integer({
100
- aliases: ['android-api-level'],
101
118
  description: '[Android only] Android API level to run your flow against',
102
119
  options: ['32', '33', '34'],
103
120
  }),
104
- 'api-key': core_1.Flags.string({
121
+ 'android-device': core_1.Flags.string({
122
+ description: '[Android only] Android device to run your flow against',
123
+ options: [
124
+ 'pixel-6',
125
+ 'pixel-6a',
126
+ 'pixel-6-pro',
127
+ 'pixel-7',
128
+ 'pixel-7-pro',
129
+ 'generic-tablet',
130
+ ],
131
+ }),
132
+ apiKey: core_1.Flags.string({
105
133
  aliases: ['api-key'],
106
134
  description: 'API key',
107
135
  }),
108
- 'api-url': core_1.Flags.string({
109
- aliases: ['api-url'],
136
+ apiUrl: core_1.Flags.string({
137
+ aliases: ['api-url', 'apiURL'],
110
138
  default: 'https://api.devicecloud.dev',
111
139
  description: 'API base URL',
112
140
  hidden: true,
@@ -123,10 +151,8 @@ class Cloud extends core_1.Command {
123
151
  default: false,
124
152
  description: '[Android only] Run your flow against arm64 devices',
125
153
  }),
126
- async: core_1.Flags.string({
127
- default: 'true',
154
+ async: core_1.Flags.boolean({
128
155
  description: 'Wait for the results of the run',
129
- options: ['true', 'false'],
130
156
  }),
131
157
  env: core_1.Flags.file({
132
158
  char: 'e',
@@ -155,10 +181,32 @@ class Cloud extends core_1.Command {
155
181
  multiple: true,
156
182
  parse: (input) => input.split(','),
157
183
  }),
184
+ 'ios-device': core_1.Flags.string({
185
+ description: '[iOS only] iOS device to run your flow against',
186
+ options: [
187
+ 'iphone-12',
188
+ 'iphone-12-mini',
189
+ 'iphone-12-pro-max',
190
+ 'iphone-13',
191
+ 'iphone-13-mini',
192
+ 'iphone-13-pro-max',
193
+ 'iphone-14',
194
+ 'iphone-14-plus',
195
+ 'iphone-14-pro',
196
+ 'iphone-14-pro-max',
197
+ 'iphone-15',
198
+ 'iphone-15-plus',
199
+ 'iphone-15-pro',
200
+ 'iphone-15-pro-max',
201
+ 'ipad-pro-6th-gen',
202
+ ],
203
+ }),
158
204
  'ios-version': core_1.Flags.string({
159
- aliases: ['ios-version'],
160
205
  description: '[iOS only] iOS version to run your flow against',
161
- options: ['16.4', '17.2'],
206
+ options: ['15', '16', '17'],
207
+ }),
208
+ name: core_1.Flags.string({
209
+ description: 'A custom name for your upload (useful for tagging commits etc)',
162
210
  }),
163
211
  orientation: core_1.Flags.string({
164
212
  description: '[Android only] The orientation of the device to run your flow against in degrees',
@@ -166,137 +214,201 @@ class Cloud extends core_1.Command {
166
214
  }),
167
215
  };
168
216
  async run() {
169
- const { args, flags } = await this.parse(Cloud);
170
- const { 'api-key': apiKey, 'api-url': apiUrl, 'app-binary-id': appBinaryId, 'app-file': appFile, arm64, async, env, 'exclude-tags': excludeTags, flows, 'google-play': googlePlay, 'include-tags': includeTags, orientation, ...rest } = flags;
171
- if (arm64) {
172
- (0, cli_ux_1.info)('Contact hello@devicecloud.dev to enquire about arm64 devices');
173
- (0, cli_ux_1.exit)();
174
- }
175
- const { firstFile, secondFile } = args;
176
- let finalBinaryId = appBinaryId;
177
- const finalAppFile = appFile ?? firstFile;
178
- let flowFile = flows ?? secondFile;
179
- if (appBinaryId) {
180
- if (secondFile) {
181
- throw new Error('You cannot provide both an appBinaryId and a binary file');
182
- }
183
- flowFile = flows ?? firstFile;
184
- }
185
- if (!flowFile) {
186
- throw new Error('You must provide a flow file');
187
- }
188
- let testFileNames = [];
189
- let continueOnFailure = true;
190
- let sequentialFlows = [];
191
- if (!flowFile?.endsWith('.yaml') &&
192
- !flowFile?.endsWith('.yml') &&
193
- !flowFile?.endsWith('/')) {
194
- flowFile += '/';
195
- }
196
217
  try {
197
- const executionPlan = await (0, plan_1.plan)(flowFile, includeTags.flat(), excludeTags.flat());
198
- testFileNames = executionPlan.flowsToRun;
199
- continueOnFailure = executionPlan.sequence?.continueOnFailure ?? true;
200
- sequentialFlows = executionPlan.sequence?.flows ?? [];
201
- }
202
- catch (error) {
203
- console.error(error);
204
- }
205
- if (!appBinaryId) {
206
- if (!(flowFile && finalAppFile)) {
207
- throw new Error('You must provide a flow file and an app binary id');
218
+ const { args, flags } = await this.parse(Cloud);
219
+ const { 'android-api-level': androidApiLevel, 'android-device': androidDevice, apiKey, apiUrl, 'app-binary-id': appBinaryId, 'app-file': appFile, arm64, async, env, 'exclude-tags': excludeTags, flows, 'google-play': googlePlay, 'include-tags': includeTags, 'ios-device': iOSDevice, 'ios-version': iOSVersion, name, orientation, ...rest } = flags;
220
+ if (arm64) {
221
+ (0, cli_ux_1.info)('Contact hello@devicecloud.dev to enquire about arm64 devices');
222
+ (0, cli_ux_1.exit)();
208
223
  }
209
- if (!finalAppFile.endsWith('.apk') && !finalAppFile.endsWith('.zip')) {
210
- throw new Error('App file must be a .apk or .zip file');
224
+ const { firstFile, secondFile } = args;
225
+ let finalBinaryId = appBinaryId;
226
+ const finalAppFile = appFile ?? firstFile;
227
+ let flowFile = flows ?? secondFile;
228
+ if (appBinaryId) {
229
+ if (secondFile) {
230
+ throw new Error('You cannot provide both an appBinaryId and a binary file');
231
+ }
232
+ flowFile = flows ?? firstFile;
211
233
  }
212
- this.log(`you want to run the flow(s) ${flowFile} against the app ${finalAppFile} with the following flags: ${JSON.stringify(flags)}\n`);
213
- }
214
- if (!finalBinaryId) {
215
- core_1.ux.action.start('Uploading binary', 'Initializing', { stdout: true });
216
- const binaryFormData = new FormData();
217
- const binaryBlob = new Blob([await (0, promises_1.readFile)(finalAppFile)], {
218
- type: mimeTypeLookupByExtension[finalAppFile.split('.').pop()],
234
+ if (!flowFile) {
235
+ throw new Error('You must provide a flow file');
236
+ }
237
+ if (iOSVersion) {
238
+ const iOSCompatibilityLookup = {
239
+ 'ipad-pro-6th-gen': ['16', '17'],
240
+ 'iphone-12': ['15', '16', '17'],
241
+ 'iphone-12-mini': ['15', '16', '17'],
242
+ 'iphone-12-pro-max': ['15', '16', '17'],
243
+ 'iphone-13': ['15', '16', '17'],
244
+ 'iphone-13-mini': ['15', '16', '17'],
245
+ 'iphone-13-pro-max': ['15', '16', '17'],
246
+ 'iphone-14': ['16', '17'],
247
+ 'iphone-14-plus': ['16', '17'],
248
+ 'iphone-14-pro': ['16', '17'],
249
+ 'iphone-14-pro-max': ['16', '17'],
250
+ 'iphone-15': ['17'],
251
+ 'iphone-15-plus': ['17'],
252
+ 'iphone-15-pro': ['17'],
253
+ 'iphone-15-pro-max': ['17'],
254
+ };
255
+ const iOSDeviceID = iOSDevice || 'iphone-14';
256
+ const supportediOSVersions = iOSCompatibilityLookup[iOSDeviceID];
257
+ if (!supportediOSVersions.includes(iOSVersion)) {
258
+ throw new Error(`${iOSDeviceID} only supports these iOS versions: ${supportediOSVersions.join(',')}`);
259
+ }
260
+ }
261
+ let testFileNames = [];
262
+ let continueOnFailure = true;
263
+ let sequentialFlows = [];
264
+ if (!flowFile?.endsWith('.yaml') &&
265
+ !flowFile?.endsWith('.yml') &&
266
+ !flowFile?.endsWith('/')) {
267
+ flowFile += '/';
268
+ }
269
+ try {
270
+ const executionPlan = await (0, plan_1.plan)(flowFile, includeTags.flat(), excludeTags.flat());
271
+ testFileNames = executionPlan.flowsToRun;
272
+ continueOnFailure = executionPlan.sequence?.continueOnFailure ?? true;
273
+ sequentialFlows = executionPlan.sequence?.flows ?? [];
274
+ }
275
+ catch (error) {
276
+ console.error(error);
277
+ }
278
+ if (!appBinaryId) {
279
+ if (!(flowFile && finalAppFile)) {
280
+ throw new Error('You must provide a flow file and an app binary id');
281
+ }
282
+ if (!finalAppFile.endsWith('.apk') && !finalAppFile.endsWith('.zip')) {
283
+ throw new Error('App file must be a .apk or .zip file');
284
+ }
285
+ }
286
+ const flagLogs = [];
287
+ for (const [k, v] of Object.entries(flags)) {
288
+ if (v && v.toString().length > 0) {
289
+ flagLogs.push(`${k}: ${v}`);
290
+ }
291
+ }
292
+ this.log(`
293
+
294
+ Submitting new job
295
+ → Flow(s): ${flowFile}
296
+ → App: ${appBinaryId || finalAppFile}
297
+
298
+ With options
299
+ → ${flagLogs.join(`
300
+ → `)}
301
+
302
+ `);
303
+ if (!finalBinaryId) {
304
+ core_1.ux.action.start('Uploading binary', 'Initializing', { stdout: true });
305
+ const binaryFormData = new FormData();
306
+ const binaryBlob = new Blob([await (0, promises_1.readFile)(finalAppFile)], {
307
+ type: mimeTypeLookupByExtension[finalAppFile.split('.').pop()],
308
+ });
309
+ binaryFormData.set('file', binaryBlob, finalAppFile);
310
+ const options = {
311
+ body: binaryFormData,
312
+ headers: { 'x-app-api-key': apiKey },
313
+ };
314
+ core_1.ux.action.status = `Uploading`;
315
+ const { binaryId, message } = await typeSafePost(apiUrl, '/uploads/binary', options);
316
+ if (!binaryId)
317
+ throw new Error(message);
318
+ core_1.ux.action.stop(`\nBinary uploaded with id: ${binaryId}`);
319
+ finalBinaryId = binaryId;
320
+ }
321
+ const testFormData = new FormData();
322
+ // eslint-disable-next-line unicorn/no-array-reduce
323
+ const envObject = (env ?? []).reduce((acc, cur) => {
324
+ const [key, value] = cur.split('=');
325
+ acc[key] = value;
326
+ return acc;
327
+ }, {});
328
+ const buffer = [...sequentialFlows, ...testFileNames]?.length > 1
329
+ ? await compressDir(flowFile.split('/').slice(0, -1).join('/'))
330
+ : await compressFile(flowFile);
331
+ const blob = new Blob([buffer], {
332
+ type: mimeTypeLookupByExtension.zip,
219
333
  });
220
- binaryFormData.set('file', binaryBlob, finalAppFile);
334
+ testFormData.set('file', blob, 'flowFile.zip');
335
+ testFormData.set('appBinaryId', finalBinaryId);
336
+ testFormData.set('testFileNames', JSON.stringify(testFileNames));
337
+ testFormData.set('sequentialFlows', JSON.stringify(sequentialFlows));
338
+ testFormData.set('env', JSON.stringify(envObject));
339
+ testFormData.set('googlePlay', googlePlay ? 'true' : 'false');
340
+ testFormData.set('config', JSON.stringify({ continueOnFailure, orientation }));
341
+ if (androidApiLevel) {
342
+ testFormData.set('androidApiLevel', androidApiLevel.toString());
343
+ }
344
+ if (androidDevice) {
345
+ testFormData.set('androidDevice', androidDevice.toString());
346
+ }
347
+ if (iOSVersion) {
348
+ testFormData.set('iOSVersion', iOSVersion.toString());
349
+ }
350
+ if (iOSDevice) {
351
+ testFormData.set('iOSDevice', iOSDevice.toString());
352
+ }
353
+ if (name) {
354
+ testFormData.set('name', name.toString());
355
+ }
356
+ for (const [key, value] of Object.entries(rest)) {
357
+ if (value) {
358
+ testFormData.set(key, value);
359
+ }
360
+ }
221
361
  const options = {
222
- body: binaryFormData,
362
+ body: testFormData,
223
363
  headers: { 'x-app-api-key': apiKey },
224
364
  };
225
- core_1.ux.action.status = `Uploading`;
226
- const { binaryId, message } = await typeSafePost(apiUrl, '/uploads/binary', options);
227
- if (!binaryId)
228
- throw new Error(message);
229
- core_1.ux.action.stop(`\nBinary uploaded with id: ${binaryId}`);
230
- finalBinaryId = binaryId;
231
- }
232
- const testFormData = new FormData();
233
- // eslint-disable-next-line unicorn/no-array-reduce
234
- const envObject = (env ?? []).reduce((acc, cur) => {
235
- const [key, value] = cur.split('=');
236
- acc[key] = value;
237
- return acc;
238
- }, {});
239
- const buffer = testFileNames?.length > 1
240
- ? await compressDir(flowFile.split('/').slice(0, -1).join('/'))
241
- : await compressFile(flowFile);
242
- const blob = new Blob([buffer], {
243
- type: mimeTypeLookupByExtension.zip,
244
- });
245
- testFormData.set('file', blob, 'flowFile.zip');
246
- testFormData.set('appBinaryId', finalBinaryId);
247
- testFormData.set('testFileNames', JSON.stringify(testFileNames));
248
- testFormData.set('sequentialFlows', JSON.stringify(sequentialFlows));
249
- testFormData.set('env', JSON.stringify(envObject));
250
- testFormData.set('googlePlay', googlePlay ? 'true' : 'false');
251
- testFormData.set('config', JSON.stringify({ continueOnFailure, orientation }));
252
- for (const [key, value] of Object.entries(rest)) {
253
- if (value) {
254
- testFormData.set(key, value);
365
+ const { message, results } = await typeSafePost(apiUrl, '/uploads/flow', options);
366
+ if (!results?.length)
367
+ (0, errors_1.error)('No tests created: ' + message);
368
+ (0, cli_ux_1.info)(`\nCreated ${results.length} tests: ${results
369
+ .map((r) => r.test_file_name)
370
+ .join(', ')}\n`);
371
+ (0, cli_ux_1.info)('Run triggered, you can access the results at:');
372
+ const url = `https://console.devicecloud.dev/results/${results[0].test_upload_id}/${results[0].id}`;
373
+ core_1.ux.url(url, url);
374
+ if (async) {
375
+ (0, cli_ux_1.info)('Not waiting for results as async flag is set to true');
376
+ (0, cli_ux_1.exit)(0);
255
377
  }
378
+ // poll for the run status every 5 seconds
379
+ core_1.ux.action.start('Waiting for results', 'Initializing', { stdout: true });
380
+ (0, cli_ux_1.info)('\nYou can safely close this terminal and the tests will continue\n');
381
+ const intervalId = setInterval(async () => {
382
+ const { results: updatedResults } = await typeSafeGet(apiUrl, `/results/${results[0].test_upload_id}`, {
383
+ headers: { 'x-app-api-key': apiKey },
384
+ });
385
+ if (!updatedResults) {
386
+ clearInterval(intervalId);
387
+ (0, errors_1.error)('No results found');
388
+ }
389
+ core_1.ux.action.status = '\nStatus | Test\n─────────── ───────────────';
390
+ for (const { status, test_file_name: test } of updatedResults) {
391
+ core_1.ux.action.status += `\n${status.padEnd(10, ' ')} | ${test}`;
392
+ }
393
+ if (updatedResults.every((result) => !['PENDING', 'RUNNING'].includes(result.status))) {
394
+ core_1.ux.action.stop('completed');
395
+ (0, cli_ux_1.info)('\n');
396
+ (0, cli_ux_1.table)(updatedResults, {
397
+ status: { get: (row) => row.status },
398
+ test: { get: (row) => row.test_file_name },
399
+ }, { printLine: this.log.bind(this) });
400
+ (0, cli_ux_1.info)('\n');
401
+ clearInterval(intervalId);
402
+ if (updatedResults.some((result) => result.status === 'FAILED')) {
403
+ (0, cli_ux_1.exit)(1);
404
+ }
405
+ }
406
+ }, 5000);
256
407
  }
257
- const options = {
258
- body: testFormData,
259
- headers: { 'x-app-api-key': apiKey },
260
- };
261
- const { message, results } = await typeSafePost(apiUrl, '/uploads/flow', options);
262
- if (!results?.length)
263
- (0, errors_1.error)('No tests created: ' + message);
264
- (0, cli_ux_1.info)(`\nCreated ${results.length} tests: ${results
265
- .map((r) => r.test_file_name)
266
- .join(', ')}\n`);
267
- (0, cli_ux_1.info)('Run triggered, you can access the results at:');
268
- (0, cli_ux_1.info)(`https://console.devicecloud.dev/results/${results[0].test_upload_id}/${results[0].id}/\n`);
269
- if (async === 'false') {
270
- (0, cli_ux_1.info)('Not waiting for results as async flag is set to false');
271
- (0, cli_ux_1.exit)(0);
408
+ catch (error) {
409
+ console.error(error);
410
+ (0, cli_ux_1.exit)(1);
272
411
  }
273
- // poll for the run status every 5 seconds
274
- core_1.ux.action.start('Waiting for results', 'Initializing', { stdout: true });
275
- (0, cli_ux_1.info)('You can safely close this terminal and the tests will continue\n');
276
- const intervalId = setInterval(async () => {
277
- const { results: updatedResults } = await typeSafeGet(apiUrl, `/results/${results[0].test_upload_id}`, {
278
- headers: { 'x-app-api-key': apiKey },
279
- });
280
- if (!updatedResults) {
281
- clearInterval(intervalId);
282
- (0, errors_1.error)('No results found');
283
- }
284
- core_1.ux.action.status = `\nStatus | Test
285
- ────────── ─────────── `;
286
- for (const { status, test_file_name: test } of updatedResults) {
287
- core_1.ux.action.status += `\n${status.padEnd(10, ' ')} | ${test}`;
288
- }
289
- if (updatedResults.every((result) => !['PENDING', 'RUNNING'].includes(result.status))) {
290
- core_1.ux.action.stop('completed');
291
- (0, cli_ux_1.info)('\n');
292
- (0, cli_ux_1.table)(updatedResults, {
293
- status: { get: (row) => row.status },
294
- test: { get: (row) => row.test_file_name },
295
- }, { printLine: this.log.bind(this) });
296
- (0, cli_ux_1.info)('\n');
297
- clearInterval(intervalId);
298
- }
299
- }, 5000);
300
412
  }
301
413
  }
302
414
  exports.default = Cloud;
@@ -20,9 +20,6 @@
20
20
  ],
21
21
  "flags": {
22
22
  "android-api-level": {
23
- "aliases": [
24
- "android-api-level"
25
- ],
26
23
  "description": "[Android only] Android API level to run your flow against",
27
24
  "name": "android-api-level",
28
25
  "hasDynamicHelp": false,
@@ -34,23 +31,39 @@
34
31
  ],
35
32
  "type": "option"
36
33
  },
37
- "api-key": {
34
+ "android-device": {
35
+ "description": "[Android only] Android device to run your flow against",
36
+ "name": "android-device",
37
+ "hasDynamicHelp": false,
38
+ "multiple": false,
39
+ "options": [
40
+ "pixel-6",
41
+ "pixel-6a",
42
+ "pixel-6-pro",
43
+ "pixel-7",
44
+ "pixel-7-pro",
45
+ "generic-tablet"
46
+ ],
47
+ "type": "option"
48
+ },
49
+ "apiKey": {
38
50
  "aliases": [
39
51
  "api-key"
40
52
  ],
41
53
  "description": "API key",
42
- "name": "api-key",
54
+ "name": "apiKey",
43
55
  "hasDynamicHelp": false,
44
56
  "multiple": false,
45
57
  "type": "option"
46
58
  },
47
- "api-url": {
59
+ "apiUrl": {
48
60
  "aliases": [
49
- "api-url"
61
+ "api-url",
62
+ "apiURL"
50
63
  ],
51
64
  "description": "API base URL",
52
65
  "hidden": true,
53
- "name": "api-url",
66
+ "name": "apiUrl",
54
67
  "default": "https://api.devicecloud.dev",
55
68
  "hasDynamicHelp": false,
56
69
  "multiple": false,
@@ -85,14 +98,8 @@
85
98
  "async": {
86
99
  "description": "Wait for the results of the run",
87
100
  "name": "async",
88
- "default": "true",
89
- "hasDynamicHelp": false,
90
- "multiple": false,
91
- "options": [
92
- "true",
93
- "false"
94
- ],
95
- "type": "option"
101
+ "allowNo": false,
102
+ "type": "boolean"
96
103
  },
97
104
  "env": {
98
105
  "char": "e",
@@ -140,20 +147,49 @@
140
147
  "multiple": true,
141
148
  "type": "option"
142
149
  },
143
- "ios-version": {
144
- "aliases": [
145
- "ios-version"
150
+ "ios-device": {
151
+ "description": "[iOS only] iOS device to run your flow against",
152
+ "name": "ios-device",
153
+ "hasDynamicHelp": false,
154
+ "multiple": false,
155
+ "options": [
156
+ "iphone-12",
157
+ "iphone-12-mini",
158
+ "iphone-12-pro-max",
159
+ "iphone-13",
160
+ "iphone-13-mini",
161
+ "iphone-13-pro-max",
162
+ "iphone-14",
163
+ "iphone-14-plus",
164
+ "iphone-14-pro",
165
+ "iphone-14-pro-max",
166
+ "iphone-15",
167
+ "iphone-15-plus",
168
+ "iphone-15-pro",
169
+ "iphone-15-pro-max",
170
+ "ipad-pro-6th-gen"
146
171
  ],
172
+ "type": "option"
173
+ },
174
+ "ios-version": {
147
175
  "description": "[iOS only] iOS version to run your flow against",
148
176
  "name": "ios-version",
149
177
  "hasDynamicHelp": false,
150
178
  "multiple": false,
151
179
  "options": [
152
- "16.4",
153
- "17.2"
180
+ "15",
181
+ "16",
182
+ "17"
154
183
  ],
155
184
  "type": "option"
156
185
  },
186
+ "name": {
187
+ "description": "A custom name for your upload (useful for tagging commits etc)",
188
+ "name": "name",
189
+ "hasDynamicHelp": false,
190
+ "multiple": false,
191
+ "type": "option"
192
+ },
157
193
  "orientation": {
158
194
  "description": "[Android only] The orientation of the device to run your flow against in degrees",
159
195
  "name": "orientation",
@@ -184,5 +220,5 @@
184
220
  ]
185
221
  }
186
222
  },
187
- "version": "0.0.1-alpha.8"
223
+ "version": "0.0.1"
188
224
  }
package/package.json CHANGED
@@ -53,10 +53,7 @@
53
53
  "commands": "./dist/commands",
54
54
  "plugins": [
55
55
  "@oclif/plugin-help",
56
- "@oclif/plugin-not-found",
57
- "@oclif/plugin-update",
58
- "@oclif/plugin-warn-if-update-available",
59
- "@oclif/plugin-autocomplete"
56
+ "@oclif/plugin-not-found"
60
57
  ]
61
58
  },
62
59
  "private": false,
@@ -75,7 +72,7 @@
75
72
  "test": "mocha --forbid-only \"test/**/*.test.ts\"",
76
73
  "version": "oclif readme && git add README.md"
77
74
  },
78
- "version": "0.0.1-alpha.8",
75
+ "version": "0.0.1",
79
76
  "bugs": {
80
77
  "url": "https://discord.gg/GzZBHcUJ"
81
78
  },
@@ -88,4 +85,4 @@
88
85
  "testing"
89
86
  ],
90
87
  "types": "dist/index.d.ts"
91
- }
88
+ }