@devicecloud.dev/dcd 4.1.4 → 4.1.5

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.
@@ -1,4 +1,16 @@
1
1
  import { Command } from '@oclif/core';
2
+ /**
3
+ * Primary CLI command for executing tests on DeviceCloud.
4
+ * Orchestrates the complete test workflow:
5
+ * - Binary upload with SHA deduplication
6
+ * - Flow file analysis and dependency resolution
7
+ * - Device compatibility validation
8
+ * - Test submission with parallel execution
9
+ * - Real-time result polling with 5-second intervals
10
+ * - Artifact download (reports, videos, logs)
11
+ *
12
+ * Replaces `maestro cloud` with DeviceCloud-specific functionality.
13
+ */
2
14
  export default class Cloud extends Command {
3
15
  static args: {
4
16
  firstFile: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
@@ -50,12 +62,30 @@ export default class Cloud extends Command {
50
62
  apiKey: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
51
63
  apiUrl: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
52
64
  };
65
+ /** Service for device/OS compatibility validation */
53
66
  private deviceValidationService;
67
+ /** Service for Moropo test framework integration */
54
68
  private moropoService;
69
+ /** Service for downloading test reports and artifacts */
55
70
  private reportDownloadService;
71
+ /** Service for polling test results with 5-second intervals */
56
72
  private resultsPollingService;
73
+ /** Service for submitting tests to the API */
57
74
  private testSubmissionService;
75
+ /**
76
+ * Check for CLI updates and notify user if outdated
77
+ * Compares current version with latest npm release
78
+ * @returns Promise that resolves when version check is complete
79
+ */
58
80
  private versionCheck;
81
+ /** Service for CLI version checking */
59
82
  private versionService;
83
+ /**
84
+ * Main command execution entry point
85
+ * Orchestrates the complete test submission and monitoring workflow
86
+ * @returns Promise that resolves when command execution is complete
87
+ * @throws RunFailedError if tests fail
88
+ * @throws Error for infrastructure or configuration errors
89
+ */
60
90
  run(): Promise<any>;
61
91
  }
@@ -23,6 +23,18 @@ process.on('warning', (warning) => {
23
23
  // Ignore punycode deprecation warnings
24
24
  }
25
25
  });
