@devicecloud.dev/dcd 3.2.2 → 3.3.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/dist/commands/cloud.d.ts +1 -0
- package/dist/commands/cloud.js +82 -70
- package/dist/commands/status.d.ts +14 -0
- package/dist/commands/status.js +77 -0
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +4 -5
- package/dist/methods.d.ts +10 -3
- package/dist/methods.js +25 -6
- package/oclif.manifest.json +81 -6
- package/package.json +1 -1
package/dist/commands/cloud.d.ts
CHANGED
|
@@ -50,6 +50,7 @@ export default class Cloud extends Command {
|
|
|
50
50
|
'ignore-sha-check': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
51
51
|
'ios-device': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
52
52
|
'ios-version': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
53
|
+
'x86-arch': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
53
54
|
'maestro-version': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
54
55
|
name: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
55
56
|
orientation: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
package/dist/commands/cloud.js
CHANGED
|
@@ -38,6 +38,15 @@ var EAndroidDevices;
|
|
|
38
38
|
EAndroidDevices["pixel-7"] = "pixel-7";
|
|
39
39
|
EAndroidDevices["pixel-7-pro"] = "pixel-7-pro";
|
|
40
40
|
})(EAndroidDevices || (exports.EAndroidDevices = EAndroidDevices = {}));
|
|
41
|
+
// Suppress punycode deprecation warning (caused by whatwg, supabase dependancy)
|
|
42
|
+
process.removeAllListeners('warning');
|
|
43
|
+
process.on('warning', (warning) => {
|
|
44
|
+
if (warning.name === 'DeprecationWarning' &&
|
|
45
|
+
warning.message.includes('punycode')) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
console.warn(warning);
|
|
49
|
+
});
|
|
41
50
|
class Cloud extends core_1.Command {
|
|
42
51
|
static args = {
|
|
43
52
|
firstFile: core_1.Args.string({
|
|
@@ -62,7 +71,7 @@ class Cloud extends core_1.Command {
|
|
|
62
71
|
}
|
|
63
72
|
await (0, methods_1.versionCheck)(this.config.version);
|
|
64
73
|
const { args, flags, raw } = await this.parse(Cloud);
|
|
65
|
-
const { '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, async, '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, ...rest } = flags;
|
|
74
|
+
const { '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, async, '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, 'x86-arch': x86Arch, ...rest } = flags;
|
|
66
75
|
const apiKey = apiKeyFlag || process.env.DEVICE_CLOUD_API_KEY;
|
|
67
76
|
if (!apiKey)
|
|
68
77
|
throw new Error('You must provide an API key via --api-key flag or DEVICE_CLOUD_API_KEY environment variable');
|
|
@@ -121,9 +130,7 @@ class Cloud extends core_1.Command {
|
|
|
121
130
|
executionPlan = await (0, plan_1.plan)(flowFile, includeTags.flat(), excludeTags.flat(), excludeFlows.flat());
|
|
122
131
|
}
|
|
123
132
|
catch (error) {
|
|
124
|
-
|
|
125
|
-
// eslint-disable-next-line unicorn/no-process-exit
|
|
126
|
-
process.exit(2);
|
|
133
|
+
throw error;
|
|
127
134
|
}
|
|
128
135
|
const { allExcludeTags, allIncludeTags, flowsToRun: testFileNames, referencedFiles, sequence, workspaceConfig, } = executionPlan;
|
|
129
136
|
const pathsShortestToLongest = [
|
|
@@ -219,6 +226,7 @@ class Cloud extends core_1.Command {
|
|
|
219
226
|
deviceLocale,
|
|
220
227
|
maestroVersion,
|
|
221
228
|
orientation,
|
|
229
|
+
x86Arch,
|
|
222
230
|
report,
|
|
223
231
|
raw: JSON.stringify(raw),
|
|
224
232
|
uploadedBinaryIds,
|
|
@@ -255,91 +263,95 @@ class Cloud extends core_1.Command {
|
|
|
255
263
|
const { message, results } = await (0, methods_1.typeSafePost)(apiUrl, '/uploads/flow', options);
|
|
256
264
|
if (!results?.length)
|
|
257
265
|
(0, errors_1.error)('No tests created: ' + message);
|
|
258
|
-
|
|
266
|
+
this.log(`\nCreated ${results.length} tests: ${results
|
|
259
267
|
.map((r) => r.test_file_name)
|
|
260
268
|
.sort((a, b) => a.localeCompare(b))
|
|
261
269
|
.join(', ')}\n`);
|
|
262
|
-
|
|
270
|
+
this.log('Run triggered, you can access the results at:');
|
|
263
271
|
const url = `https://console.devicecloud.dev/results?upload=${results[0].test_upload_id}&result=${results[0].id}`;
|
|
264
272
|
core_1.ux.url(url, url);
|
|
265
273
|
if (async) {
|
|
266
|
-
|
|
274
|
+
this.log('Not waiting for results as async flag is set to true');
|
|
267
275
|
return;
|
|
268
276
|
}
|
|
269
277
|
// poll for the run status every 5 seconds
|
|
270
278
|
core_1.ux.action.start('Waiting for results', 'Initializing', { stdout: true });
|
|
271
|
-
|
|
279
|
+
this.log('\nYou can safely close this terminal and the tests will continue\n');
|
|
272
280
|
let sequentialPollFaillures = 0;
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
if (!quiet) {
|
|
282
|
-
core_1.ux.action.status =
|
|
283
|
-
'\nStatus Test\n─────────── ───────────────';
|
|
284
|
-
for (const { retry_of: isRetry, status, test_file_name: test, } of updatedResults) {
|
|
285
|
-
core_1.ux.action.status += `\n${status.padEnd(10, ' ')} ${test} ${isRetry ? '(retry)' : ''}`;
|
|
281
|
+
await new Promise((resolve, reject) => {
|
|
282
|
+
const intervalId = setInterval(async () => {
|
|
283
|
+
try {
|
|
284
|
+
const { results: updatedResults } = await (0, methods_1.typeSafeGet)(apiUrl, `/results/${results[0].test_upload_id}`, {
|
|
285
|
+
headers: { 'x-app-api-key': apiKey },
|
|
286
|
+
});
|
|
287
|
+
if (!updatedResults) {
|
|
288
|
+
throw new Error('no results');
|
|
286
289
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
status: { get: (row) => row.status },
|
|
293
|
-
test: {
|
|
294
|
-
get: (row) => `${row.test_file_name} ${row.retry_of ? '(retry)' : ''}`,
|
|
295
|
-
},
|
|
296
|
-
}, { printLine: this.log.bind(this) });
|
|
297
|
-
(0, cli_ux_1.info)('\n');
|
|
298
|
-
(0, cli_ux_1.info)('Run completed, you can access the results at:');
|
|
299
|
-
core_1.ux.url(url, url);
|
|
300
|
-
(0, cli_ux_1.info)('\n');
|
|
301
|
-
clearInterval(intervalId);
|
|
302
|
-
if (downloadArtifacts) {
|
|
303
|
-
try {
|
|
304
|
-
await (0, methods_1.typeSafePostDownload)(apiUrl, `/results/${results[0].test_upload_id}/download`, {
|
|
305
|
-
body: JSON.stringify({ results: downloadArtifacts }),
|
|
306
|
-
headers: {
|
|
307
|
-
'content-type': 'application/json',
|
|
308
|
-
'x-app-api-key': apiKey,
|
|
309
|
-
},
|
|
310
|
-
});
|
|
311
|
-
(0, cli_ux_1.info)('\n');
|
|
312
|
-
(0, cli_ux_1.info)('Test artifacts have been downloaded to ./artifacts.zip');
|
|
313
|
-
}
|
|
314
|
-
catch {
|
|
315
|
-
this.warn('Failed to download artifacts');
|
|
290
|
+
if (!quiet) {
|
|
291
|
+
core_1.ux.action.status =
|
|
292
|
+
'\nStatus Test\n─────────── ───────────────';
|
|
293
|
+
for (const { retry_of: isRetry, status, test_file_name: test, } of updatedResults) {
|
|
294
|
+
core_1.ux.action.status += `\n${status.padEnd(10, ' ')} ${test} ${isRetry ? '(retry)' : ''}`;
|
|
316
295
|
}
|
|
317
296
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
297
|
+
if (updatedResults.every((result) => !['PENDING', 'RUNNING'].includes(result.status))) {
|
|
298
|
+
core_1.ux.action.stop('completed');
|
|
299
|
+
this.log('\n');
|
|
300
|
+
(0, cli_ux_1.table)(updatedResults, {
|
|
301
|
+
status: { get: (row) => row.status },
|
|
302
|
+
test: {
|
|
303
|
+
get: (row) => `${row.test_file_name} ${row.retry_of ? '(retry)' : ''}`,
|
|
304
|
+
},
|
|
305
|
+
}, { printLine: this.log.bind(this) });
|
|
306
|
+
this.log('\n');
|
|
307
|
+
this.log('Run completed, you can access the results at:');
|
|
308
|
+
core_1.ux.url(url, url);
|
|
309
|
+
this.log('\n');
|
|
310
|
+
clearInterval(intervalId);
|
|
311
|
+
if (downloadArtifacts) {
|
|
312
|
+
try {
|
|
313
|
+
await (0, methods_1.typeSafePostDownload)(apiUrl, `/results/${results[0].test_upload_id}/download`, {
|
|
314
|
+
body: JSON.stringify({ results: downloadArtifacts }),
|
|
315
|
+
headers: {
|
|
316
|
+
'content-type': 'application/json',
|
|
317
|
+
'x-app-api-key': apiKey,
|
|
318
|
+
},
|
|
319
|
+
});
|
|
320
|
+
this.log('\n');
|
|
321
|
+
this.log('Test artifacts have been downloaded to ./artifacts.zip');
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
this.warn('Failed to download artifacts');
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
const resultsWithoutEarlierTries = updatedResults.filter((result) => {
|
|
328
|
+
const beenRetried = updatedResults.find((r) => r.retry_of === result.id);
|
|
329
|
+
return !beenRetried;
|
|
330
|
+
});
|
|
331
|
+
if (resultsWithoutEarlierTries.some((result) => result.status === 'FAILED')) {
|
|
332
|
+
reject(new Error('RUN_FAILED'));
|
|
333
|
+
}
|
|
334
|
+
sequentialPollFaillures = 0;
|
|
335
|
+
resolve();
|
|
325
336
|
}
|
|
326
|
-
sequentialPollFaillures = 0;
|
|
327
337
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
338
|
+
catch (error) {
|
|
339
|
+
sequentialPollFaillures++;
|
|
340
|
+
if (sequentialPollFaillures > 5) {
|
|
341
|
+
// dropped poll requests shouldn't err user CI
|
|
342
|
+
clearInterval(intervalId);
|
|
343
|
+
throw new Error('unable to fetch results after 5 attempts');
|
|
344
|
+
}
|
|
345
|
+
this.log('unable to fetch results, trying again...');
|
|
335
346
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
}, 5000);
|
|
347
|
+
}, 5000);
|
|
348
|
+
});
|
|
339
349
|
}
|
|
340
350
|
catch (error) {
|
|
341
|
-
|
|
342
|
-
|
|
351
|
+
if (error instanceof Error && error.message === 'RUN_FAILED') {
|
|
352
|
+
this.exit(2);
|
|
353
|
+
}
|
|
354
|
+
this.error(error, { exit: 1 });
|
|
343
355
|
}
|
|
344
356
|
}
|
|
345
357
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class Status extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
name: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
8
|
+
'upload-id': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
9
|
+
apiKey: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
10
|
+
apiUrl: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
|
+
};
|
|
12
|
+
private getStatusSymbol;
|
|
13
|
+
run(): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const constants_1 = require("../constants");
|
|
5
|
+
const methods_1 = require("../methods");
|
|
6
|
+
class Status extends core_1.Command {
|
|
7
|
+
static description = 'Get the status of an upload by name or upload ID';
|
|
8
|
+
static examples = [
|
|
9
|
+
'<%= config.bin %> <%= command.id %> --name my-upload-name',
|
|
10
|
+
'<%= config.bin %> <%= command.id %> --upload-id 123e4567-e89b-12d3-a456-426614174000 --json',
|
|
11
|
+
];
|
|
12
|
+
static flags = {
|
|
13
|
+
json: core_1.Flags.boolean({
|
|
14
|
+
description: 'output in json format',
|
|
15
|
+
}),
|
|
16
|
+
name: core_1.Flags.string({
|
|
17
|
+
description: 'Name of the upload to check status for',
|
|
18
|
+
exclusive: ['upload-id'],
|
|
19
|
+
}),
|
|
20
|
+
'upload-id': core_1.Flags.string({
|
|
21
|
+
description: 'UUID of the upload to check status for',
|
|
22
|
+
exclusive: ['name'],
|
|
23
|
+
}),
|
|
24
|
+
apiKey: constants_1.flags.apiKey,
|
|
25
|
+
apiUrl: constants_1.flags.apiUrl,
|
|
26
|
+
};
|
|
27
|
+
getStatusSymbol(status) {
|
|
28
|
+
switch (status) {
|
|
29
|
+
case 'SUCCESS':
|
|
30
|
+
return '✓';
|
|
31
|
+
case 'FAILED':
|
|
32
|
+
return '✗';
|
|
33
|
+
case 'CANCELED':
|
|
34
|
+
return '⊘';
|
|
35
|
+
case 'PENDING':
|
|
36
|
+
return '⋯';
|
|
37
|
+
default:
|
|
38
|
+
return '?';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async run() {
|
|
42
|
+
const { flags } = await this.parse(Status);
|
|
43
|
+
const { apiUrl, apiKey, name, 'upload-id': uploadId } = flags;
|
|
44
|
+
if (!apiKey) {
|
|
45
|
+
this.error('API Key is required. Please provide it via --api-key flag or DEVICE_CLOUD_API_KEY environment variable.');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (!name && !uploadId) {
|
|
49
|
+
this.error('Either --name or --upload-id must be provided');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const status = await (0, methods_1.getUploadStatus)(apiUrl, apiKey, {
|
|
54
|
+
name,
|
|
55
|
+
uploadId,
|
|
56
|
+
});
|
|
57
|
+
if (flags.json) {
|
|
58
|
+
this.log(JSON.stringify(status, null, 2));
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
this.log('\nUpload Status:');
|
|
62
|
+
this.log('─'.repeat(50));
|
|
63
|
+
status.forEach((item) => {
|
|
64
|
+
const symbol = this.getStatusSymbol(item.status);
|
|
65
|
+
this.log(`\n${symbol} Flow: ${item.name}`);
|
|
66
|
+
this.log(` Status: ${item.status}`);
|
|
67
|
+
this.log('─'.repeat(50));
|
|
68
|
+
});
|
|
69
|
+
this.log(''); // Add empty line at the end
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
this.error(`Failed to get status: ${error.message}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
exports.default = Status;
|
package/dist/constants.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export declare const flags: {
|
|
|
20
20
|
'ignore-sha-check': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
21
21
|
'ios-device': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
22
22
|
'ios-version': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
23
|
+
'x86-arch': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
23
24
|
'maestro-version': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
24
25
|
name: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
25
26
|
orientation: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
package/dist/constants.js
CHANGED
|
@@ -122,17 +122,16 @@ exports.flags = {
|
|
|
122
122
|
description: '[iOS only] iOS version to run your flow against',
|
|
123
123
|
options: ['16', '17', '18'],
|
|
124
124
|
}),
|
|
125
|
+
'x86-arch': core_1.Flags.boolean({
|
|
126
|
+
description: '[iOS only, experimental] Run your flow against x86 architecture simulator instead of arm64',
|
|
127
|
+
default: false,
|
|
128
|
+
}),
|
|
125
129
|
'maestro-version': core_1.Flags.string({
|
|
126
130
|
aliases: ['maestroVersion'],
|
|
127
131
|
default: '1.39.5',
|
|
128
132
|
description: 'Maestro version to run your flow against',
|
|
129
133
|
options: [
|
|
130
134
|
'1.36.0',
|
|
131
|
-
'1.37.0',
|
|
132
|
-
'1.37.1',
|
|
133
|
-
'1.37.2',
|
|
134
|
-
'1.37.3',
|
|
135
|
-
'1.37.4',
|
|
136
135
|
'1.37.5',
|
|
137
136
|
'1.37.6',
|
|
138
137
|
'1.37.7',
|
package/dist/methods.d.ts
CHANGED
|
@@ -14,10 +14,10 @@ export declare const typeSafeGet: <T extends keyof paths>(baseUrl: string, path:
|
|
|
14
14
|
body?: FormData;
|
|
15
15
|
headers?: HeadersInit;
|
|
16
16
|
}) => Promise<paths[T]["get"]["responses"]["200"]["content"]["application/json"]>;
|
|
17
|
-
export declare const toBuffer: (archive: archiver.Archiver) => Promise<Buffer
|
|
18
|
-
export declare const compressDir: (sourceDir: string) => Promise<Buffer
|
|
17
|
+
export declare const toBuffer: (archive: archiver.Archiver) => Promise<Buffer<ArrayBuffer>>;
|
|
18
|
+
export declare const compressDir: (sourceDir: string) => Promise<Buffer<ArrayBuffer>>;
|
|
19
19
|
export declare const compressFolderToBlob: (sourceDir: string) => Promise<Blob>;
|
|
20
|
-
export declare const compressFilesFromRelativePath: (path: string, files: string[], commonRoot: string) => Promise<Buffer
|
|
20
|
+
export declare const compressFilesFromRelativePath: (path: string, files: string[], commonRoot: string) => Promise<Buffer<ArrayBuffer>>;
|
|
21
21
|
export declare const verifyAppZip: (zipPath: string) => Promise<void>;
|
|
22
22
|
export declare const extractAppMetadataAndroid: (appFilePath: string) => Promise<TAppMetadata>;
|
|
23
23
|
export declare const extractAppMetadataIosZip: (appFilePath: string) => Promise<TAppMetadata>;
|
|
@@ -25,3 +25,10 @@ export declare const extractAppMetadataIos: (appFolderPath: string) => Promise<T
|
|
|
25
25
|
export declare const uploadBinary: (filePath: string, apiUrl: string, apiKey: string, ignoreShaCheck?: boolean) => Promise<string>;
|
|
26
26
|
export declare const uploadBinaries: (finalAppFiles: string[], apiUrl: string, apiKey: string, ignoreShaCheck?: boolean) => Promise<string[]>;
|
|
27
27
|
export declare const verifyAdditionalAppFiles: (appFiles: string[] | undefined) => Promise<void>;
|
|
28
|
+
export declare const getUploadStatus: (apiUrl: string, apiKey: string, options: {
|
|
29
|
+
uploadId?: string;
|
|
30
|
+
name?: string;
|
|
31
|
+
}) => Promise<{
|
|
32
|
+
name: string;
|
|
33
|
+
status: "SUCCESS" | "FAILED" | "CANCELED" | "PENDING";
|
|
34
|
+
}[]>;
|
package/dist/methods.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
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 = exports.versionCheck = void 0;
|
|
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 = exports.versionCheck = 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
|
|
@@ -33,7 +33,7 @@ const versionCheck = async (currentVersion) => {
|
|
|
33
33
|
const versionResponseJson = await versionResponse.json();
|
|
34
34
|
const latestVersion = versionResponseJson.version;
|
|
35
35
|
if (latestVersion !== currentVersion) {
|
|
36
|
-
|
|
36
|
+
console.log(`
|
|
37
37
|
-------------------
|
|
38
38
|
A new version of the devicecloud.dev CLI is available: ${latestVersion}
|
|
39
39
|
Run 'npm install -g @devicecloud.dev/dcd@latest' to update to the latest version
|
|
@@ -272,16 +272,16 @@ const uploadBinary = async (filePath, apiUrl, apiKey, ignoreShaCheck = false) =>
|
|
|
272
272
|
// this needs to made nicer by using envs or maybe fetching the keys from the getSignedURL call
|
|
273
273
|
const SB = {
|
|
274
274
|
dev: {
|
|
275
|
-
|
|
275
|
+
SUPABASE_PUBLIC_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImxibXNvd2VodGp3bnFsdXJwZW1iIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDkyMTg0ODcsImV4cCI6MjAyNDc5NDQ4N30.zeLTMAuZ_WwYvGdeP0kdvL_Zrs-RQee5APPyxmWq7qQ',
|
|
276
276
|
SUPABASE_URL: 'https://lbmsowehtjwnqlurpemb.supabase.co',
|
|
277
277
|
},
|
|
278
278
|
prod: {
|
|
279
|
-
|
|
279
|
+
SUPABASE_PUBLIC_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBneWRucGhiaW1ldGluc2dma2JvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDc1OTQzNDYsImV4cCI6MjAyMzE3MDM0Nn0.hAYOMFxxwX1exkQkY9xyQJGC_GhGnyogkj2N-kBkMI8',
|
|
280
280
|
SUPABASE_URL: 'https://pgydnphbimetinsgfkbo.supabase.co',
|
|
281
281
|
},
|
|
282
282
|
};
|
|
283
|
-
const {
|
|
284
|
-
const supabase = (0, supabase_js_1.createClient)(SUPABASE_URL,
|
|
283
|
+
const { SUPABASE_PUBLIC_KEY, SUPABASE_URL } = SB[apiUrl === 'https://api.devicecloud.dev' ? 'prod' : 'dev'];
|
|
284
|
+
const supabase = (0, supabase_js_1.createClient)(SUPABASE_URL, SUPABASE_PUBLIC_KEY);
|
|
285
285
|
const uploadToUrl = await supabase.storage
|
|
286
286
|
.from('organizations')
|
|
287
287
|
.uploadToSignedUrl(path, token, file);
|
|
@@ -337,3 +337,22 @@ async function getFileHashFromFile(file) {
|
|
|
337
337
|
processChunks();
|
|
338
338
|
});
|
|
339
339
|
}
|
|
340
|
+
const getUploadStatus = async (apiUrl, apiKey, options) => {
|
|
341
|
+
const queryParams = new URLSearchParams();
|
|
342
|
+
if (options.uploadId) {
|
|
343
|
+
queryParams.append('uploadId', options.uploadId);
|
|
344
|
+
}
|
|
345
|
+
if (options.name) {
|
|
346
|
+
queryParams.append('name', options.name);
|
|
347
|
+
}
|
|
348
|
+
const response = await fetch(`${apiUrl}/uploads/status?${queryParams}`, {
|
|
349
|
+
headers: {
|
|
350
|
+
'x-app-api-key': apiKey,
|
|
351
|
+
},
|
|
352
|
+
});
|
|
353
|
+
if (!response.ok) {
|
|
354
|
+
throw new Error(`Failed to fetch status: ${response.statusText}`);
|
|
355
|
+
}
|
|
356
|
+
return response.json();
|
|
357
|
+
};
|
|
358
|
+
exports.getUploadStatus = getUploadStatus;
|
package/oclif.manifest.json
CHANGED
|
@@ -227,6 +227,12 @@
|
|
|
227
227
|
],
|
|
228
228
|
"type": "option"
|
|
229
229
|
},
|
|
230
|
+
"x86-arch": {
|
|
231
|
+
"description": "[iOS only, experimental] Run your flow against x86 architecture simulator instead of arm64",
|
|
232
|
+
"name": "x86-arch",
|
|
233
|
+
"allowNo": false,
|
|
234
|
+
"type": "boolean"
|
|
235
|
+
},
|
|
230
236
|
"maestro-version": {
|
|
231
237
|
"aliases": [
|
|
232
238
|
"maestroVersion"
|
|
@@ -238,11 +244,6 @@
|
|
|
238
244
|
"multiple": false,
|
|
239
245
|
"options": [
|
|
240
246
|
"1.36.0",
|
|
241
|
-
"1.37.0",
|
|
242
|
-
"1.37.1",
|
|
243
|
-
"1.37.2",
|
|
244
|
-
"1.37.3",
|
|
245
|
-
"1.37.4",
|
|
246
247
|
"1.37.5",
|
|
247
248
|
"1.37.6",
|
|
248
249
|
"1.37.7",
|
|
@@ -321,7 +322,81 @@
|
|
|
321
322
|
"commands",
|
|
322
323
|
"cloud.js"
|
|
323
324
|
]
|
|
325
|
+
},
|
|
326
|
+
"status": {
|
|
327
|
+
"aliases": [],
|
|
328
|
+
"args": {},
|
|
329
|
+
"description": "Get the status of an upload by name or upload ID",
|
|
330
|
+
"examples": [
|
|
331
|
+
"<%= config.bin %> <%= command.id %> --name my-upload-name",
|
|
332
|
+
"<%= config.bin %> <%= command.id %> --upload-id 123e4567-e89b-12d3-a456-426614174000 --json"
|
|
333
|
+
],
|
|
334
|
+
"flags": {
|
|
335
|
+
"json": {
|
|
336
|
+
"description": "output in json format",
|
|
337
|
+
"name": "json",
|
|
338
|
+
"allowNo": false,
|
|
339
|
+
"type": "boolean"
|
|
340
|
+
},
|
|
341
|
+
"name": {
|
|
342
|
+
"description": "Name of the upload to check status for",
|
|
343
|
+
"exclusive": [
|
|
344
|
+
"upload-id"
|
|
345
|
+
],
|
|
346
|
+
"name": "name",
|
|
347
|
+
"hasDynamicHelp": false,
|
|
348
|
+
"multiple": false,
|
|
349
|
+
"type": "option"
|
|
350
|
+
},
|
|
351
|
+
"upload-id": {
|
|
352
|
+
"description": "UUID of the upload to check status for",
|
|
353
|
+
"exclusive": [
|
|
354
|
+
"name"
|
|
355
|
+
],
|
|
356
|
+
"name": "upload-id",
|
|
357
|
+
"hasDynamicHelp": false,
|
|
358
|
+
"multiple": false,
|
|
359
|
+
"type": "option"
|
|
360
|
+
},
|
|
361
|
+
"apiKey": {
|
|
362
|
+
"aliases": [
|
|
363
|
+
"api-key"
|
|
364
|
+
],
|
|
365
|
+
"description": "API key for devicecloud.dev (find this in the console UI). You can also set the DEVICE_CLOUD_API_KEY environment variable.",
|
|
366
|
+
"name": "apiKey",
|
|
367
|
+
"hasDynamicHelp": false,
|
|
368
|
+
"multiple": false,
|
|
369
|
+
"type": "option"
|
|
370
|
+
},
|
|
371
|
+
"apiUrl": {
|
|
372
|
+
"aliases": [
|
|
373
|
+
"api-url",
|
|
374
|
+
"apiURL"
|
|
375
|
+
],
|
|
376
|
+
"description": "API base URL",
|
|
377
|
+
"hidden": true,
|
|
378
|
+
"name": "apiUrl",
|
|
379
|
+
"default": "https://api.devicecloud.dev",
|
|
380
|
+
"hasDynamicHelp": false,
|
|
381
|
+
"multiple": false,
|
|
382
|
+
"type": "option"
|
|
383
|
+
}
|
|
384
|
+
},
|
|
385
|
+
"hasDynamicHelp": false,
|
|
386
|
+
"hiddenAliases": [],
|
|
387
|
+
"id": "status",
|
|
388
|
+
"pluginAlias": "@devicecloud.dev/dcd",
|
|
389
|
+
"pluginName": "@devicecloud.dev/dcd",
|
|
390
|
+
"pluginType": "core",
|
|
391
|
+
"strict": true,
|
|
392
|
+
"enableJsonFlag": false,
|
|
393
|
+
"isESM": false,
|
|
394
|
+
"relativePath": [
|
|
395
|
+
"dist",
|
|
396
|
+
"commands",
|
|
397
|
+
"status.js"
|
|
398
|
+
]
|
|
324
399
|
}
|
|
325
400
|
},
|
|
326
|
-
"version": "3.
|
|
401
|
+
"version": "3.3.0"
|
|
327
402
|
}
|