@devicecloud.dev/dcd 0.0.1-alpha.5 → 0.0.1-alpha.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.
- package/dist/commands/cloud.d.ts +1 -0
- package/dist/commands/cloud.js +64 -15
- package/oclif.manifest.json +11 -5
- package/package.json +1 -1
package/dist/commands/cloud.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export default class Cloud extends Command {
|
|
|
12
12
|
apiUrl: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
13
13
|
appBinaryId: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
14
14
|
appFile: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
15
|
+
async: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
15
16
|
env: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
16
17
|
excludeTags: import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
17
18
|
flows: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
package/dist/commands/cloud.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
/* eslint-disable complexity */
|
|
4
4
|
const core_1 = require("@oclif/core");
|
|
5
|
+
const cli_ux_1 = require("@oclif/core/lib/cli-ux");
|
|
6
|
+
const errors_1 = require("@oclif/core/lib/errors");
|
|
5
7
|
const archiver = require("archiver");
|
|
6
8
|
const promises_1 = require("node:fs/promises");
|
|
7
9
|
const node_stream_1 = require("node:stream");
|
|
@@ -21,7 +23,14 @@ const PERMITTED_EXTENSIONS = new Set([
|
|
|
21
23
|
'mp4',
|
|
22
24
|
'js',
|
|
23
25
|
]);
|
|
24
|
-
const
|
|
26
|
+
const typeSafePost = async (baseUrl, path, init) => {
|
|
27
|
+
const res = await fetch(baseUrl + path, { ...init, method: 'POST' });
|
|
28
|
+
if (!res.ok) {
|
|
29
|
+
throw new Error(await res.text());
|
|
30
|
+
}
|
|
31
|
+
return res.json();
|
|
32
|
+
};
|
|
33
|
+
const typeSafeGet = async (baseUrl, path, init) => {
|
|
25
34
|
const res = await fetch(baseUrl + path, init);
|
|
26
35
|
if (!res.ok) {
|
|
27
36
|
throw new Error(await res.text());
|
|
@@ -105,11 +114,15 @@ class Cloud extends core_1.Command {
|
|
|
105
114
|
}),
|
|
106
115
|
appFile: core_1.Flags.file({
|
|
107
116
|
aliases: ['app-file'],
|
|
108
|
-
description: 'App binary to run your
|
|
117
|
+
description: 'App binary to run your flows against',
|
|
118
|
+
}),
|
|
119
|
+
async: core_1.Flags.boolean({
|
|
120
|
+
default: true,
|
|
121
|
+
description: 'Wait for the results of the run',
|
|
109
122
|
}),
|
|
110
123
|
env: core_1.Flags.file({
|
|
111
124
|
char: 'e',
|
|
112
|
-
description: 'One or more environment variables to inject into your
|
|
125
|
+
description: 'One or more environment variables to inject into your flows',
|
|
113
126
|
multiple: true,
|
|
114
127
|
}),
|
|
115
128
|
excludeTags: core_1.Flags.string({
|
|
@@ -120,7 +133,7 @@ class Cloud extends core_1.Command {
|
|
|
120
133
|
parse: (input) => input.split(','),
|
|
121
134
|
}),
|
|
122
135
|
flows: core_1.Flags.string({
|
|
123
|
-
description: 'The path to the flow file or folder containing your
|
|
136
|
+
description: 'The path to the flow file or folder containing your flows',
|
|
124
137
|
}),
|
|
125
138
|
iOSVersion: core_1.Flags.string({
|
|
126
139
|
aliases: ['ios-version'],
|
|
@@ -130,15 +143,14 @@ class Cloud extends core_1.Command {
|
|
|
130
143
|
includeTags: core_1.Flags.string({
|
|
131
144
|
aliases: ['include-tags'],
|
|
132
145
|
default: [],
|
|
133
|
-
description: 'Only
|
|
146
|
+
description: 'Only flows which have these tags will be included in the run',
|
|
134
147
|
multiple: true,
|
|
135
148
|
parse: (input) => input.split(','),
|
|
136
149
|
}),
|
|
137
150
|
};
|
|
138
151
|
async run() {
|
|
139
152
|
const { args, flags } = await this.parse(Cloud);
|
|
140
|
-
const { apiKey, apiUrl, appBinaryId, appFile, env, excludeTags, flows, includeTags, ...rest } = flags;
|
|
141
|
-
console.log({ args });
|
|
153
|
+
const { apiKey, apiUrl, appBinaryId, appFile, async, env, excludeTags, flows, includeTags, ...rest } = flags;
|
|
142
154
|
const { firstFile, secondFile } = args;
|
|
143
155
|
let finalBinaryId = appBinaryId;
|
|
144
156
|
const finalAppFile = appFile ?? firstFile;
|
|
@@ -148,7 +160,11 @@ class Cloud extends core_1.Command {
|
|
|
148
160
|
throw new Error('You cannot provide both an appBinaryId and a binary file');
|
|
149
161
|
}
|
|
150
162
|
flowFile = flows ?? firstFile;
|
|
151
|
-
this.log(
|
|
163
|
+
// this.log(
|
|
164
|
+
// `you want to run the flow(s) ${flowFile} against the binary with id ${appBinaryId} with the following flags: ${JSON.stringify(
|
|
165
|
+
// flags,
|
|
166
|
+
// )}`,
|
|
167
|
+
// );
|
|
152
168
|
}
|
|
153
169
|
else {
|
|
154
170
|
if (!(flowFile && finalAppFile)) {
|
|
@@ -167,14 +183,12 @@ class Cloud extends core_1.Command {
|
|
|
167
183
|
const binaryBlob = new Blob([await (0, promises_1.readFile)(finalAppFile)], {
|
|
168
184
|
type: mimeTypeLookupByExtension[finalAppFile.split('.').pop()],
|
|
169
185
|
});
|
|
170
|
-
console.log(mimeTypeLookupByExtension[finalAppFile.split('.').pop()]);
|
|
171
186
|
binaryFormData.set('file', binaryBlob, finalAppFile);
|
|
172
187
|
const options = {
|
|
173
188
|
body: binaryFormData,
|
|
174
189
|
headers: { 'x-app-api-key': apiKey },
|
|
175
|
-
method: 'POST',
|
|
176
190
|
};
|
|
177
|
-
const { binaryId, message } = await
|
|
191
|
+
const { binaryId, message } = await typeSafePost(apiUrl, '/uploads/binary', options);
|
|
178
192
|
if (!binaryId)
|
|
179
193
|
throw new Error(message);
|
|
180
194
|
this.log(message);
|
|
@@ -192,7 +206,6 @@ class Cloud extends core_1.Command {
|
|
|
192
206
|
// todo: handle continueOnFailure and other sequence properties
|
|
193
207
|
testFileNames.push(file);
|
|
194
208
|
}
|
|
195
|
-
console.log(executionPlan);
|
|
196
209
|
}
|
|
197
210
|
catch (error) {
|
|
198
211
|
console.error(error);
|
|
@@ -228,10 +241,46 @@ class Cloud extends core_1.Command {
|
|
|
228
241
|
const options = {
|
|
229
242
|
body: testFormData,
|
|
230
243
|
headers: { 'x-app-api-key': apiKey },
|
|
231
|
-
method: 'POST',
|
|
232
244
|
};
|
|
233
|
-
const { message } = await
|
|
234
|
-
|
|
245
|
+
const { message, results } = await typeSafePost(apiUrl, '/uploads/flow', options);
|
|
246
|
+
if (!results?.length)
|
|
247
|
+
(0, errors_1.error)('No tests created: ' + message);
|
|
248
|
+
(0, cli_ux_1.info)(`\nCreated ${results.length} tests: ${results
|
|
249
|
+
.map((r) => r.test_file_name)
|
|
250
|
+
.join(', ')}\n`);
|
|
251
|
+
(0, cli_ux_1.info)('Run triggered, you can access the results at:');
|
|
252
|
+
(0, cli_ux_1.info)(`https://console.devicecloud.dev/results/${results[0].test_upload_id}/${results[0].id}/\n`);
|
|
253
|
+
if (!async) {
|
|
254
|
+
(0, cli_ux_1.info)('completed');
|
|
255
|
+
(0, cli_ux_1.exit)(0);
|
|
256
|
+
}
|
|
257
|
+
if (async) {
|
|
258
|
+
// poll for the run status every 5 seconds
|
|
259
|
+
core_1.ux.action.start('Waiting for results', 'Initializing', { stdout: true });
|
|
260
|
+
(0, cli_ux_1.info)(' ');
|
|
261
|
+
const intervalId = setInterval(async () => {
|
|
262
|
+
const { results: updatedResults } = await typeSafeGet(apiUrl, `/results/${results[0].test_upload_id}`, {
|
|
263
|
+
headers: { 'x-app-api-key': apiKey },
|
|
264
|
+
});
|
|
265
|
+
if (!updatedResults) {
|
|
266
|
+
clearInterval(intervalId);
|
|
267
|
+
(0, errors_1.error)('No results found');
|
|
268
|
+
}
|
|
269
|
+
core_1.ux.action.status = `\nStatus | Test
|
|
270
|
+
────────── ─────────── `;
|
|
271
|
+
for (const { status, test_file_name: test } of updatedResults) {
|
|
272
|
+
core_1.ux.action.status += `\n${status.padEnd(10, ' ')} | ${test}`;
|
|
273
|
+
}
|
|
274
|
+
if (updatedResults.every((result) => !['PENDING', 'RUNNING'].includes(result.status))) {
|
|
275
|
+
(0, cli_ux_1.info)('\nRun completed\n');
|
|
276
|
+
(0, cli_ux_1.table)(updatedResults, {
|
|
277
|
+
status: { get: (row) => row.status },
|
|
278
|
+
test: { get: (row) => row.test_file_name },
|
|
279
|
+
}, { printLine: this.log.bind(this) });
|
|
280
|
+
clearInterval(intervalId);
|
|
281
|
+
}
|
|
282
|
+
}, 5000);
|
|
283
|
+
}
|
|
235
284
|
}
|
|
236
285
|
}
|
|
237
286
|
exports.default = Cloud;
|
package/oclif.manifest.json
CHANGED
|
@@ -70,15 +70,21 @@
|
|
|
70
70
|
"aliases": [
|
|
71
71
|
"app-file"
|
|
72
72
|
],
|
|
73
|
-
"description": "App binary to run your
|
|
73
|
+
"description": "App binary to run your flows against",
|
|
74
74
|
"name": "appFile",
|
|
75
75
|
"hasDynamicHelp": false,
|
|
76
76
|
"multiple": false,
|
|
77
77
|
"type": "option"
|
|
78
78
|
},
|
|
79
|
+
"async": {
|
|
80
|
+
"description": "Wait for the results of the run",
|
|
81
|
+
"name": "async",
|
|
82
|
+
"allowNo": false,
|
|
83
|
+
"type": "boolean"
|
|
84
|
+
},
|
|
79
85
|
"env": {
|
|
80
86
|
"char": "e",
|
|
81
|
-
"description": "One or more environment variables to inject into your
|
|
87
|
+
"description": "One or more environment variables to inject into your flows",
|
|
82
88
|
"name": "env",
|
|
83
89
|
"hasDynamicHelp": false,
|
|
84
90
|
"multiple": true,
|
|
@@ -96,7 +102,7 @@
|
|
|
96
102
|
"type": "option"
|
|
97
103
|
},
|
|
98
104
|
"flows": {
|
|
99
|
-
"description": "The path to the flow file or folder containing your
|
|
105
|
+
"description": "The path to the flow file or folder containing your flows",
|
|
100
106
|
"name": "flows",
|
|
101
107
|
"hasDynamicHelp": false,
|
|
102
108
|
"multiple": false,
|
|
@@ -120,7 +126,7 @@
|
|
|
120
126
|
"aliases": [
|
|
121
127
|
"include-tags"
|
|
122
128
|
],
|
|
123
|
-
"description": "Only
|
|
129
|
+
"description": "Only flows which have these tags will be included in the run",
|
|
124
130
|
"name": "includeTags",
|
|
125
131
|
"default": [],
|
|
126
132
|
"hasDynamicHelp": false,
|
|
@@ -144,5 +150,5 @@
|
|
|
144
150
|
]
|
|
145
151
|
}
|
|
146
152
|
},
|
|
147
|
-
"version": "0.0.1-alpha.
|
|
153
|
+
"version": "0.0.1-alpha.6"
|
|
148
154
|
}
|
package/package.json
CHANGED