26
+ /**
27
+ * Primary CLI command for executing tests on DeviceCloud.
28
+ * Orchestrates the complete test workflow:
29
+ * - Binary upload with SHA deduplication
30
+ * - Flow file analysis and dependency resolution
31
+ * - Device compatibility validation
32
+ * - Test submission with parallel execution
33
+ * - Real-time result polling with 5-second intervals
34
+ * - Artifact download (reports, videos, logs)
35
+ *
36
+ * Replaces `maestro cloud` with DeviceCloud-specific functionality.
37
+ */
26
38
  class Cloud extends core_1.Command {
27
39
  static args = {
28
40
  firstFile: core_1.Args.string({
@@ -40,11 +52,21 @@ class Cloud extends core_1.Command {
40
52
  static enableJsonFlag = true;
41
53
  static examples = ['<%= config.bin %> <%= command.id %>'];
42
54
  static flags = constants_1.flags;
55
+ /** Service for device/OS compatibility validation */
43
56
  deviceValidationService = new device_validation_service_1.DeviceValidationService();
57
+ /** Service for Moropo test framework integration */
44
58
  moropoService = new moropo_service_1.MoropoService();
59
+ /** Service for downloading test reports and artifacts */
45
60
  reportDownloadService = new report_download_service_1.ReportDownloadService();
61
+ /** Service for polling test results with 5-second intervals */
46
62
  resultsPollingService = new results_polling_service_1.ResultsPollingService();
63
+ /** Service for submitting tests to the API */
47
64
  testSubmissionService = new test_submission_service_1.TestSubmissionService();
65
+ /**
66
+ * Check for CLI updates and notify user if outdated
67
+ * Compares current version with latest npm release
68
+ * @returns Promise that resolves when version check is complete
69
+ */
48
70
  versionCheck = async () => {
49
71
  const latestVersion = await this.versionService.checkLatestCliVersion();
50
72
  if (latestVersion &&
@@ -57,7 +79,15 @@ class Cloud extends core_1.Command {
57
79
  `);
58
80
  }
59
81
  };
82
+ /** Service for CLI version checking */
60
83
  versionService = new version_service_1.VersionService();
84
+ /**
85
+ * Main command execution entry point
86
+ * Orchestrates the complete test submission and monitoring workflow
87
+ * @returns Promise that resolves when command execution is complete
88
+ * @throws RunFailedError if tests fail
89
+ * @throws Error for infrastructure or configuration errors
90
+ */
61
91
  async run() {
62
92
  let output = null;
63
93
  // Store debug flag outside try/catch to access it in catch block
@@ -44,7 +44,7 @@ exports.executionFlags = {
44
44
  }),
45
45
  'runner-type': core_1.Flags.string({
46
46
  default: 'default',
47
- description: '[experimental] The type of runner to use - note: anything other than default will incur premium pricing tiers, see https://docs.devicecloud.dev/reference/runner-type for more information. gpu1 is Android-only and requires contacting support to enable, otherwise reverts to default.',
48
- options: ['default', 'm4', 'm1', 'gpu1'],
47
+ description: '[experimental] The type of runner to use - note: anything other than default will incur premium pricing tiers, see https://docs.devicecloud.dev/reference/runner-type for more information. gpu1 and cpu1 are Android-only and require contacting support to enable, otherwise reverts to default.',
48
+ options: ['default', 'm4', 'm1', 'gpu1', 'cpu1'],
49
49
  }),
50
50
  };
@@ -14,14 +14,14 @@ export declare const ApiGateway: {
14
14
  downloadArtifactsZip(baseUrl: string, apiKey: string, uploadId: string, results: "ALL" | "FAILED", artifactsPath?: string): Promise<void>;
15
15
  finaliseUpload(baseUrl: string, apiKey: string, id: string, metadata: TAppMetadata, path: string, sha: string): Promise<Record<string, never>>;
16
16
  getBinaryUploadUrl(baseUrl: string, apiKey: string, platform: "android" | "ios"): Promise<{
17
- id: string;
18
17
  message: string;
19
18
  path: string;
20
19
  token: string;
20
+ id: string;
21
21
  }>;
22
22
  getResultsForUpload(baseUrl: string, apiKey: string, uploadId: string): Promise<{
23
- results?: import("../types/generated/schema.types").components["schemas"]["TResultResponse"][];
24
23
  statusCode?: number;
24
+ results?: import("../types/generated/schema.types").components["schemas"]["TResultResponse"][];
25
25
  }>;
26
26
  getUploadStatus(baseUrl: string, apiKey: string, options: {
27
27
  name?: string;
@@ -1,3 +1,4 @@
1
+ /** Email notification configuration */
1
2
  interface INotificationsConfig {
2
3
  email?: {
3
4
  enabled?: boolean;
@@ -5,6 +6,7 @@ interface INotificationsConfig {
5
6
  recipients?: string[];
6
7
  };
7
8
  }
9
+ /** Workspace configuration from config.yaml */
8
10
  interface IWorkspaceConfig {
9
11
  excludeTags?: null | string[];
10
12
  executionOrder?: IExecutionOrder | null;
@@ -13,13 +15,16 @@ interface IWorkspaceConfig {
13
15
  local?: ILocal | null;
14
16
  notifications?: INotificationsConfig;
15
17
  }
18
+ /** Local execution configuration */
16
19
  interface ILocal {
17
20
  deterministicOrder: boolean | null;
18
21
  }
22
+ /** Sequential execution configuration */
19
23
  interface IExecutionOrder {
20
24
  continueOnFailure: boolean;
21
25
  flowsOrder: string[];
22
26
  }
27
+ /** Options for execution plan generation */
23
28
  export interface PlanOptions {
24
29
  configFile?: string;
25
30
  debug?: boolean;
@@ -28,6 +33,7 @@ export interface PlanOptions {
28
33
  includeTags?: string[];
29
34
  input: string;
30
35
  }
36
+ /** Execution plan containing all flows to run with metadata and dependencies */
31
37
  export interface IExecutionPlan {
32
38
  allExcludeTags?: null | string[];
33
39
  allIncludeTags?: null | string[];
@@ -39,9 +45,26 @@ export interface IExecutionPlan {
39
45
  totalFlowFiles: number;
40
46
  workspaceConfig?: IWorkspaceConfig;
41
47
  }
48
+ /** Flow sequence configuration for ordered execution */
42
49
  interface IFlowSequence {
43
50
  continueOnFailure?: boolean;
44
51
  flows: string[];
45
52
  }
53
+ /**
54
+ * Generate execution plan for test flows
55
+ *
56
+ * Handles:
57
+ * - Single file or directory input
58
+ * - Workspace configuration (config.yaml)
59
+ * - Flow inclusion/exclusion patterns
60
+ * - Tag-based filtering (include/exclude)
61
+ * - Dependency resolution (runFlow, scripts, media)
62
+ * - Sequential execution ordering
63
+ * - DeviceCloud-specific overrides
64
+ *
65
+ * @param options - Plan generation options
66
+ * @returns Complete execution plan with flows, dependencies, and metadata
67
+ * @throws Error if input path doesn't exist, no flows found, or dependencies missing
68
+ */
46
69
  export declare function plan(options: PlanOptions): Promise<IExecutionPlan>;
47
70
  export {};
@@ -5,6 +5,13 @@ const glob_1 = require("glob");
5
5
  const fs = require("node:fs");
6
6
  const path = require("node:path");
7
7
  const execution_plan_utils_1 = require("./execution-plan.utils");
8
+ /**
9
+ * Recursively check and resolve all dependencies for a flow file
10
+ * Includes runFlow references, JavaScript scripts, and media files
11
+ * @param input - Path to flow file to check
12
+ * @returns Array of all dependency file paths (deduplicated)
13
+ * @throws Error if any referenced files are missing
14
+ */
8
15
  async function checkDependencies(input) {
9
16
  const checkedDependencies = [];
10
17
  const uncheckedDependencies = [input];
@@ -35,12 +42,24 @@ async function checkDependencies(input) {
35
42
  }
36
43
  return checkedDependencies;
37
44
  }
45
+ /**
46
+ * Filter flow files based on exclude patterns
47
+ * @param unfilteredFlowFiles - All discovered flow files
48
+ * @param excludeFlows - Patterns to exclude
49
+ * @returns Filtered array of flow file paths
50
+ */
38
51
  function filterFlowFiles(unfilteredFlowFiles, excludeFlows) {
39
52
  if (excludeFlows) {
40
53
  return unfilteredFlowFiles.filter((file) => !excludeFlows.some((flow) => path.normalize(file).startsWith(path.normalize(path.resolve(flow)))));
41
54
  }
42
55
  return unfilteredFlowFiles;
43
56
  }
57
+ /**
58
+ * Load workspace configuration from config.yaml/yml if present
59
+ * @param input - Input directory path
60
+ * @param unfilteredFlowFiles - List of discovered flow files
61
+ * @returns Workspace configuration object (empty if no config file found)
62
+ */
44
63
  function getWorkspaceConfig(input, unfilteredFlowFiles) {
45
64
  const possibleConfigPaths = new Set([path.join(input, 'config.yaml'), path.join(input, 'config.yml')].map((p) => path.normalize(p)));
46
65
  const configFilePath = unfilteredFlowFiles.find((file) => possibleConfigPaths.has(path.normalize(file)));
@@ -49,6 +68,12 @@ function getWorkspaceConfig(input, unfilteredFlowFiles) {
49
68
  : {};
50
69
  return config;
51
70
  }
71
+ /**
72
+ * Extract DeviceCloud-specific override environment variables
73
+ * Looks for env vars prefixed with DEVICECLOUD_OVERRIDE_
74
+ * @param config - Flow configuration object
75
+ * @returns Object containing override key-value pairs
76
+ */
52
77
  function extractDeviceCloudOverrides(config) {
53
78
  if (!config || !config.env || typeof config.env !== 'object') {
54
79
  return {};
@@ -64,6 +89,22 @@ function extractDeviceCloudOverrides(config) {
64
89
  }
65
90
  return overrides;
66
91
  }
92
+ /**
93
+ * Generate execution plan for test flows
94
+ *
95
+ * Handles:
96
+ * - Single file or directory input
97
+ * - Workspace configuration (config.yaml)
98
+ * - Flow inclusion/exclusion patterns
99
+ * - Tag-based filtering (include/exclude)
100
+ * - Dependency resolution (runFlow, scripts, media)
101
+ * - Sequential execution ordering
102
+ * - DeviceCloud-specific overrides
103
+ *
104
+ * @param options - Plan generation options
105
+ * @returns Complete execution plan with flows, dependencies, and metadata
106
+ * @throws Error if input path doesn't exist, no flows found, or dependencies missing
107
+ */
67
108
  async function plan(options) {
68
109
  const { input, includeTags = [], excludeTags = [], excludeFlows, configFile, debug = false, } = options;
69
110
  const normalizedInput = path.normalize(input);