eas-cli 16.15.0 → 16.16.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/README.md +137 -84
- package/build/commandUtils/workflow/fetchLogs.d.ts +2 -0
- package/build/commandUtils/workflow/fetchLogs.js +16 -0
- package/build/commandUtils/workflow/stateMachine.d.ts +44 -0
- package/build/commandUtils/workflow/stateMachine.js +212 -0
- package/build/commandUtils/workflow/types.d.ts +39 -0
- package/build/commandUtils/workflow/types.js +13 -0
- package/build/commandUtils/workflow/utils.d.ts +12 -0
- package/build/commandUtils/workflow/utils.js +116 -0
- package/build/commands/workflow/cancel.js +3 -6
- package/build/commands/workflow/logs.d.ts +18 -0
- package/build/commands/workflow/logs.js +94 -0
- package/build/commands/workflow/run.d.ts +105 -0
- package/build/commands/workflow/run.js +280 -0
- package/build/commands/workflow/runs.js +4 -3
- package/build/commands/workflow/view.d.ts +17 -0
- package/build/commands/workflow/view.js +95 -0
- package/build/credentials/ios/appstore/bundleIdCapabilities.d.ts +4 -17
- package/build/credentials/ios/appstore/bundleIdCapabilities.js +45 -625
- package/build/credentials/ios/appstore/capabilityIdentifiers.js +33 -34
- package/build/credentials/ios/appstore/capabilityList.d.ts +33 -0
- package/build/credentials/ios/appstore/capabilityList.js +646 -0
- package/build/graphql/generated.d.ts +236 -19
- package/build/graphql/queries/WorkflowJobQuery.d.ts +7 -0
- package/build/graphql/queries/WorkflowJobQuery.js +29 -0
- package/build/graphql/queries/WorkflowRunQuery.js +13 -13
- package/build/graphql/types/WorkflowJob.d.ts +1 -0
- package/build/graphql/types/WorkflowJob.js +32 -0
- package/build/graphql/types/WorkflowRun.js +18 -0
- package/build/worker/assets.d.ts +0 -3
- package/build/worker/assets.js +3 -3
- package/build/worker/upload.js +4 -8
- package/build/worker/utils/multipart.d.ts +5 -4
- package/build/worker/utils/multipart.js +44 -9
- package/oclif.manifest.json +85 -1
- package/package.json +2 -2
- package/build/commandUtils/workflows.d.ts +0 -20
- package/build/commandUtils/workflows.js +0 -21
|
@@ -1,3 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EAS Workflow Run Command
|
|
3
|
+
*
|
|
4
|
+
* This command runs an EAS workflow with support for interactive input prompting.
|
|
5
|
+
*
|
|
6
|
+
* Input Sources (in order of precedence):
|
|
7
|
+
* 1. Command line flags (-F key=value)
|
|
8
|
+
* 2. STDIN JSON input (echo '{"key": "value"}' | eas workflow:run)
|
|
9
|
+
* 3. Interactive prompts (when required inputs are missing and not in non-interactive mode)
|
|
10
|
+
*
|
|
11
|
+
* Interactive Prompting:
|
|
12
|
+
* - When running in interactive mode (default), the command will automatically prompt
|
|
13
|
+
* for any required inputs that are not provided via flags or STDIN
|
|
14
|
+
* - Input types supported: string, boolean, number, choice, environment
|
|
15
|
+
* - Each input type has appropriate validation and default values
|
|
16
|
+
* - Use --non-interactive flag to disable prompting and require all inputs via flags
|
|
17
|
+
*
|
|
18
|
+
* Example workflow with inputs:
|
|
19
|
+
* ```yaml
|
|
20
|
+
* on:
|
|
21
|
+
* workflow_dispatch:
|
|
22
|
+
* inputs:
|
|
23
|
+
* environment:
|
|
24
|
+
* type: string
|
|
25
|
+
* required: true
|
|
26
|
+
* description: "Environment to deploy to"
|
|
27
|
+
* debug:
|
|
28
|
+
* type: boolean
|
|
29
|
+
* default: false
|
|
30
|
+
* description: "Enable debug mode"
|
|
31
|
+
* version:
|
|
32
|
+
* type: number
|
|
33
|
+
* required: true
|
|
34
|
+
* description: "Version number"
|
|
35
|
+
* deployment_type:
|
|
36
|
+
* type: choice
|
|
37
|
+
* options: ["staging", "production"]
|
|
38
|
+
* default: "staging"
|
|
39
|
+
* description: "Type of deployment"
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
import { z } from 'zod';
|
|
1
43
|
import EasCommand from '../../commandUtils/EasCommand';
|
|
2
44
|
export default class WorkflowRun extends EasCommand {
|
|
3
45
|
static description: string;
|
|
@@ -8,6 +50,7 @@ export default class WorkflowRun extends EasCommand {
|
|
|
8
50
|
static flags: {
|
|
9
51
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
10
52
|
wait: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
53
|
+
input: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined>;
|
|
11
54
|
'non-interactive': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
12
55
|
};
|
|
13
56
|
static contextDefinition: {
|
|
@@ -19,3 +62,65 @@ export default class WorkflowRun extends EasCommand {
|
|
|
19
62
|
};
|
|
20
63
|
runAsync(): Promise<void>;
|
|
21
64
|
}
|
|
65
|
+
export declare function parseInputs(inputFlags: string[]): Record<string, string>;
|
|
66
|
+
export declare function maybeReadStdinAsync(): Promise<string | null>;
|
|
67
|
+
export declare function parseJsonInputs(jsonString: string): Record<string, string>;
|
|
68
|
+
export declare const WorkflowDispatchInputZ: z.ZodIntersection<z.ZodObject<{
|
|
69
|
+
description: z.ZodOptional<z.ZodPipeline<z.ZodUnion<[z.ZodNumber, z.ZodString]>, z.ZodString>>;
|
|
70
|
+
required: z.ZodDefault<z.ZodUnion<[z.ZodBoolean, z.ZodPipeline<z.ZodNumber, z.ZodBoolean>, z.ZodEffects<z.ZodBoolean, boolean, unknown>]>>;
|
|
71
|
+
}, "strip", z.ZodTypeAny, {
|
|
72
|
+
required: boolean;
|
|
73
|
+
description?: string | undefined;
|
|
74
|
+
}, {
|
|
75
|
+
description?: string | number | undefined;
|
|
76
|
+
required?: unknown;
|
|
77
|
+
}>, z.ZodUnion<[z.ZodObject<{
|
|
78
|
+
type: z.ZodDefault<z.ZodLiteral<"string">>;
|
|
79
|
+
default: z.ZodOptional<z.ZodPipeline<z.ZodUnion<[z.ZodNumber, z.ZodString]>, z.ZodString>>;
|
|
80
|
+
}, "strip", z.ZodTypeAny, {
|
|
81
|
+
type: "string";
|
|
82
|
+
default?: string | undefined;
|
|
83
|
+
}, {
|
|
84
|
+
default?: string | number | undefined;
|
|
85
|
+
type?: "string" | undefined;
|
|
86
|
+
}>, z.ZodObject<{
|
|
87
|
+
type: z.ZodLiteral<"boolean">;
|
|
88
|
+
default: z.ZodOptional<z.ZodUnion<[z.ZodBoolean, z.ZodPipeline<z.ZodNumber, z.ZodBoolean>, z.ZodEffects<z.ZodBoolean, boolean, unknown>]>>;
|
|
89
|
+
}, "strip", z.ZodTypeAny, {
|
|
90
|
+
type: "boolean";
|
|
91
|
+
default?: boolean | undefined;
|
|
92
|
+
}, {
|
|
93
|
+
type: "boolean";
|
|
94
|
+
default?: unknown;
|
|
95
|
+
}>, z.ZodObject<{
|
|
96
|
+
type: z.ZodLiteral<"number">;
|
|
97
|
+
default: z.ZodOptional<z.ZodNumber>;
|
|
98
|
+
}, "strip", z.ZodTypeAny, {
|
|
99
|
+
type: "number";
|
|
100
|
+
default?: number | undefined;
|
|
101
|
+
}, {
|
|
102
|
+
type: "number";
|
|
103
|
+
default?: number | undefined;
|
|
104
|
+
}>, z.ZodObject<{
|
|
105
|
+
type: z.ZodLiteral<"choice">;
|
|
106
|
+
default: z.ZodOptional<z.ZodPipeline<z.ZodUnion<[z.ZodNumber, z.ZodString]>, z.ZodString>>;
|
|
107
|
+
options: z.ZodArray<z.ZodPipeline<z.ZodUnion<[z.ZodNumber, z.ZodString]>, z.ZodString>, "many">;
|
|
108
|
+
}, "strip", z.ZodTypeAny, {
|
|
109
|
+
type: "choice";
|
|
110
|
+
options: string[];
|
|
111
|
+
default?: string | undefined;
|
|
112
|
+
}, {
|
|
113
|
+
type: "choice";
|
|
114
|
+
options: (string | number)[];
|
|
115
|
+
default?: string | number | undefined;
|
|
116
|
+
}>, z.ZodObject<{
|
|
117
|
+
type: z.ZodLiteral<"environment">;
|
|
118
|
+
default: z.ZodOptional<z.ZodString>;
|
|
119
|
+
}, "strip", z.ZodTypeAny, {
|
|
120
|
+
type: "environment";
|
|
121
|
+
default?: string | undefined;
|
|
122
|
+
}, {
|
|
123
|
+
type: "environment";
|
|
124
|
+
default?: string | undefined;
|
|
125
|
+
}>]>>;
|
|
126
|
+
export declare function parseWorkflowInputsFromYaml(yamlConfig: string): Record<string, z.infer<typeof WorkflowDispatchInputZ>>;
|
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* EAS Workflow Run Command
|
|
4
|
+
*
|
|
5
|
+
* This command runs an EAS workflow with support for interactive input prompting.
|
|
6
|
+
*
|
|
7
|
+
* Input Sources (in order of precedence):
|
|
8
|
+
* 1. Command line flags (-F key=value)
|
|
9
|
+
* 2. STDIN JSON input (echo '{"key": "value"}' | eas workflow:run)
|
|
10
|
+
* 3. Interactive prompts (when required inputs are missing and not in non-interactive mode)
|
|
11
|
+
*
|
|
12
|
+
* Interactive Prompting:
|
|
13
|
+
* - When running in interactive mode (default), the command will automatically prompt
|
|
14
|
+
* for any required inputs that are not provided via flags or STDIN
|
|
15
|
+
* - Input types supported: string, boolean, number, choice, environment
|
|
16
|
+
* - Each input type has appropriate validation and default values
|
|
17
|
+
* - Use --non-interactive flag to disable prompting and require all inputs via flags
|
|
18
|
+
*
|
|
19
|
+
* Example workflow with inputs:
|
|
20
|
+
* ```yaml
|
|
21
|
+
* on:
|
|
22
|
+
* workflow_dispatch:
|
|
23
|
+
* inputs:
|
|
24
|
+
* environment:
|
|
25
|
+
* type: string
|
|
26
|
+
* required: true
|
|
27
|
+
* description: "Environment to deploy to"
|
|
28
|
+
* debug:
|
|
29
|
+
* type: boolean
|
|
30
|
+
* default: false
|
|
31
|
+
* description: "Enable debug mode"
|
|
32
|
+
* version:
|
|
33
|
+
* type: number
|
|
34
|
+
* required: true
|
|
35
|
+
* description: "Version number"
|
|
36
|
+
* deployment_type:
|
|
37
|
+
* type: choice
|
|
38
|
+
* options: ["staging", "production"]
|
|
39
|
+
* default: "staging"
|
|
40
|
+
* description: "Type of deployment"
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
2
43
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.parseWorkflowInputsFromYaml = exports.WorkflowDispatchInputZ = exports.parseJsonInputs = exports.maybeReadStdinAsync = exports.parseInputs = void 0;
|
|
3
45
|
const tslib_1 = require("tslib");
|
|
4
46
|
const core_1 = require("@oclif/core");
|
|
5
47
|
const core_2 = require("@urql/core");
|
|
@@ -7,6 +49,8 @@ const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
|
7
49
|
const fs = tslib_1.__importStar(require("node:fs"));
|
|
8
50
|
const path = tslib_1.__importStar(require("node:path"));
|
|
9
51
|
const slash_1 = tslib_1.__importDefault(require("slash"));
|
|
52
|
+
const YAML = tslib_1.__importStar(require("yaml"));
|
|
53
|
+
const zod_1 = require("zod");
|
|
10
54
|
const url_1 = require("../../build/utils/url");
|
|
11
55
|
const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
|
|
12
56
|
const flags_1 = require("../../commandUtils/flags");
|
|
@@ -19,6 +63,7 @@ const ora_1 = require("../../ora");
|
|
|
19
63
|
const projectUtils_1 = require("../../project/projectUtils");
|
|
20
64
|
const uploadAccountScopedFileAsync_1 = require("../../project/uploadAccountScopedFileAsync");
|
|
21
65
|
const uploadAccountScopedProjectSourceAsync_1 = require("../../project/uploadAccountScopedProjectSourceAsync");
|
|
66
|
+
const prompts_1 = require("../../prompts");
|
|
22
67
|
const json_1 = require("../../utils/json");
|
|
23
68
|
const promise_1 = require("../../utils/promise");
|
|
24
69
|
const workflowFile_1 = require("../../utils/workflowFile");
|
|
@@ -38,6 +83,13 @@ class WorkflowRun extends EasCommand_1.default {
|
|
|
38
83
|
description: 'Exit codes: 0 = success, 11 = failure, 12 = canceled, 13 = wait aborted.',
|
|
39
84
|
summary: 'Wait for workflow run to complete',
|
|
40
85
|
}),
|
|
86
|
+
input: core_1.Flags.string({
|
|
87
|
+
char: 'F',
|
|
88
|
+
aliases: ['f', 'field'],
|
|
89
|
+
multiple: true,
|
|
90
|
+
description: 'Add a parameter in key=value format. Use multiple instances of this flag to set multiple inputs.',
|
|
91
|
+
summary: 'Set workflow inputs',
|
|
92
|
+
}),
|
|
41
93
|
...flags_1.EasJsonOnlyFlag,
|
|
42
94
|
};
|
|
43
95
|
static contextDefinition = {
|
|
@@ -86,6 +138,33 @@ class WorkflowRun extends EasCommand_1.default {
|
|
|
86
138
|
throw error;
|
|
87
139
|
}
|
|
88
140
|
}
|
|
141
|
+
let inputs;
|
|
142
|
+
// Check for stdin input
|
|
143
|
+
const stdinData = await maybeReadStdinAsync();
|
|
144
|
+
const inputsFromFlags = [...(flags.input ?? [])];
|
|
145
|
+
// Validate that both stdin and -F flags are not provided simultaneously
|
|
146
|
+
if (stdinData && inputsFromFlags.length > 0) {
|
|
147
|
+
throw new Error('Cannot use both stdin JSON input and -F flags simultaneously. Please use only one input method.');
|
|
148
|
+
}
|
|
149
|
+
if (stdinData) {
|
|
150
|
+
inputs = parseJsonInputs(stdinData);
|
|
151
|
+
}
|
|
152
|
+
else if (inputsFromFlags.length > 0) {
|
|
153
|
+
inputs = parseInputs(inputsFromFlags);
|
|
154
|
+
}
|
|
155
|
+
// Parse workflow inputs from YAML and prompt for missing required inputs
|
|
156
|
+
const inputSpecs = parseWorkflowInputsFromYaml(yamlConfig);
|
|
157
|
+
if (!flags['non-interactive']) {
|
|
158
|
+
inputs = await maybePromptForMissingInputsAsync({ inputSpecs, inputs: inputs ?? {} });
|
|
159
|
+
}
|
|
160
|
+
if (inputs && Object.keys(inputs).length > 0) {
|
|
161
|
+
log_1.default.addNewLineIfNone();
|
|
162
|
+
log_1.default.newLine();
|
|
163
|
+
log_1.default.log('Running with inputs:');
|
|
164
|
+
for (const [key, value] of Object.entries(inputs)) {
|
|
165
|
+
log_1.default.log(`- ${chalk_1.default.bold(key)}: ${JSON.stringify(value)}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
89
168
|
let projectArchiveBucketKey;
|
|
90
169
|
let easJsonBucketKey = null;
|
|
91
170
|
let packageJsonBucketKey = null;
|
|
@@ -134,6 +213,7 @@ class WorkflowRun extends EasCommand_1.default {
|
|
|
134
213
|
yamlConfig,
|
|
135
214
|
},
|
|
136
215
|
workflowRunInput: {
|
|
216
|
+
inputs,
|
|
137
217
|
projectSource: {
|
|
138
218
|
type: generated_1.WorkflowProjectSourceType.Gcs,
|
|
139
219
|
projectArchiveBucketKey,
|
|
@@ -226,3 +306,203 @@ async function fileExistsAsync(filePath) {
|
|
|
226
306
|
.then(() => true)
|
|
227
307
|
.catch(() => false);
|
|
228
308
|
}
|
|
309
|
+
function parseInputs(inputFlags) {
|
|
310
|
+
const inputs = {};
|
|
311
|
+
for (const inputFlag of inputFlags) {
|
|
312
|
+
const equalIndex = inputFlag.indexOf('=');
|
|
313
|
+
if (equalIndex === -1) {
|
|
314
|
+
throw new Error(`Invalid input format: ${inputFlag}. Expected key=value format.`);
|
|
315
|
+
}
|
|
316
|
+
const key = inputFlag.substring(0, equalIndex);
|
|
317
|
+
const value = inputFlag.substring(equalIndex + 1);
|
|
318
|
+
if (!key) {
|
|
319
|
+
throw new Error(`Invalid input format: ${inputFlag}. Key cannot be empty.`);
|
|
320
|
+
}
|
|
321
|
+
inputs[key] = value;
|
|
322
|
+
}
|
|
323
|
+
return inputs;
|
|
324
|
+
}
|
|
325
|
+
exports.parseInputs = parseInputs;
|
|
326
|
+
async function maybeReadStdinAsync() {
|
|
327
|
+
// Check if there's data on stdin
|
|
328
|
+
if (process.stdin.isTTY) {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
return await new Promise((resolve, reject) => {
|
|
332
|
+
let data = '';
|
|
333
|
+
process.stdin.setEncoding('utf8');
|
|
334
|
+
process.stdin.on('readable', () => {
|
|
335
|
+
let chunk;
|
|
336
|
+
while ((chunk = process.stdin.read()) !== null) {
|
|
337
|
+
data += chunk;
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
process.stdin.on('end', () => {
|
|
341
|
+
const trimmedData = data.trim();
|
|
342
|
+
resolve(trimmedData || null);
|
|
343
|
+
});
|
|
344
|
+
process.stdin.on('error', err => {
|
|
345
|
+
reject(err);
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
exports.maybeReadStdinAsync = maybeReadStdinAsync;
|
|
350
|
+
function parseJsonInputs(jsonString) {
|
|
351
|
+
try {
|
|
352
|
+
const parsed = JSON.parse(jsonString);
|
|
353
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
354
|
+
throw new Error('JSON input must be an object.');
|
|
355
|
+
}
|
|
356
|
+
return parsed;
|
|
357
|
+
}
|
|
358
|
+
catch (error) {
|
|
359
|
+
throw new Error(`Invalid JSON input.`, { cause: error });
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
exports.parseJsonInputs = parseJsonInputs;
|
|
363
|
+
// `z.coerce.boolean()` does `Boolean(val)` under the hood,
|
|
364
|
+
// which is not what we want. See:
|
|
365
|
+
// https://github.com/colinhacks/zod/issues/2985#issuecomment-2230692578
|
|
366
|
+
const booleanLike = zod_1.z.union([
|
|
367
|
+
zod_1.z.boolean(),
|
|
368
|
+
zod_1.z.number().pipe(zod_1.z.coerce.boolean()),
|
|
369
|
+
zod_1.z.preprocess(val => {
|
|
370
|
+
if (typeof val === 'string') {
|
|
371
|
+
if (val.toLowerCase() === 'true') {
|
|
372
|
+
return true;
|
|
373
|
+
}
|
|
374
|
+
if (val.toLowerCase() === 'false') {
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return val;
|
|
379
|
+
}, zod_1.z.boolean()),
|
|
380
|
+
]);
|
|
381
|
+
const stringLike = zod_1.z
|
|
382
|
+
.union([
|
|
383
|
+
// We're going to coerce numbers and strings into strings.
|
|
384
|
+
zod_1.z.number(),
|
|
385
|
+
zod_1.z.string(),
|
|
386
|
+
// We do not allow other primitives, like:
|
|
387
|
+
// - bigints, symbols - because YAML does not support them,
|
|
388
|
+
// - booleans - because YAML accepts `True` and `true` as boolean input
|
|
389
|
+
// and parses both as JS `true` -- if we stringified that,
|
|
390
|
+
// we would lose the capital "T" which may not be what the user expects,
|
|
391
|
+
// - nulls - user should do `"null"` or not pass the property at all.
|
|
392
|
+
])
|
|
393
|
+
.pipe(zod_1.z.coerce.string());
|
|
394
|
+
exports.WorkflowDispatchInputZ = zod_1.z
|
|
395
|
+
.object({
|
|
396
|
+
description: stringLike.optional().describe('Description of the input'),
|
|
397
|
+
required: booleanLike.default(false).describe('Whether the input is required'),
|
|
398
|
+
})
|
|
399
|
+
.and(zod_1.z.union([
|
|
400
|
+
zod_1.z.object({
|
|
401
|
+
type: zod_1.z.literal('string').default('string'),
|
|
402
|
+
default: stringLike.optional().describe('Default value for the input'),
|
|
403
|
+
}),
|
|
404
|
+
zod_1.z.object({
|
|
405
|
+
type: zod_1.z.literal('boolean'),
|
|
406
|
+
default: booleanLike.optional().describe('Default value for the input'),
|
|
407
|
+
}),
|
|
408
|
+
zod_1.z.object({
|
|
409
|
+
type: zod_1.z.literal('number'),
|
|
410
|
+
default: zod_1.z.number().optional().describe('Default value for the input'),
|
|
411
|
+
}),
|
|
412
|
+
zod_1.z.object({
|
|
413
|
+
type: zod_1.z.literal('choice'),
|
|
414
|
+
default: stringLike.optional().describe('Default value for the input'),
|
|
415
|
+
options: zod_1.z.array(stringLike).min(1).describe('Options for choice type inputs'),
|
|
416
|
+
}),
|
|
417
|
+
zod_1.z.object({
|
|
418
|
+
type: zod_1.z.literal('environment'),
|
|
419
|
+
default: zod_1.z.string().optional().describe('Default value for the input'),
|
|
420
|
+
}),
|
|
421
|
+
]));
|
|
422
|
+
function parseWorkflowInputsFromYaml(yamlConfig) {
|
|
423
|
+
try {
|
|
424
|
+
const parsed = YAML.parse(yamlConfig);
|
|
425
|
+
return zod_1.z
|
|
426
|
+
.record(zod_1.z.string(), exports.WorkflowDispatchInputZ)
|
|
427
|
+
.default({})
|
|
428
|
+
.parse(parsed?.on?.workflow_dispatch?.inputs);
|
|
429
|
+
}
|
|
430
|
+
catch (error) {
|
|
431
|
+
log_1.default.warn('Failed to parse workflow inputs from YAML:', error);
|
|
432
|
+
return {};
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
exports.parseWorkflowInputsFromYaml = parseWorkflowInputsFromYaml;
|
|
436
|
+
async function maybePromptForMissingInputsAsync({ inputSpecs, inputs, }) {
|
|
437
|
+
const requiredInputs = Object.entries(inputSpecs).filter(([_, spec]) => spec.required);
|
|
438
|
+
const missingRequiredInputs = requiredInputs.filter(([key]) => inputs[key] === undefined);
|
|
439
|
+
if (missingRequiredInputs.length === 0) {
|
|
440
|
+
return inputs;
|
|
441
|
+
}
|
|
442
|
+
log_1.default.addNewLineIfNone();
|
|
443
|
+
log_1.default.log('Some required inputs are missing. Please provide them:');
|
|
444
|
+
const nextInputs = { ...inputs };
|
|
445
|
+
for (const [key, spec] of missingRequiredInputs) {
|
|
446
|
+
const value = await promptForMissingInputAsync({ key, spec });
|
|
447
|
+
nextInputs[key] = value;
|
|
448
|
+
}
|
|
449
|
+
return nextInputs;
|
|
450
|
+
}
|
|
451
|
+
async function promptForMissingInputAsync({ key, spec, }) {
|
|
452
|
+
const message = spec.description ? `${key} (${spec.description})` : key;
|
|
453
|
+
switch (spec.type) {
|
|
454
|
+
case 'boolean': {
|
|
455
|
+
const { value } = await (0, prompts_1.promptAsync)({
|
|
456
|
+
type: 'confirm',
|
|
457
|
+
name: 'value',
|
|
458
|
+
message,
|
|
459
|
+
initial: spec.default,
|
|
460
|
+
});
|
|
461
|
+
return value;
|
|
462
|
+
}
|
|
463
|
+
case 'number': {
|
|
464
|
+
const { value } = await (0, prompts_1.promptAsync)({
|
|
465
|
+
type: 'number',
|
|
466
|
+
name: 'value',
|
|
467
|
+
message,
|
|
468
|
+
initial: spec.default,
|
|
469
|
+
validate: (val) => {
|
|
470
|
+
if (isNaN(val)) {
|
|
471
|
+
return 'Please enter a valid number';
|
|
472
|
+
}
|
|
473
|
+
return true;
|
|
474
|
+
},
|
|
475
|
+
});
|
|
476
|
+
return value;
|
|
477
|
+
}
|
|
478
|
+
case 'choice': {
|
|
479
|
+
const { value } = await (0, prompts_1.promptAsync)({
|
|
480
|
+
type: 'select',
|
|
481
|
+
name: 'value',
|
|
482
|
+
message,
|
|
483
|
+
choices: spec.options.map(option => ({
|
|
484
|
+
title: option,
|
|
485
|
+
value: option,
|
|
486
|
+
})),
|
|
487
|
+
initial: spec.default,
|
|
488
|
+
});
|
|
489
|
+
return value;
|
|
490
|
+
}
|
|
491
|
+
case 'string':
|
|
492
|
+
case 'environment': {
|
|
493
|
+
const { value } = await (0, prompts_1.promptAsync)({
|
|
494
|
+
type: 'text',
|
|
495
|
+
name: 'value',
|
|
496
|
+
message,
|
|
497
|
+
initial: spec.default,
|
|
498
|
+
validate: (val) => {
|
|
499
|
+
if (spec.required && (!val || val.trim() === '')) {
|
|
500
|
+
return 'This field is required';
|
|
501
|
+
}
|
|
502
|
+
return true;
|
|
503
|
+
},
|
|
504
|
+
});
|
|
505
|
+
return value;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
@@ -5,7 +5,7 @@ const core_1 = require("@oclif/core");
|
|
|
5
5
|
const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
|
|
6
6
|
const flags_1 = require("../../commandUtils/flags");
|
|
7
7
|
const pagination_1 = require("../../commandUtils/pagination");
|
|
8
|
-
const
|
|
8
|
+
const utils_1 = require("../../commandUtils/workflow/utils");
|
|
9
9
|
const generated_1 = require("../../graphql/generated");
|
|
10
10
|
const AppQuery_1 = require("../../graphql/queries/AppQuery");
|
|
11
11
|
const WorkflowRunQuery_1 = require("../../graphql/queries/WorkflowRunQuery");
|
|
@@ -49,7 +49,7 @@ class WorkflowRunList extends EasCommand_1.default {
|
|
|
49
49
|
else {
|
|
50
50
|
runs = await AppQuery_1.AppQuery.byIdWorkflowRunsFilteredByStatusAsync(graphqlClient, projectId, status, limit);
|
|
51
51
|
}
|
|
52
|
-
const result = (0,
|
|
52
|
+
const result = (0, utils_1.processWorkflowRuns)(runs);
|
|
53
53
|
if (flags.json) {
|
|
54
54
|
(0, json_1.printJsonOnlyOutput)(result);
|
|
55
55
|
return;
|
|
@@ -62,8 +62,9 @@ class WorkflowRunList extends EasCommand_1.default {
|
|
|
62
62
|
{ label: 'Status', value: run.status },
|
|
63
63
|
{ label: 'Started At', value: run.startedAt },
|
|
64
64
|
{ label: 'Finished At', value: run.finishedAt },
|
|
65
|
+
{ label: 'Trigger Type', value: run.triggerType },
|
|
66
|
+
{ label: 'Trigger', value: run.trigger ?? 'null' },
|
|
65
67
|
{ label: 'Git Commit Message', value: run.gitCommitMessage ?? 'null' },
|
|
66
|
-
{ label: 'Git Commit Hash', value: run.gitCommitHash ?? 'null' },
|
|
67
68
|
]));
|
|
68
69
|
log_1.default.addNewLineIfNone();
|
|
69
70
|
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import EasCommand from '../../commandUtils/EasCommand';
|
|
2
|
+
export default class WorkflowView extends EasCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
'non-interactive': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
6
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
};
|
|
8
|
+
static args: {
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
}[];
|
|
12
|
+
static contextDefinition: {
|
|
13
|
+
loggedIn: import("../../commandUtils/context/LoggedInContextField").default;
|
|
14
|
+
projectId: import("../../commandUtils/context/ProjectIdContextField").ProjectIdContextField;
|
|
15
|
+
};
|
|
16
|
+
runAsync(): Promise<void>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const url_1 = require("../../build/utils/url");
|
|
5
|
+
const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
|
|
6
|
+
const flags_1 = require("../../commandUtils/flags");
|
|
7
|
+
const stateMachine_1 = require("../../commandUtils/workflow/stateMachine");
|
|
8
|
+
const utils_1 = require("../../commandUtils/workflow/utils");
|
|
9
|
+
const WorkflowRunQuery_1 = require("../../graphql/queries/WorkflowRunQuery");
|
|
10
|
+
const log_1 = tslib_1.__importStar(require("../../log"));
|
|
11
|
+
const formatFields_1 = tslib_1.__importDefault(require("../../utils/formatFields"));
|
|
12
|
+
const json_1 = require("../../utils/json");
|
|
13
|
+
class WorkflowView extends EasCommand_1.default {
|
|
14
|
+
static description = 'view details for a workflow run, including jobs. If no run ID is provided, you will be prompted to select from recent workflow runs for the current project.';
|
|
15
|
+
static flags = {
|
|
16
|
+
...flags_1.EasJsonOnlyFlag,
|
|
17
|
+
...flags_1.EASNonInteractiveFlag,
|
|
18
|
+
};
|
|
19
|
+
static args = [{ name: 'id', description: 'ID of the workflow run to view' }];
|
|
20
|
+
static contextDefinition = {
|
|
21
|
+
...this.ContextOptions.ProjectId,
|
|
22
|
+
...this.ContextOptions.LoggedIn,
|
|
23
|
+
};
|
|
24
|
+
async runAsync() {
|
|
25
|
+
const { args, flags } = await this.parse(WorkflowView);
|
|
26
|
+
const nonInteractive = flags['non-interactive'];
|
|
27
|
+
const { loggedIn: { graphqlClient }, projectId, } = await this.getContextAsync(WorkflowView, {
|
|
28
|
+
nonInteractive,
|
|
29
|
+
});
|
|
30
|
+
if (flags.json) {
|
|
31
|
+
(0, json_1.enableJsonOutput)();
|
|
32
|
+
}
|
|
33
|
+
if (nonInteractive && !args.id) {
|
|
34
|
+
throw new Error('If non-interactive, this command requires a workflow run ID as argument');
|
|
35
|
+
}
|
|
36
|
+
const actionResult = await (0, stateMachine_1.workflowRunSelectionAction)({
|
|
37
|
+
graphqlClient,
|
|
38
|
+
projectId,
|
|
39
|
+
nonInteractive,
|
|
40
|
+
allSteps: false,
|
|
41
|
+
state: stateMachine_1.WorkflowCommandSelectionStateValue.WORKFLOW_RUN_SELECTION,
|
|
42
|
+
runId: args.id,
|
|
43
|
+
});
|
|
44
|
+
if (actionResult.state === stateMachine_1.WorkflowCommandSelectionStateValue.ERROR) {
|
|
45
|
+
log_1.default.error(actionResult.message);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const idToQuery = actionResult.runId ?? '';
|
|
49
|
+
const result = await WorkflowRunQuery_1.WorkflowRunQuery.withJobsByIdAsync(graphqlClient, idToQuery, {
|
|
50
|
+
useCache: false,
|
|
51
|
+
});
|
|
52
|
+
const { triggerType, trigger } = (0, utils_1.computeTriggerInfoForWorkflowRun)(result);
|
|
53
|
+
result.triggerType = triggerType;
|
|
54
|
+
result.trigger = trigger;
|
|
55
|
+
result.jobs.forEach(job => {
|
|
56
|
+
delete job.turtleJobRun;
|
|
57
|
+
});
|
|
58
|
+
result.logURL = (0, url_1.getWorkflowRunUrl)(result.workflow.app.ownerAccount.name, result.workflow.app.name, result.id);
|
|
59
|
+
if (flags.json) {
|
|
60
|
+
(0, json_1.printJsonOnlyOutput)(result);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
log_1.default.log((0, formatFields_1.default)([
|
|
64
|
+
{ label: 'Run ID', value: result.id },
|
|
65
|
+
{ label: 'Workflow', value: result.workflow.fileName },
|
|
66
|
+
{ label: 'Trigger Type', value: result.triggerType },
|
|
67
|
+
{ label: 'Trigger', value: result.trigger ?? 'null' },
|
|
68
|
+
{
|
|
69
|
+
label: 'Git Commit Message',
|
|
70
|
+
value: result.gitCommitMessage?.split('\n')[0] ?? null ?? 'null',
|
|
71
|
+
},
|
|
72
|
+
{ label: 'Status', value: result.status },
|
|
73
|
+
{ label: 'Errors', value: result.errors.map(error => error.title).join('\n') },
|
|
74
|
+
{ label: 'Created At', value: result.createdAt },
|
|
75
|
+
{ label: 'Updated At', value: result.updatedAt },
|
|
76
|
+
{ label: 'Log URL', value: (0, log_1.link)(result.logURL) },
|
|
77
|
+
]));
|
|
78
|
+
log_1.default.addNewLineIfNone();
|
|
79
|
+
result.jobs.forEach(job => {
|
|
80
|
+
log_1.default.log((0, formatFields_1.default)([
|
|
81
|
+
{ label: 'Job ID', value: job.id },
|
|
82
|
+
{ label: ' Key', value: job.key },
|
|
83
|
+
{ label: ' Name', value: job.name },
|
|
84
|
+
{ label: ' Status', value: job.status },
|
|
85
|
+
{ label: ' Type', value: job.type },
|
|
86
|
+
{ label: ' Created At', value: job.createdAt },
|
|
87
|
+
{ label: ' Updated At', value: job.updatedAt },
|
|
88
|
+
{ label: ' Outputs', value: JSON.stringify(job.outputs, null, 2) },
|
|
89
|
+
{ label: ' Errors', value: job.errors.map(error => error.title).join('\n') },
|
|
90
|
+
]));
|
|
91
|
+
log_1.default.addNewLineIfNone();
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.default = WorkflowView;
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
/// <reference types="@expo/apple-utils/ts-declarations/expo__app-store" />
|
|
2
|
-
import { BundleId
|
|
3
|
-
import { JSONObject
|
|
2
|
+
import { BundleId } from '@expo/apple-utils';
|
|
3
|
+
import { JSONObject } from '@expo/json-file';
|
|
4
|
+
import { CapabilityClassifier } from './capabilityList';
|
|
4
5
|
export declare const EXPO_NO_CAPABILITY_SYNC: boolean;
|
|
5
|
-
type GetOptionsMethod<T extends CapabilityType = any> = (entitlement: JSONValue, entitlementsJson: JSONObject, additionalOptions: {
|
|
6
|
-
usesBroadcastPushNotifications?: boolean;
|
|
7
|
-
}) => CapabilityOptionMap[T];
|
|
8
6
|
/**
|
|
9
7
|
* Given an entitlements JSON object, synchronizes the remote capabilities for a bundle identifier.
|
|
10
8
|
*
|
|
@@ -18,6 +16,7 @@ type GetOptionsMethod<T extends CapabilityType = any> = (entitlement: JSONValue,
|
|
|
18
16
|
*
|
|
19
17
|
* @param bundleId bundle identifier object
|
|
20
18
|
* @param entitlements JSON representation of the entitlements plist
|
|
19
|
+
* @param additionalOptions Additional options to consider when syncing capabilities.
|
|
21
20
|
* @returns
|
|
22
21
|
*/
|
|
23
22
|
export declare function syncCapabilitiesForEntitlementsAsync(bundleId: BundleId, entitlements: JSONObject | undefined, additionalOptions: {
|
|
@@ -27,15 +26,3 @@ export declare function syncCapabilitiesForEntitlementsAsync(bundleId: BundleId,
|
|
|
27
26
|
disabled: string[];
|
|
28
27
|
}>;
|
|
29
28
|
export declare function assertValidOptions(classifier: CapabilityClassifier, value: any): asserts value;
|
|
30
|
-
type CapabilityClassifier = {
|
|
31
|
-
name: string;
|
|
32
|
-
entitlement: string;
|
|
33
|
-
capability: CapabilityType;
|
|
34
|
-
validateOptions: (options: any) => boolean;
|
|
35
|
-
getOptions: GetOptionsMethod;
|
|
36
|
-
capabilityIdModel?: typeof MerchantId;
|
|
37
|
-
capabilityIdPrefix?: string;
|
|
38
|
-
options?: undefined;
|
|
39
|
-
};
|
|
40
|
-
export declare const CapabilityMapping: CapabilityClassifier[];
|
|
41
|
-
export {};
|