@devicecloud.dev/dcd 0.0.1-alpha.4 → 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 +3 -0
- package/dist/commands/cloud.js +78 -17
- package/dist/plan.js +1 -1
- package/oclif.manifest.json +31 -9
- package/package.json +1 -1
package/dist/commands/cloud.d.ts
CHANGED
|
@@ -12,9 +12,12 @@ 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>;
|
|
17
|
+
excludeTags: import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
16
18
|
flows: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
17
19
|
iOSVersion: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
20
|
+
includeTags: import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
18
21
|
};
|
|
19
22
|
run(): Promise<void>;
|
|
20
23
|
}
|
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,28 +114,43 @@ 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
|
-
aliases: ['env'],
|
|
112
124
|
char: 'e',
|
|
113
|
-
description: 'One or more environment variables to inject into your
|
|
125
|
+
description: 'One or more environment variables to inject into your flows',
|
|
126
|
+
multiple: true,
|
|
127
|
+
}),
|
|
128
|
+
excludeTags: core_1.Flags.string({
|
|
129
|
+
aliases: ['exclude-tags'],
|
|
130
|
+
default: [],
|
|
131
|
+
description: 'Flows which have these tags will be excluded from the run',
|
|
114
132
|
multiple: true,
|
|
133
|
+
parse: (input) => input.split(','),
|
|
115
134
|
}),
|
|
116
135
|
flows: core_1.Flags.string({
|
|
117
|
-
|
|
118
|
-
description: 'The path to the flow file or folder containing your Flows',
|
|
136
|
+
description: 'The path to the flow file or folder containing your flows',
|
|
119
137
|
}),
|
|
120
138
|
iOSVersion: core_1.Flags.string({
|
|
121
139
|
aliases: ['ios-version'],
|
|
122
140
|
description: 'iOS version to run your flow against',
|
|
123
141
|
options: ['16.4', '17.2'],
|
|
124
142
|
}),
|
|
143
|
+
includeTags: core_1.Flags.string({
|
|
144
|
+
aliases: ['include-tags'],
|
|
145
|
+
default: [],
|
|
146
|
+
description: 'Only flows which have these tags will be included in the run',
|
|
147
|
+
multiple: true,
|
|
148
|
+
parse: (input) => input.split(','),
|
|
149
|
+
}),
|
|
125
150
|
};
|
|
126
151
|
async run() {
|
|
127
152
|
const { args, flags } = await this.parse(Cloud);
|
|
128
|
-
const { apiKey, apiUrl, appBinaryId, appFile, env, flows, ...rest } = flags;
|
|
129
|
-
console.log({ args });
|
|
153
|
+
const { apiKey, apiUrl, appBinaryId, appFile, async, env, excludeTags, flows, includeTags, ...rest } = flags;
|
|
130
154
|
const { firstFile, secondFile } = args;
|
|
131
155
|
let finalBinaryId = appBinaryId;
|
|
132
156
|
const finalAppFile = appFile ?? firstFile;
|
|
@@ -136,7 +160,11 @@ class Cloud extends core_1.Command {
|
|
|
136
160
|
throw new Error('You cannot provide both an appBinaryId and a binary file');
|
|
137
161
|
}
|
|
138
162
|
flowFile = flows ?? firstFile;
|
|
139
|
-
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
|
+
// );
|
|
140
168
|
}
|
|
141
169
|
else {
|
|
142
170
|
if (!(flowFile && finalAppFile)) {
|
|
@@ -155,14 +183,12 @@ class Cloud extends core_1.Command {
|
|
|
155
183
|
const binaryBlob = new Blob([await (0, promises_1.readFile)(finalAppFile)], {
|
|
156
184
|
type: mimeTypeLookupByExtension[finalAppFile.split('.').pop()],
|
|
157
185
|
});
|
|
158
|
-
console.log(mimeTypeLookupByExtension[finalAppFile.split('.').pop()]);
|
|
159
186
|
binaryFormData.set('file', binaryBlob, finalAppFile);
|
|
160
187
|
const options = {
|
|
161
188
|
body: binaryFormData,
|
|
162
189
|
headers: { 'x-app-api-key': apiKey },
|
|
163
|
-
method: 'POST',
|
|
164
190
|
};
|
|
165
|
-
const { binaryId, message } = await
|
|
191
|
+
const { binaryId, message } = await typeSafePost(apiUrl, '/uploads/binary', options);
|
|
166
192
|
if (!binaryId)
|
|
167
193
|
throw new Error(message);
|
|
168
194
|
this.log(message);
|
|
@@ -172,7 +198,7 @@ class Cloud extends core_1.Command {
|
|
|
172
198
|
let flowFileDirectory = flowFile;
|
|
173
199
|
if (!flowFile?.endsWith('.yaml') && !flowFile?.endsWith('.yml')) {
|
|
174
200
|
try {
|
|
175
|
-
const executionPlan = await (0, plan_1.plan)(flowFile,
|
|
201
|
+
const executionPlan = await (0, plan_1.plan)(flowFile, includeTags.flat(), excludeTags.flat());
|
|
176
202
|
for (const file of executionPlan.flowsToRun) {
|
|
177
203
|
testFileNames.push(file);
|
|
178
204
|
}
|
|
@@ -180,7 +206,6 @@ class Cloud extends core_1.Command {
|
|
|
180
206
|
// todo: handle continueOnFailure and other sequence properties
|
|
181
207
|
testFileNames.push(file);
|
|
182
208
|
}
|
|
183
|
-
console.log(executionPlan);
|
|
184
209
|
}
|
|
185
210
|
catch (error) {
|
|
186
211
|
console.error(error);
|
|
@@ -216,10 +241,46 @@ class Cloud extends core_1.Command {
|
|
|
216
241
|
const options = {
|
|
217
242
|
body: testFormData,
|
|
218
243
|
headers: { 'x-app-api-key': apiKey },
|
|
219
|
-
method: 'POST',
|
|
220
244
|
};
|
|
221
|
-
const { message } = await
|
|
222
|
-
|
|
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
|
+
}
|
|
223
284
|
}
|
|
224
285
|
}
|
|
225
286
|
exports.default = Cloud;
|
package/dist/plan.js
CHANGED
|
@@ -39,7 +39,7 @@ const readConfigFromYamlFileAsJson = (filePath) => {
|
|
|
39
39
|
if (yamlText.includes('\n---\n')) {
|
|
40
40
|
const yamlTexts = yamlText.split('\n---\n');
|
|
41
41
|
const config = yaml.load(yamlTexts[0]);
|
|
42
|
-
if (Object.keys(config).
|
|
42
|
+
if (Object.keys(config).length > 0) {
|
|
43
43
|
return config;
|
|
44
44
|
}
|
|
45
45
|
}
|
package/oclif.manifest.json
CHANGED
|
@@ -70,28 +70,39 @@
|
|
|
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
|
-
"aliases": [
|
|
81
|
-
"env"
|
|
82
|
-
],
|
|
83
86
|
"char": "e",
|
|
84
|
-
"description": "One or more environment variables to inject into your
|
|
87
|
+
"description": "One or more environment variables to inject into your flows",
|
|
85
88
|
"name": "env",
|
|
86
89
|
"hasDynamicHelp": false,
|
|
87
90
|
"multiple": true,
|
|
88
91
|
"type": "option"
|
|
89
92
|
},
|
|
90
|
-
"
|
|
93
|
+
"excludeTags": {
|
|
91
94
|
"aliases": [
|
|
92
|
-
"
|
|
95
|
+
"exclude-tags"
|
|
93
96
|
],
|
|
94
|
-
"description": "
|
|
97
|
+
"description": "Flows which have these tags will be excluded from the run",
|
|
98
|
+
"name": "excludeTags",
|
|
99
|
+
"default": [],
|
|
100
|
+
"hasDynamicHelp": false,
|
|
101
|
+
"multiple": true,
|
|
102
|
+
"type": "option"
|
|
103
|
+
},
|
|
104
|
+
"flows": {
|
|
105
|
+
"description": "The path to the flow file or folder containing your flows",
|
|
95
106
|
"name": "flows",
|
|
96
107
|
"hasDynamicHelp": false,
|
|
97
108
|
"multiple": false,
|
|
@@ -110,6 +121,17 @@
|
|
|
110
121
|
"17.2"
|
|
111
122
|
],
|
|
112
123
|
"type": "option"
|
|
124
|
+
},
|
|
125
|
+
"includeTags": {
|
|
126
|
+
"aliases": [
|
|
127
|
+
"include-tags"
|
|
128
|
+
],
|
|
129
|
+
"description": "Only flows which have these tags will be included in the run",
|
|
130
|
+
"name": "includeTags",
|
|
131
|
+
"default": [],
|
|
132
|
+
"hasDynamicHelp": false,
|
|
133
|
+
"multiple": true,
|
|
134
|
+
"type": "option"
|
|
113
135
|
}
|
|
114
136
|
},
|
|
115
137
|
"hasDynamicHelp": false,
|
|
@@ -128,5 +150,5 @@
|
|
|
128
150
|
]
|
|
129
151
|
}
|
|
130
152
|
},
|
|
131
|
-
"version": "0.0.1-alpha.
|
|
153
|
+
"version": "0.0.1-alpha.6"
|
|
132
154
|
}
|
package/package.json
CHANGED