@devicecloud.dev/dcd 4.0.3 → 4.1.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 +15 -0
- package/dist/commands/cloud.js +79 -37
- package/dist/constants.d.ts +2 -0
- package/dist/constants.js +11 -2
- package/dist/gateways/api-gateway.d.ts +17 -1
- package/dist/gateways/api-gateway.js +128 -26
- package/dist/plan.d.ts +8 -0
- package/dist/types/device.types.d.ts +2 -1
- package/dist/types/device.types.js +1 -0
- package/dist/types/schema.types.d.ts +189 -79
- package/oclif.manifest.json +26 -3
- package/package.json +2 -2
package/dist/commands/cloud.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export default class Cloud extends Command {
|
|
|
19
19
|
'app-file': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
20
20
|
'artifacts-path': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
21
21
|
'junit-path': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
22
|
+
'allure-path': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
23
|
+
'html-path': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
22
24
|
async: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
23
25
|
config: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
24
26
|
debug: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
@@ -54,4 +56,17 @@ export default class Cloud extends Command {
|
|
|
54
56
|
};
|
|
55
57
|
private versionCheck;
|
|
56
58
|
run(): Promise<any>;
|
|
59
|
+
/**
|
|
60
|
+
* Handle downloading reports based on the report type specified
|
|
61
|
+
* @param reportType The type of report to download ('junit', 'allure', or 'html')
|
|
62
|
+
* @param apiUrl The base URL for the API server
|
|
63
|
+
* @param apiKey The API key for authentication
|
|
64
|
+
* @param uploadId The unique identifier for the test upload
|
|
65
|
+
* @param junitPath Optional file path where the JUnit report should be saved
|
|
66
|
+
* @param allurePath Optional file path where the Allure report should be saved
|
|
67
|
+
* @param htmlPath Optional file path where the HTML report should be saved
|
|
68
|
+
* @param debug Whether debug logging is enabled
|
|
69
|
+
* @returns Promise that resolves when all reports have been downloaded
|
|
70
|
+
*/
|
|
71
|
+
private handleReportDownloads;
|
|
57
72
|
}
|
package/dist/commands/cloud.js
CHANGED
|
@@ -5,15 +5,16 @@ exports.mimeTypeLookupByExtension = void 0;
|
|
|
5
5
|
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
|
+
const node_child_process_1 = require("node:child_process");
|
|
8
9
|
const fs = require("node:fs");
|
|
9
10
|
const os = require("node:os");
|
|
10
11
|
const path = require("node:path");
|
|
11
|
-
const streamZip = require("node-stream-zip");
|
|
12
12
|
const constants_1 = require("../constants");
|
|
13
13
|
const api_gateway_1 = require("../gateways/api-gateway");
|
|
14
14
|
const methods_1 = require("../methods");
|
|
15
15
|
const plan_1 = require("../plan");
|
|
16
16
|
const compatibility_1 = require("../utils/compatibility");
|
|
17
|
+
const StreamZip = require("node-stream-zip");
|
|
17
18
|
exports.mimeTypeLookupByExtension = {
|
|
18
19
|
apk: 'application/vnd.android.package-archive',
|
|
19
20
|
yaml: 'application/x-yaml',
|
|
@@ -45,16 +46,22 @@ class Cloud extends core_1.Command {
|
|
|
45
46
|
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
46
47
|
static flags = constants_1.flags;
|
|
47
48
|
versionCheck = async () => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
try {
|
|
50
|
+
const latestVersion = (0, node_child_process_1.execSync)('npm view @devicecloud.dev/dcd version', {
|
|
51
|
+
encoding: 'utf8',
|
|
52
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
53
|
+
}).trim();
|
|
54
|
+
if (latestVersion !== this.config.version) {
|
|
55
|
+
this.log(`
|
|
53
56
|
-------------------
|
|
54
57
|
A new version of the devicecloud.dev CLI is available: ${latestVersion}
|
|
55
58
|
Run 'npm install -g @devicecloud.dev/dcd@latest' to update to the latest version
|
|
56
59
|
-------------------
|
|
57
60
|
`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// Silently fail if npm view command fails (e.g., no network connection)
|
|
58
65
|
}
|
|
59
66
|
};
|
|
60
67
|
async run() {
|
|
@@ -64,7 +71,7 @@ class Cloud extends core_1.Command {
|
|
|
64
71
|
let jsonFile = false;
|
|
65
72
|
try {
|
|
66
73
|
const { args, flags, raw } = await this.parse(Cloud);
|
|
67
|
-
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, 'junit-path': junitPath, async, config: configFile, debug, 'device-locale': deviceLocale, 'download-artifacts': downloadArtifacts, 'dry-run': dryRun, env, 'exclude-flows': excludeFlows, 'exclude-tags': excludeTags, flows, 'google-play': googlePlay, 'ignore-sha-check': ignoreShaCheck, 'include-tags': includeTags, 'ios-device': iOSDevice, 'ios-version': iOSVersion, json, 'json-file-name': jsonFileName, 'maestro-version': maestroVersion, metadata, mitmHost, mitmPath, 'moropo-v1-api-key': moropoApiKey, name, orientation, quiet, report, retry, 'runner-type': runnerType, 'x86-arch': x86Arch, ...rest } = flags;
|
|
74
|
+
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, 'junit-path': junitPath, 'allure-path': allurePath, 'html-path': htmlPath, async, config: configFile, debug, 'device-locale': deviceLocale, 'download-artifacts': downloadArtifacts, 'dry-run': dryRun, env, 'exclude-flows': excludeFlows, 'exclude-tags': excludeTags, flows, 'google-play': googlePlay, 'ignore-sha-check': ignoreShaCheck, 'include-tags': includeTags, 'ios-device': iOSDevice, 'ios-version': iOSVersion, json, 'json-file-name': jsonFileName, 'maestro-version': maestroVersion, metadata, mitmHost, mitmPath, 'moropo-v1-api-key': moropoApiKey, name, orientation, quiet, report, retry, 'runner-type': runnerType, 'x86-arch': x86Arch, ...rest } = flags;
|
|
68
75
|
// Resolve "latest" maestro version to actual version
|
|
69
76
|
const resolvedMaestroVersion = (0, constants_1.resolveMaestroVersion)(maestroVersion);
|
|
70
77
|
// Store debug flag for use in catch block
|
|
@@ -163,7 +170,6 @@ class Cloud extends core_1.Command {
|
|
|
163
170
|
core_1.ux.action.status = 'Extracting tests...';
|
|
164
171
|
}
|
|
165
172
|
// Extract zip file
|
|
166
|
-
const StreamZip = streamZip;
|
|
167
173
|
// eslint-disable-next-line new-cap
|
|
168
174
|
const zip = new StreamZip.async({ file: zipPath });
|
|
169
175
|
await zip.extract(null, moropoDir);
|
|
@@ -215,7 +221,6 @@ class Cloud extends core_1.Command {
|
|
|
215
221
|
}
|
|
216
222
|
if (debug) {
|
|
217
223
|
this.log(`DEBUG: API URL: ${apiUrl}`);
|
|
218
|
-
this.log(`DEBUG: API Key provided: ${apiKey ? 'Yes' : 'No'}`);
|
|
219
224
|
}
|
|
220
225
|
if (retry && retry > 2) {
|
|
221
226
|
this.log("Retries are now free of charge but limited to 2. If you're test is still failing after 2 retries, please ask for help on Discord.");
|
|
@@ -368,8 +373,9 @@ class Cloud extends core_1.Command {
|
|
|
368
373
|
}
|
|
369
374
|
await (0, methods_1.verifyAdditionalAppFiles)(additionalAppFiles);
|
|
370
375
|
const flagLogs = [];
|
|
376
|
+
const sensitiveFlags = new Set(['api-key', 'apiKey', 'moropo-v1-api-key']);
|
|
371
377
|
for (const [k, v] of Object.entries(flags)) {
|
|
372
|
-
if (v && v.toString().length > 0) {
|
|
378
|
+
if (v && v.toString().length > 0 && !sensitiveFlags.has(k)) {
|
|
373
379
|
flagLogs.push(`${k}: ${v}`);
|
|
374
380
|
}
|
|
375
381
|
}
|
|
@@ -684,33 +690,9 @@ class Cloud extends core_1.Command {
|
|
|
684
690
|
this.warn('Failed to download artifacts');
|
|
685
691
|
}
|
|
686
692
|
}
|
|
687
|
-
// Handle report
|
|
688
|
-
if (report
|
|
689
|
-
|
|
690
|
-
if (debug) {
|
|
691
|
-
this.log('DEBUG: Downloading JUNIT report');
|
|
692
|
-
}
|
|
693
|
-
const reportPath = path.resolve(process.cwd(), junitPath || 'report.xml');
|
|
694
|
-
await api_gateway_1.ApiGateway.downloadReport(apiUrl, apiKey, results[0].test_upload_id, reportPath);
|
|
695
|
-
this.log('\n');
|
|
696
|
-
this.log(`JUNIT test report has been downloaded to ${reportPath}`);
|
|
697
|
-
}
|
|
698
|
-
catch (error) {
|
|
699
|
-
if (debug) {
|
|
700
|
-
this.log(`DEBUG: Error downloading JUNIT report: ${error}`);
|
|
701
|
-
}
|
|
702
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
703
|
-
this.warn(`Failed to download JUNIT report: ${errorMessage}`);
|
|
704
|
-
if (errorMessage.includes('404')) {
|
|
705
|
-
this.warn('No JUNIT reports found for this upload. Make sure your tests were run with --report junit flag.');
|
|
706
|
-
}
|
|
707
|
-
else if (errorMessage.includes('EACCES') || errorMessage.includes('EPERM')) {
|
|
708
|
-
this.warn('Permission denied. Check write permissions for the current directory.');
|
|
709
|
-
}
|
|
710
|
-
else if (errorMessage.includes('ENOENT')) {
|
|
711
|
-
this.warn('Directory does not exist. Make sure you have write access to the current directory.');
|
|
712
|
-
}
|
|
713
|
-
}
|
|
693
|
+
// Handle report downloads based on --report flag
|
|
694
|
+
if (report && ['allure', 'html', 'junit'].includes(report)) {
|
|
695
|
+
await this.handleReportDownloads(report, apiUrl, apiKey, results[0].test_upload_id, junitPath, allurePath, htmlPath, debug);
|
|
714
696
|
}
|
|
715
697
|
const resultsWithoutEarlierTries = updatedResults.filter((result) => {
|
|
716
698
|
const originalTryId = result.retry_of || result.id;
|
|
@@ -811,5 +793,65 @@ class Cloud extends core_1.Command {
|
|
|
811
793
|
}
|
|
812
794
|
}
|
|
813
795
|
}
|
|
796
|
+
/**
|
|
797
|
+
* Handle downloading reports based on the report type specified
|
|
798
|
+
* @param reportType The type of report to download ('junit', 'allure', or 'html')
|
|
799
|
+
* @param apiUrl The base URL for the API server
|
|
800
|
+
* @param apiKey The API key for authentication
|
|
801
|
+
* @param uploadId The unique identifier for the test upload
|
|
802
|
+
* @param junitPath Optional file path where the JUnit report should be saved
|
|
803
|
+
* @param allurePath Optional file path where the Allure report should be saved
|
|
804
|
+
* @param htmlPath Optional file path where the HTML report should be saved
|
|
805
|
+
* @param debug Whether debug logging is enabled
|
|
806
|
+
* @returns Promise that resolves when all reports have been downloaded
|
|
807
|
+
*/
|
|
808
|
+
// eslint-disable-next-line max-params
|
|
809
|
+
async handleReportDownloads(reportType, apiUrl, apiKey, uploadId, junitPath, allurePath, htmlPath, debug) {
|
|
810
|
+
const downloadReport = async (type, filePath) => {
|
|
811
|
+
try {
|
|
812
|
+
if (debug) {
|
|
813
|
+
this.log(`DEBUG: Downloading ${type.toUpperCase()} report`);
|
|
814
|
+
}
|
|
815
|
+
await api_gateway_1.ApiGateway.downloadReportGeneric(apiUrl, apiKey, uploadId, type, filePath);
|
|
816
|
+
this.log(`${type.toUpperCase()} test report has been downloaded to ${filePath}`);
|
|
817
|
+
}
|
|
818
|
+
catch (error) {
|
|
819
|
+
if (debug) {
|
|
820
|
+
this.log(`DEBUG: Error downloading ${type.toUpperCase()} report: ${error}`);
|
|
821
|
+
}
|
|
822
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
823
|
+
this.warn(`Failed to download ${type.toUpperCase()} report: ${errorMessage}`);
|
|
824
|
+
if (errorMessage.includes('404')) {
|
|
825
|
+
this.warn(`No ${type.toUpperCase()} reports found for this upload. Make sure your tests generated results.`);
|
|
826
|
+
}
|
|
827
|
+
else if (errorMessage.includes('EACCES') || errorMessage.includes('EPERM')) {
|
|
828
|
+
this.warn('Permission denied. Check write permissions for the current directory.');
|
|
829
|
+
}
|
|
830
|
+
else if (errorMessage.includes('ENOENT')) {
|
|
831
|
+
this.warn('Directory does not exist. Make sure you have write access to the current directory.');
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
};
|
|
835
|
+
switch (reportType) {
|
|
836
|
+
case 'junit': {
|
|
837
|
+
const reportPath = path.resolve(process.cwd(), junitPath || 'report.xml');
|
|
838
|
+
await downloadReport('junit', reportPath);
|
|
839
|
+
break;
|
|
840
|
+
}
|
|
841
|
+
case 'allure': {
|
|
842
|
+
const reportPath = path.resolve(process.cwd(), allurePath || 'report.html');
|
|
843
|
+
await downloadReport('allure', reportPath);
|
|
844
|
+
break;
|
|
845
|
+
}
|
|
846
|
+
case 'html': {
|
|
847
|
+
const htmlReportPath = path.resolve(process.cwd(), htmlPath || 'report.html');
|
|
848
|
+
await downloadReport('html', htmlReportPath);
|
|
849
|
+
break;
|
|
850
|
+
}
|
|
851
|
+
default: {
|
|
852
|
+
this.warn(`Unknown report type: ${reportType}`);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
814
856
|
}
|
|
815
857
|
exports.default = Cloud;
|
package/dist/constants.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export declare const flags: {
|
|
|
13
13
|
'app-file': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
14
14
|
'artifacts-path': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
15
15
|
'junit-path': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
16
|
+
'allure-path': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
17
|
+
'html-path': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
16
18
|
async: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
17
19
|
config: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
18
20
|
debug: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
package/dist/constants.js
CHANGED
|
@@ -14,6 +14,7 @@ exports.SUPPORTED_MAESTRO_VERSIONS = [
|
|
|
14
14
|
'1.41.0',
|
|
15
15
|
'2.0.2',
|
|
16
16
|
'2.0.3',
|
|
17
|
+
'2.0.4',
|
|
17
18
|
];
|
|
18
19
|
exports.DEFAULT_MAESTRO_VERSION = '1.41.0';
|
|
19
20
|
const getLatestMaestroVersion = () => exports.SUPPORTED_MAESTRO_VERSIONS.at(-1);
|
|
@@ -74,6 +75,14 @@ exports.flags = {
|
|
|
74
75
|
dependsOn: ['report'],
|
|
75
76
|
description: 'Custom file path for downloaded JUnit report (default: ./report.xml)',
|
|
76
77
|
}),
|
|
78
|
+
'allure-path': core_1.Flags.string({
|
|
79
|
+
dependsOn: ['report'],
|
|
80
|
+
description: 'Custom file path for downloaded Allure report (default: ./report.html)',
|
|
81
|
+
}),
|
|
82
|
+
'html-path': core_1.Flags.string({
|
|
83
|
+
dependsOn: ['report'],
|
|
84
|
+
description: 'Custom file path for downloaded HTML report (default: ./report.html)',
|
|
85
|
+
}),
|
|
77
86
|
async: core_1.Flags.boolean({
|
|
78
87
|
description: 'Immediately return (exit code 0) from the command without waiting for the results of the run (useful for saving CI minutes)',
|
|
79
88
|
}),
|
|
@@ -191,8 +200,8 @@ exports.flags = {
|
|
|
191
200
|
}),
|
|
192
201
|
report: core_1.Flags.string({
|
|
193
202
|
aliases: ['format'],
|
|
194
|
-
description: '
|
|
195
|
-
options: ['junit', 'html'],
|
|
203
|
+
description: 'Generate and download test reports in the specified format. Use "allure" for a complete HTML report.',
|
|
204
|
+
options: ['allure', 'junit', 'html'],
|
|
196
205
|
}),
|
|
197
206
|
retry: core_1.Flags.integer({
|
|
198
207
|
description: 'Automatically retry the run up to the number of times specified (same as pressing retry in the UI) - this is free of charge',
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { TAppMetadata } from '../types';
|
|
2
2
|
export declare const ApiGateway: {
|
|
3
|
+
/**
|
|
4
|
+
* Standardized error handling for API responses
|
|
5
|
+
* @param res - The fetch response object
|
|
6
|
+
* @param operation - Description of the operation that failed
|
|
7
|
+
* @returns Never returns, always throws
|
|
8
|
+
*/
|
|
9
|
+
handleApiError(res: Response, operation: string): Promise<never>;
|
|
3
10
|
checkForExistingUpload(baseUrl: string, apiKey: string, sha: string): Promise<{
|
|
4
11
|
appBinaryId: string;
|
|
5
12
|
exists: boolean;
|
|
6
13
|
}>;
|
|
7
|
-
downloadReport(baseUrl: string, apiKey: string, uploadId: string, reportPath?: string): Promise<void>;
|
|
8
14
|
downloadArtifactsZip(baseUrl: string, apiKey: string, uploadId: string, results: "ALL" | "FAILED", artifactsPath?: string): Promise<void>;
|
|
9
15
|
finaliseUpload(baseUrl: string, apiKey: string, id: string, metadata: TAppMetadata, path: string, sha: string): Promise<Record<string, never>>;
|
|
10
16
|
getBinaryUploadUrl(baseUrl: string, apiKey: string, platform: "android" | "ios"): Promise<{
|
|
@@ -33,4 +39,14 @@ export declare const ApiGateway: {
|
|
|
33
39
|
message?: string;
|
|
34
40
|
results?: import("../types/schema.types").components["schemas"]["IDBResult"][];
|
|
35
41
|
}>;
|
|
42
|
+
/**
|
|
43
|
+
* Generic report download method that handles both junit and allure reports
|
|
44
|
+
* @param baseUrl - API base URL
|
|
45
|
+
* @param apiKey - API key for authentication
|
|
46
|
+
* @param uploadId - Upload ID to download report for
|
|
47
|
+
* @param reportType - Type of report to download ('junit' or 'allure')
|
|
48
|
+
* @param reportPath - Optional custom path for the downloaded report
|
|
49
|
+
* @returns Promise that resolves when download is complete
|
|
50
|
+
*/
|
|
51
|
+
downloadReportGeneric(baseUrl: string, apiKey: string, uploadId: string, reportType: "allure" | "html" | "junit", reportPath?: string): Promise<void>;
|
|
36
52
|
};
|
|
@@ -1,9 +1,50 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ApiGateway = void 0;
|
|
4
|
-
const fs = require("node:fs/promises");
|
|
5
4
|
const path = require("node:path");
|
|
6
5
|
exports.ApiGateway = {
|
|
6
|
+
/**
|
|
7
|
+
* Standardized error handling for API responses
|
|
8
|
+
* @param res - The fetch response object
|
|
9
|
+
* @param operation - Description of the operation that failed
|
|
10
|
+
* @returns Never returns, always throws
|
|
11
|
+
*/
|
|
12
|
+
async handleApiError(res, operation) {
|
|
13
|
+
const errorText = await res.text();
|
|
14
|
+
let userMessage;
|
|
15
|
+
// Parse common API error formats
|
|
16
|
+
try {
|
|
17
|
+
const errorData = JSON.parse(errorText);
|
|
18
|
+
userMessage = errorData.message || errorData.error || errorText;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
userMessage = errorText;
|
|
22
|
+
}
|
|
23
|
+
// Add context and improve readability
|
|
24
|
+
switch (res.status) {
|
|
25
|
+
case 400: {
|
|
26
|
+
throw new Error(`Invalid request: ${userMessage}`);
|
|
27
|
+
}
|
|
28
|
+
case 401: {
|
|
29
|
+
throw new Error(`Authentication failed. Please check your API key.`);
|
|
30
|
+
}
|
|
31
|
+
case 403: {
|
|
32
|
+
throw new Error(`Access denied. ${userMessage}`);
|
|
33
|
+
}
|
|
34
|
+
case 404: {
|
|
35
|
+
throw new Error(`Resource not found. ${userMessage}`);
|
|
36
|
+
}
|
|
37
|
+
case 429: {
|
|
38
|
+
throw new Error(`Rate limit exceeded. Please try again later.`);
|
|
39
|
+
}
|
|
40
|
+
case 500: {
|
|
41
|
+
throw new Error(`Server error occurred. Please try again or contact support.`);
|
|
42
|
+
}
|
|
43
|
+
default: {
|
|
44
|
+
throw new Error(`${operation} failed: ${userMessage} (HTTP ${res.status})`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
},
|
|
7
48
|
async checkForExistingUpload(baseUrl, apiKey, sha) {
|
|
8
49
|
const res = await fetch(`${baseUrl}/uploads/checkForExistingUpload`, {
|
|
9
50
|
body: JSON.stringify({ sha }),
|
|
@@ -15,25 +56,6 @@ exports.ApiGateway = {
|
|
|
15
56
|
});
|
|
16
57
|
return res.json();
|
|
17
58
|
},
|
|
18
|
-
async downloadReport(baseUrl, apiKey, uploadId, reportPath) {
|
|
19
|
-
const finalReportPath = reportPath || path.resolve(process.cwd(), `report-${uploadId}.xml`);
|
|
20
|
-
const url = `${baseUrl}/results/${uploadId}/report`;
|
|
21
|
-
const res = await fetch(url, {
|
|
22
|
-
headers: {
|
|
23
|
-
'x-app-api-key': apiKey,
|
|
24
|
-
},
|
|
25
|
-
method: 'GET',
|
|
26
|
-
});
|
|
27
|
-
if (!res.ok) {
|
|
28
|
-
const errorText = await res.text();
|
|
29
|
-
if (res.status === 404) {
|
|
30
|
-
throw new Error(`Upload ID '${uploadId}' not found or no results available for this upload`);
|
|
31
|
-
}
|
|
32
|
-
throw new Error(`Failed to download report: ${res.status} ${errorText}`);
|
|
33
|
-
}
|
|
34
|
-
const buffer = await res.arrayBuffer();
|
|
35
|
-
await fs.writeFile(finalReportPath, Buffer.from(buffer));
|
|
36
|
-
},
|
|
37
59
|
async downloadArtifactsZip(baseUrl, apiKey, uploadId, results, artifactsPath = './artifacts.zip') {
|
|
38
60
|
const res = await fetch(`${baseUrl}/results/${uploadId}/download`, {
|
|
39
61
|
body: JSON.stringify({ results }),
|
|
@@ -44,7 +66,7 @@ exports.ApiGateway = {
|
|
|
44
66
|
method: 'POST',
|
|
45
67
|
});
|
|
46
68
|
if (!res.ok) {
|
|
47
|
-
|
|
69
|
+
await this.handleApiError(res, 'Failed to download artifacts');
|
|
48
70
|
}
|
|
49
71
|
// Handle tilde expansion for home directory
|
|
50
72
|
if (artifactsPath.startsWith('~/') || artifactsPath === '~') {
|
|
@@ -87,7 +109,7 @@ exports.ApiGateway = {
|
|
|
87
109
|
method: 'POST',
|
|
88
110
|
});
|
|
89
111
|
if (!res.ok) {
|
|
90
|
-
|
|
112
|
+
await this.handleApiError(res, 'Failed to finalize upload');
|
|
91
113
|
}
|
|
92
114
|
return res.json();
|
|
93
115
|
},
|
|
@@ -101,7 +123,7 @@ exports.ApiGateway = {
|
|
|
101
123
|
method: 'POST',
|
|
102
124
|
});
|
|
103
125
|
if (!res.ok) {
|
|
104
|
-
|
|
126
|
+
await this.handleApiError(res, 'Failed to get upload URL');
|
|
105
127
|
}
|
|
106
128
|
return res.json();
|
|
107
129
|
},
|
|
@@ -111,7 +133,7 @@ exports.ApiGateway = {
|
|
|
111
133
|
headers: { 'x-app-api-key': apiKey },
|
|
112
134
|
});
|
|
113
135
|
if (!res.ok) {
|
|
114
|
-
|
|
136
|
+
await this.handleApiError(res, 'Failed to get results');
|
|
115
137
|
}
|
|
116
138
|
return res.json();
|
|
117
139
|
},
|
|
@@ -129,7 +151,7 @@ exports.ApiGateway = {
|
|
|
129
151
|
},
|
|
130
152
|
});
|
|
131
153
|
if (!response.ok) {
|
|
132
|
-
|
|
154
|
+
await this.handleApiError(response, 'Failed to get upload status');
|
|
133
155
|
}
|
|
134
156
|
return response.json();
|
|
135
157
|
},
|
|
@@ -142,8 +164,88 @@ exports.ApiGateway = {
|
|
|
142
164
|
method: 'POST',
|
|
143
165
|
});
|
|
144
166
|
if (!res.ok) {
|
|
145
|
-
|
|
167
|
+
await this.handleApiError(res, 'Failed to upload test flows');
|
|
146
168
|
}
|
|
147
169
|
return res.json();
|
|
148
170
|
},
|
|
171
|
+
/**
|
|
172
|
+
* Generic report download method that handles both junit and allure reports
|
|
173
|
+
* @param baseUrl - API base URL
|
|
174
|
+
* @param apiKey - API key for authentication
|
|
175
|
+
* @param uploadId - Upload ID to download report for
|
|
176
|
+
* @param reportType - Type of report to download ('junit' or 'allure')
|
|
177
|
+
* @param reportPath - Optional custom path for the downloaded report
|
|
178
|
+
* @returns Promise that resolves when download is complete
|
|
179
|
+
*/
|
|
180
|
+
async downloadReportGeneric(baseUrl, apiKey, uploadId, reportType, reportPath) {
|
|
181
|
+
// Define endpoint and default filename mappings
|
|
182
|
+
const config = {
|
|
183
|
+
junit: {
|
|
184
|
+
endpoint: `/results/${uploadId}/report`,
|
|
185
|
+
defaultFilename: `report-${uploadId}.xml`,
|
|
186
|
+
notFoundMessage: `Upload ID '${uploadId}' not found or no results available for this upload`,
|
|
187
|
+
errorPrefix: 'Failed to download report',
|
|
188
|
+
},
|
|
189
|
+
allure: {
|
|
190
|
+
endpoint: `/allure/${uploadId}/download`,
|
|
191
|
+
defaultFilename: `report-${uploadId}.html`,
|
|
192
|
+
notFoundMessage: `Upload ID '${uploadId}' not found or no Allure report available for this upload`,
|
|
193
|
+
errorPrefix: 'Failed to download Allure report',
|
|
194
|
+
},
|
|
195
|
+
html: {
|
|
196
|
+
endpoint: `/results/${uploadId}/html-report`,
|
|
197
|
+
defaultFilename: `report-${uploadId}.html`,
|
|
198
|
+
notFoundMessage: `Upload ID '${uploadId}' not found or no HTML report available for this upload`,
|
|
199
|
+
errorPrefix: 'Failed to download HTML report',
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
const { endpoint, defaultFilename, notFoundMessage, errorPrefix } = config[reportType];
|
|
203
|
+
const finalReportPath = reportPath || path.resolve(process.cwd(), defaultFilename);
|
|
204
|
+
const url = `${baseUrl}${endpoint}`;
|
|
205
|
+
// Make the download request
|
|
206
|
+
const res = await fetch(url, {
|
|
207
|
+
headers: {
|
|
208
|
+
'x-app-api-key': apiKey,
|
|
209
|
+
},
|
|
210
|
+
method: 'GET',
|
|
211
|
+
});
|
|
212
|
+
if (!res.ok) {
|
|
213
|
+
const errorText = await res.text();
|
|
214
|
+
if (res.status === 404) {
|
|
215
|
+
throw new Error(notFoundMessage);
|
|
216
|
+
}
|
|
217
|
+
throw new Error(`${errorPrefix}: ${res.status} ${errorText}`);
|
|
218
|
+
}
|
|
219
|
+
// Handle tilde expansion for home directory (applies to all report types)
|
|
220
|
+
let expandedPath = finalReportPath;
|
|
221
|
+
if (finalReportPath.startsWith('~/') || finalReportPath === '~') {
|
|
222
|
+
expandedPath = finalReportPath.replace(/^~/,
|
|
223
|
+
// eslint-disable-next-line unicorn/prefer-module
|
|
224
|
+
require('node:os').homedir());
|
|
225
|
+
}
|
|
226
|
+
// Create directory structure if it doesn't exist
|
|
227
|
+
// eslint-disable-next-line unicorn/prefer-module
|
|
228
|
+
const { dirname } = require('node:path');
|
|
229
|
+
// eslint-disable-next-line unicorn/prefer-module
|
|
230
|
+
const { createWriteStream, mkdirSync } = require('node:fs');
|
|
231
|
+
// eslint-disable-next-line unicorn/prefer-module
|
|
232
|
+
const { finished } = require('node:stream/promises');
|
|
233
|
+
// eslint-disable-next-line unicorn/prefer-module
|
|
234
|
+
const { Readable } = require('node:stream');
|
|
235
|
+
const directory = dirname(expandedPath);
|
|
236
|
+
if (directory !== '.') {
|
|
237
|
+
try {
|
|
238
|
+
mkdirSync(directory, { recursive: true });
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
// Ignore EEXIST errors (directory already exists)
|
|
242
|
+
if (error.code !== 'EEXIST') {
|
|
243
|
+
throw error;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// Write the file using streaming for better memory efficiency
|
|
248
|
+
const fileStream = createWriteStream(expandedPath, { flags: 'wx' });
|
|
249
|
+
await finished(Readable.fromWeb(res.body).pipe(fileStream));
|
|
250
|
+
},
|
|
149
251
|
};
|
package/dist/plan.d.ts
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
|
+
interface INotificationsConfig {
|
|
2
|
+
email?: {
|
|
3
|
+
enabled?: boolean;
|
|
4
|
+
onSuccess?: boolean;
|
|
5
|
+
recipients?: string[];
|
|
6
|
+
};
|
|
7
|
+
}
|
|
1
8
|
interface IWorkspaceConfig {
|
|
2
9
|
excludeTags?: null | string[];
|
|
3
10
|
executionOrder?: IExecutionOrder | null;
|
|
4
11
|
flows?: null | string[];
|
|
5
12
|
includeTags?: null | string[];
|
|
6
13
|
local?: ILocal | null;
|
|
14
|
+
notifications?: INotificationsConfig;
|
|
7
15
|
}
|
|
8
16
|
interface ILocal {
|
|
9
17
|
deterministicOrder: boolean | null;
|
|
@@ -30,6 +30,7 @@ var EiOSVersions;
|
|
|
30
30
|
EiOSVersions["eighteen"] = "18";
|
|
31
31
|
EiOSVersions["seventeen"] = "17";
|
|
32
32
|
EiOSVersions["sixteen"] = "16";
|
|
33
|
+
EiOSVersions["twentySix"] = "26";
|
|
33
34
|
})(EiOSVersions || (exports.EiOSVersions = EiOSVersions = {}));
|
|
34
35
|
var EAndroidApiLevels;
|
|
35
36
|
(function (EAndroidApiLevels) {
|
|
@@ -3,9 +3,6 @@
|
|
|
3
3
|
* Do not make direct changes to the file.
|
|
4
4
|
*/
|
|
5
5
|
export interface paths {
|
|
6
|
-
"/admin/cleanupOldUploads": {
|
|
7
|
-
post: operations["AdminController_cleanupOldUploads"];
|
|
8
|
-
};
|
|
9
6
|
"/uploads/binary": {
|
|
10
7
|
post: operations["UploadsController_createBinary"];
|
|
11
8
|
};
|
|
@@ -39,15 +36,36 @@ export interface paths {
|
|
|
39
36
|
"/results/{uploadId}/download": {
|
|
40
37
|
post: operations["ResultsController_getTestRunArtifacts"];
|
|
41
38
|
};
|
|
42
|
-
"/results": {
|
|
43
|
-
post: operations["ResultsController_createResult"];
|
|
44
|
-
};
|
|
45
39
|
"/results/notify/{uploadId}": {
|
|
46
40
|
post: operations["ResultsController_notifyTestRunComplete"];
|
|
47
41
|
};
|
|
42
|
+
"/results/{uploadId}/report": {
|
|
43
|
+
get: operations["ResultsController_downloadReport"];
|
|
44
|
+
};
|
|
45
|
+
"/results/{uploadId}/html-report": {
|
|
46
|
+
get: operations["ResultsController_downloadHtmlReport"];
|
|
47
|
+
};
|
|
48
48
|
"/results/compatibility/data": {
|
|
49
49
|
get: operations["ResultsController_getCompatibilityData"];
|
|
50
50
|
};
|
|
51
|
+
"/allure/{uploadId}/download": {
|
|
52
|
+
/**
|
|
53
|
+
* Download Allure report as HTML
|
|
54
|
+
* @description Downloads a single-file Allure report as HTML containing all test results. Report is generated once and stored in Supabase Storage for subsequent downloads.
|
|
55
|
+
*/
|
|
56
|
+
get: operations["AllureController_downloadAllureReport"];
|
|
57
|
+
};
|
|
58
|
+
"/webhooks": {
|
|
59
|
+
get: operations["WebhooksController_getWebhook"];
|
|
60
|
+
post: operations["WebhooksController_setWebhook"];
|
|
61
|
+
delete: operations["WebhooksController_deleteWebhook"];
|
|
62
|
+
};
|
|
63
|
+
"/webhooks/regenerate-secret": {
|
|
64
|
+
post: operations["WebhooksController_regenerateWebhookSecret"];
|
|
65
|
+
};
|
|
66
|
+
"/webhooks/test": {
|
|
67
|
+
post: operations["WebhooksController_testWebhook"];
|
|
68
|
+
};
|
|
51
69
|
"/org/increase_credits": {
|
|
52
70
|
post: operations["OrgController_paddleTransactionCompleted"];
|
|
53
71
|
};
|
|
@@ -60,12 +78,6 @@ export interface paths {
|
|
|
60
78
|
"/org/accept-invite": {
|
|
61
79
|
post: operations["OrgController_acceptInvite"];
|
|
62
80
|
};
|
|
63
|
-
"/public/stats": {
|
|
64
|
-
get: operations["StatsController_getPublicStats"];
|
|
65
|
-
};
|
|
66
|
-
"/moropo/run-scheduled-jobs": {
|
|
67
|
-
get: operations["MoropoController_runScheduledJobs"];
|
|
68
|
-
};
|
|
69
81
|
"/frontend/check-domain-saml": {
|
|
70
82
|
post: operations["FrontendController_checkDomainSaml"];
|
|
71
83
|
};
|
|
@@ -137,7 +149,7 @@ export interface components {
|
|
|
137
149
|
apiUrl?: string;
|
|
138
150
|
appFile?: string;
|
|
139
151
|
/** @enum {string} */
|
|
140
|
-
iOSVersion?: "16" | "17" | "18";
|
|
152
|
+
iOSVersion?: "16" | "17" | "18" | "26";
|
|
141
153
|
/** @enum {string} */
|
|
142
154
|
iOSDevice?: "iphone-14" | "iphone-14-pro" | "iphone-15" | "iphone-15-pro" | "iphone-16" | "iphone-16-plus" | "iphone-16-pro" | "iphone-16-pro-max" | "ipad-pro-6th-gen";
|
|
143
155
|
platform?: string;
|
|
@@ -182,32 +194,6 @@ export interface components {
|
|
|
182
194
|
export type $defs = Record<string, never>;
|
|
183
195
|
export type external = Record<string, never>;
|
|
184
196
|
export interface operations {
|
|
185
|
-
AdminController_cleanupOldUploads: {
|
|
186
|
-
parameters: {
|
|
187
|
-
query?: {
|
|
188
|
-
/** @description If true, shows what would be deleted without actually deleting */
|
|
189
|
-
dryRun?: boolean;
|
|
190
|
-
};
|
|
191
|
-
};
|
|
192
|
-
responses: {
|
|
193
|
-
/** @description Cleanup of old uploads has been triggered. */
|
|
194
|
-
201: {
|
|
195
|
-
content: {
|
|
196
|
-
"application/json": {
|
|
197
|
-
message?: string;
|
|
198
|
-
deletedCount?: number;
|
|
199
|
-
uploads?: ({
|
|
200
|
-
id?: string;
|
|
201
|
-
uploadType?: string;
|
|
202
|
-
createdAt?: string;
|
|
203
|
-
lastUsedDate?: string | null;
|
|
204
|
-
})[];
|
|
205
|
-
dryRun?: boolean;
|
|
206
|
-
};
|
|
207
|
-
};
|
|
208
|
-
};
|
|
209
|
-
};
|
|
210
|
-
};
|
|
211
197
|
UploadsController_createBinary: {
|
|
212
198
|
parameters: {
|
|
213
199
|
header: {
|
|
@@ -445,19 +431,25 @@ export interface operations {
|
|
|
445
431
|
};
|
|
446
432
|
};
|
|
447
433
|
};
|
|
448
|
-
|
|
434
|
+
ResultsController_notifyTestRunComplete: {
|
|
449
435
|
parameters: {
|
|
450
436
|
header: {
|
|
451
437
|
"x-app-api-key": string;
|
|
452
438
|
};
|
|
439
|
+
path: {
|
|
440
|
+
uploadId: string;
|
|
441
|
+
};
|
|
453
442
|
};
|
|
454
443
|
responses: {
|
|
444
|
+
/** @description Send results summary email. */
|
|
455
445
|
201: {
|
|
456
|
-
content:
|
|
446
|
+
content: {
|
|
447
|
+
"application/json": string;
|
|
448
|
+
};
|
|
457
449
|
};
|
|
458
450
|
};
|
|
459
451
|
};
|
|
460
|
-
|
|
452
|
+
ResultsController_downloadReport: {
|
|
461
453
|
parameters: {
|
|
462
454
|
header: {
|
|
463
455
|
"x-app-api-key": string;
|
|
@@ -467,8 +459,26 @@ export interface operations {
|
|
|
467
459
|
};
|
|
468
460
|
};
|
|
469
461
|
responses: {
|
|
470
|
-
/** @description
|
|
471
|
-
|
|
462
|
+
/** @description Download combined JUNIT test report (report.xml) for the upload */
|
|
463
|
+
200: {
|
|
464
|
+
content: {
|
|
465
|
+
"application/json": string;
|
|
466
|
+
};
|
|
467
|
+
};
|
|
468
|
+
};
|
|
469
|
+
};
|
|
470
|
+
ResultsController_downloadHtmlReport: {
|
|
471
|
+
parameters: {
|
|
472
|
+
header: {
|
|
473
|
+
"x-app-api-key": string;
|
|
474
|
+
};
|
|
475
|
+
path: {
|
|
476
|
+
uploadId: string;
|
|
477
|
+
};
|
|
478
|
+
};
|
|
479
|
+
responses: {
|
|
480
|
+
/** @description Download combined HTML test report (report.html) for the upload */
|
|
481
|
+
200: {
|
|
472
482
|
content: {
|
|
473
483
|
"application/json": string;
|
|
474
484
|
};
|
|
@@ -497,6 +507,141 @@ export interface operations {
|
|
|
497
507
|
};
|
|
498
508
|
};
|
|
499
509
|
};
|
|
510
|
+
/**
|
|
511
|
+
* Download Allure report as HTML
|
|
512
|
+
* @description Downloads a single-file Allure report as HTML containing all test results. Report is generated once and stored in Supabase Storage for subsequent downloads.
|
|
513
|
+
*/
|
|
514
|
+
AllureController_downloadAllureReport: {
|
|
515
|
+
parameters: {
|
|
516
|
+
header: {
|
|
517
|
+
"x-app-api-key": string;
|
|
518
|
+
};
|
|
519
|
+
path: {
|
|
520
|
+
/** @description The upload ID to generate Allure report for */
|
|
521
|
+
uploadId: string;
|
|
522
|
+
};
|
|
523
|
+
};
|
|
524
|
+
responses: {
|
|
525
|
+
/** @description Allure report HTML file download */
|
|
526
|
+
200: {
|
|
527
|
+
content: {
|
|
528
|
+
"text/html": string;
|
|
529
|
+
};
|
|
530
|
+
};
|
|
531
|
+
/** @description Upload not found or no results available */
|
|
532
|
+
404: {
|
|
533
|
+
content: never;
|
|
534
|
+
};
|
|
535
|
+
};
|
|
536
|
+
};
|
|
537
|
+
WebhooksController_getWebhook: {
|
|
538
|
+
parameters: {
|
|
539
|
+
query?: {
|
|
540
|
+
/** @description Set to true to return full secret instead of masked version */
|
|
541
|
+
show_secret?: boolean;
|
|
542
|
+
};
|
|
543
|
+
header: {
|
|
544
|
+
"x-app-api-key": string;
|
|
545
|
+
};
|
|
546
|
+
};
|
|
547
|
+
responses: {
|
|
548
|
+
/** @description Current webhook configuration */
|
|
549
|
+
200: {
|
|
550
|
+
content: {
|
|
551
|
+
"application/json": {
|
|
552
|
+
webhook_url?: string;
|
|
553
|
+
/** @description Full secret (only when show_secret=true) */
|
|
554
|
+
secret_key?: string;
|
|
555
|
+
/** @description Masked secret (default) */
|
|
556
|
+
secret_key_masked?: string;
|
|
557
|
+
/** Format: date-time */
|
|
558
|
+
created_at?: string;
|
|
559
|
+
/** Format: date-time */
|
|
560
|
+
updated_at?: string;
|
|
561
|
+
};
|
|
562
|
+
};
|
|
563
|
+
};
|
|
564
|
+
};
|
|
565
|
+
};
|
|
566
|
+
WebhooksController_setWebhook: {
|
|
567
|
+
parameters: {
|
|
568
|
+
header: {
|
|
569
|
+
"x-app-api-key": string;
|
|
570
|
+
};
|
|
571
|
+
};
|
|
572
|
+
requestBody: {
|
|
573
|
+
content: {
|
|
574
|
+
"application/json": {
|
|
575
|
+
/**
|
|
576
|
+
* Format: uri
|
|
577
|
+
* @example https://api.example.com/webhook
|
|
578
|
+
*/
|
|
579
|
+
url: string;
|
|
580
|
+
};
|
|
581
|
+
};
|
|
582
|
+
};
|
|
583
|
+
responses: {
|
|
584
|
+
/** @description Webhook URL set successfully */
|
|
585
|
+
201: {
|
|
586
|
+
content: {
|
|
587
|
+
"application/json": Record<string, never>;
|
|
588
|
+
};
|
|
589
|
+
};
|
|
590
|
+
};
|
|
591
|
+
};
|
|
592
|
+
WebhooksController_deleteWebhook: {
|
|
593
|
+
parameters: {
|
|
594
|
+
header: {
|
|
595
|
+
"x-app-api-key": string;
|
|
596
|
+
};
|
|
597
|
+
};
|
|
598
|
+
responses: {
|
|
599
|
+
/** @description Webhook configuration deleted successfully */
|
|
600
|
+
200: {
|
|
601
|
+
content: {
|
|
602
|
+
"application/json": Record<string, never>;
|
|
603
|
+
};
|
|
604
|
+
};
|
|
605
|
+
};
|
|
606
|
+
};
|
|
607
|
+
WebhooksController_regenerateWebhookSecret: {
|
|
608
|
+
parameters: {
|
|
609
|
+
header: {
|
|
610
|
+
"x-app-api-key": string;
|
|
611
|
+
};
|
|
612
|
+
};
|
|
613
|
+
responses: {
|
|
614
|
+
/** @description Webhook secret regenerated successfully */
|
|
615
|
+
201: {
|
|
616
|
+
content: {
|
|
617
|
+
"application/json": Record<string, never>;
|
|
618
|
+
};
|
|
619
|
+
};
|
|
620
|
+
};
|
|
621
|
+
};
|
|
622
|
+
WebhooksController_testWebhook: {
|
|
623
|
+
parameters: {
|
|
624
|
+
header: {
|
|
625
|
+
"x-app-api-key": string;
|
|
626
|
+
};
|
|
627
|
+
};
|
|
628
|
+
requestBody: {
|
|
629
|
+
content: {
|
|
630
|
+
"application/json": {
|
|
631
|
+
/** Format: uri */
|
|
632
|
+
url?: string;
|
|
633
|
+
};
|
|
634
|
+
};
|
|
635
|
+
};
|
|
636
|
+
responses: {
|
|
637
|
+
/** @description Test webhook sent successfully */
|
|
638
|
+
201: {
|
|
639
|
+
content: {
|
|
640
|
+
"application/json": Record<string, never>;
|
|
641
|
+
};
|
|
642
|
+
};
|
|
643
|
+
};
|
|
644
|
+
};
|
|
500
645
|
OrgController_paddleTransactionCompleted: {
|
|
501
646
|
parameters: {
|
|
502
647
|
header: {
|
|
@@ -583,41 +728,6 @@ export interface operations {
|
|
|
583
728
|
};
|
|
584
729
|
};
|
|
585
730
|
};
|
|
586
|
-
StatsController_getPublicStats: {
|
|
587
|
-
responses: {
|
|
588
|
-
200: {
|
|
589
|
-
content: never;
|
|
590
|
-
};
|
|
591
|
-
};
|
|
592
|
-
};
|
|
593
|
-
StatsController_sendDailyReport: {
|
|
594
|
-
responses: {
|
|
595
|
-
201: {
|
|
596
|
-
content: never;
|
|
597
|
-
};
|
|
598
|
-
};
|
|
599
|
-
};
|
|
600
|
-
StatsController_reportSlowTestsDev: {
|
|
601
|
-
responses: {
|
|
602
|
-
201: {
|
|
603
|
-
content: never;
|
|
604
|
-
};
|
|
605
|
-
};
|
|
606
|
-
};
|
|
607
|
-
StatsController_reportSlowTestsProd: {
|
|
608
|
-
responses: {
|
|
609
|
-
201: {
|
|
610
|
-
content: never;
|
|
611
|
-
};
|
|
612
|
-
};
|
|
613
|
-
};
|
|
614
|
-
MoropoController_runScheduledJobs: {
|
|
615
|
-
responses: {
|
|
616
|
-
200: {
|
|
617
|
-
content: never;
|
|
618
|
-
};
|
|
619
|
-
};
|
|
620
|
-
};
|
|
621
731
|
FrontendController_checkDomainSaml: {
|
|
622
732
|
/** @description Domain to check for SAML configuration */
|
|
623
733
|
requestBody: {
|
package/oclif.manifest.json
CHANGED
|
@@ -134,6 +134,26 @@
|
|
|
134
134
|
"multiple": false,
|
|
135
135
|
"type": "option"
|
|
136
136
|
},
|
|
137
|
+
"allure-path": {
|
|
138
|
+
"dependsOn": [
|
|
139
|
+
"report"
|
|
140
|
+
],
|
|
141
|
+
"description": "Custom file path for downloaded Allure report (default: ./report.html)",
|
|
142
|
+
"name": "allure-path",
|
|
143
|
+
"hasDynamicHelp": false,
|
|
144
|
+
"multiple": false,
|
|
145
|
+
"type": "option"
|
|
146
|
+
},
|
|
147
|
+
"html-path": {
|
|
148
|
+
"dependsOn": [
|
|
149
|
+
"report"
|
|
150
|
+
],
|
|
151
|
+
"description": "Custom file path for downloaded HTML report (default: ./report.html)",
|
|
152
|
+
"name": "html-path",
|
|
153
|
+
"hasDynamicHelp": false,
|
|
154
|
+
"multiple": false,
|
|
155
|
+
"type": "option"
|
|
156
|
+
},
|
|
137
157
|
"async": {
|
|
138
158
|
"description": "Immediately return (exit code 0) from the command without waiting for the results of the run (useful for saving CI minutes)",
|
|
139
159
|
"name": "async",
|
|
@@ -263,7 +283,8 @@
|
|
|
263
283
|
"options": [
|
|
264
284
|
"18",
|
|
265
285
|
"17",
|
|
266
|
-
"16"
|
|
286
|
+
"16",
|
|
287
|
+
"26"
|
|
267
288
|
],
|
|
268
289
|
"type": "option"
|
|
269
290
|
},
|
|
@@ -303,6 +324,7 @@
|
|
|
303
324
|
"1.41.0",
|
|
304
325
|
"2.0.2",
|
|
305
326
|
"2.0.3",
|
|
327
|
+
"2.0.4",
|
|
306
328
|
"latest"
|
|
307
329
|
],
|
|
308
330
|
"type": "option"
|
|
@@ -371,11 +393,12 @@
|
|
|
371
393
|
"aliases": [
|
|
372
394
|
"format"
|
|
373
395
|
],
|
|
374
|
-
"description": "
|
|
396
|
+
"description": "Generate and download test reports in the specified format. Use \"allure\" for a complete HTML report.",
|
|
375
397
|
"name": "report",
|
|
376
398
|
"hasDynamicHelp": false,
|
|
377
399
|
"multiple": false,
|
|
378
400
|
"options": [
|
|
401
|
+
"allure",
|
|
379
402
|
"junit",
|
|
380
403
|
"html"
|
|
381
404
|
],
|
|
@@ -578,5 +601,5 @@
|
|
|
578
601
|
]
|
|
579
602
|
}
|
|
580
603
|
},
|
|
581
|
-
"version": "4.0
|
|
604
|
+
"version": "4.1.0"
|
|
582
605
|
}
|
package/package.json
CHANGED
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"type": "git",
|
|
73
73
|
"url": "https://devicecloud.dev"
|
|
74
74
|
},
|
|
75
|
-
"version": "4.0
|
|
75
|
+
"version": "4.1.0",
|
|
76
76
|
"bugs": {
|
|
77
77
|
"url": "https://discord.gg/gm3mJwcNw8"
|
|
78
78
|
},
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"dcd": "./bin/dev.js",
|
|
90
90
|
"prod": "./bin/run.js",
|
|
91
91
|
"build": "shx rm -rf dist && tsc -b",
|
|
92
|
-
"lint": "
|
|
92
|
+
"lint": "eslint . --ext .ts",
|
|
93
93
|
"version": "oclif readme && git add README.md",
|
|
94
94
|
"test": "node scripts/test-runner.mjs"
|
|
95
95
|
}
|