eas-cli 16.14.1 → 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/deploy/index.js +47 -49
- 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 +19 -16
- package/build/worker/assets.js +51 -22
- package/build/worker/upload.d.ts +21 -9
- package/build/worker/upload.js +98 -80
- package/build/worker/utils/multipart.d.ts +11 -0
- package/build/worker/utils/multipart.js +98 -0
- 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
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fetchRawLogsForJobAsync = void 0;
|
|
4
|
+
// This function is in a separate module for testing purposes
|
|
5
|
+
async function fetchRawLogsForJobAsync(job) {
|
|
6
|
+
const firstLogFileUrl = job.turtleJobRun?.logFileUrls?.[0];
|
|
7
|
+
if (!firstLogFileUrl) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
const response = await fetch(firstLogFileUrl, {
|
|
11
|
+
method: 'GET',
|
|
12
|
+
});
|
|
13
|
+
const rawLogs = await response.text();
|
|
14
|
+
return rawLogs;
|
|
15
|
+
}
|
|
16
|
+
exports.fetchRawLogsForJobAsync = fetchRawLogsForJobAsync;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { WorkflowJobResult, WorkflowLogs } from './types';
|
|
2
|
+
import { ExpoGraphqlClient } from '../context/contextUtils/createGraphqlClient';
|
|
3
|
+
export declare enum WorkflowCommandSelectionStateValue {
|
|
4
|
+
WORKFLOW_RUN_SELECTION = "WORKFLOW_RUN_SELECTION",
|
|
5
|
+
WORKFLOW_JOB_SELECTION = "WORKFLOW_JOB_SELECTION",
|
|
6
|
+
WORKFLOW_STEP_SELECTION = "WORKFLOW_STEP_SELECTION",
|
|
7
|
+
FINISH = "FINISH",
|
|
8
|
+
ERROR = "ERROR"
|
|
9
|
+
}
|
|
10
|
+
export type WorkflowCommandSelectionState = {
|
|
11
|
+
graphqlClient: ExpoGraphqlClient;
|
|
12
|
+
projectId: string;
|
|
13
|
+
nonInteractive: boolean;
|
|
14
|
+
allSteps: boolean;
|
|
15
|
+
state: WorkflowCommandSelectionStateValue;
|
|
16
|
+
runId?: string;
|
|
17
|
+
jobId?: string;
|
|
18
|
+
step?: string;
|
|
19
|
+
job?: WorkflowJobResult;
|
|
20
|
+
logs?: WorkflowLogs | null;
|
|
21
|
+
message?: string;
|
|
22
|
+
};
|
|
23
|
+
export type WorkflowCommandSelectionStateParameters = Omit<WorkflowCommandSelectionState, 'graphqlClient' | 'projectId' | 'state' | 'nonInteractive' | 'allSteps'>;
|
|
24
|
+
export type WorkflowCommandSelectionAction = (prevState: WorkflowCommandSelectionState) => Promise<WorkflowCommandSelectionState>;
|
|
25
|
+
export declare function moveToNewWorkflowCommandSelectionState(previousState: WorkflowCommandSelectionState, newStateValue: WorkflowCommandSelectionStateValue, parameters: WorkflowCommandSelectionStateParameters): WorkflowCommandSelectionState;
|
|
26
|
+
export declare function moveToWorkflowRunSelectionState(previousState: WorkflowCommandSelectionState, params?: {
|
|
27
|
+
runId?: string | undefined;
|
|
28
|
+
}): WorkflowCommandSelectionState;
|
|
29
|
+
export declare function moveToWorkflowJobSelectionState(previousState: WorkflowCommandSelectionState, params: {
|
|
30
|
+
jobId?: string | undefined;
|
|
31
|
+
runId?: string | undefined;
|
|
32
|
+
}): WorkflowCommandSelectionState;
|
|
33
|
+
export declare function moveToWorkflowStepSelectionState(previousState: WorkflowCommandSelectionState, params: {
|
|
34
|
+
job: WorkflowJobResult;
|
|
35
|
+
}): WorkflowCommandSelectionState;
|
|
36
|
+
export declare function moveToWorkflowSelectionFinishedState(previousState: WorkflowCommandSelectionState, params: {
|
|
37
|
+
step: string;
|
|
38
|
+
logs: WorkflowLogs;
|
|
39
|
+
}): WorkflowCommandSelectionState;
|
|
40
|
+
export declare function moveToWorkflowSelectionErrorState(previousState: WorkflowCommandSelectionState, message: string): WorkflowCommandSelectionState;
|
|
41
|
+
export declare const workflowRunSelectionAction: WorkflowCommandSelectionAction;
|
|
42
|
+
export declare const workflowJobSelectionAction: WorkflowCommandSelectionAction;
|
|
43
|
+
export declare const workflowStepSelectionAction: WorkflowCommandSelectionAction;
|
|
44
|
+
export declare const executeWorkflowSelectionActionsAsync: WorkflowCommandSelectionAction;
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.executeWorkflowSelectionActionsAsync = exports.workflowStepSelectionAction = exports.workflowJobSelectionAction = exports.workflowRunSelectionAction = exports.moveToWorkflowSelectionErrorState = exports.moveToWorkflowSelectionFinishedState = exports.moveToWorkflowStepSelectionState = exports.moveToWorkflowJobSelectionState = exports.moveToWorkflowRunSelectionState = exports.moveToNewWorkflowCommandSelectionState = exports.WorkflowCommandSelectionStateValue = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
const AppQuery_1 = require("../../graphql/queries/AppQuery");
|
|
7
|
+
const WorkflowJobQuery_1 = require("../../graphql/queries/WorkflowJobQuery");
|
|
8
|
+
const WorkflowRunQuery_1 = require("../../graphql/queries/WorkflowRunQuery");
|
|
9
|
+
const log_1 = tslib_1.__importDefault(require("../../log"));
|
|
10
|
+
const prompts_1 = require("../../prompts");
|
|
11
|
+
/*
|
|
12
|
+
* State machine types and functions for moving between different workflow command states
|
|
13
|
+
*/
|
|
14
|
+
var WorkflowCommandSelectionStateValue;
|
|
15
|
+
(function (WorkflowCommandSelectionStateValue) {
|
|
16
|
+
WorkflowCommandSelectionStateValue["WORKFLOW_RUN_SELECTION"] = "WORKFLOW_RUN_SELECTION";
|
|
17
|
+
WorkflowCommandSelectionStateValue["WORKFLOW_JOB_SELECTION"] = "WORKFLOW_JOB_SELECTION";
|
|
18
|
+
WorkflowCommandSelectionStateValue["WORKFLOW_STEP_SELECTION"] = "WORKFLOW_STEP_SELECTION";
|
|
19
|
+
WorkflowCommandSelectionStateValue["FINISH"] = "FINISH";
|
|
20
|
+
WorkflowCommandSelectionStateValue["ERROR"] = "ERROR";
|
|
21
|
+
})(WorkflowCommandSelectionStateValue || (exports.WorkflowCommandSelectionStateValue = WorkflowCommandSelectionStateValue = {}));
|
|
22
|
+
const workflowCommandSelectionAllowedStateTransitions = {
|
|
23
|
+
WORKFLOW_JOB_SELECTION: [
|
|
24
|
+
WorkflowCommandSelectionStateValue.WORKFLOW_STEP_SELECTION,
|
|
25
|
+
WorkflowCommandSelectionStateValue.WORKFLOW_RUN_SELECTION,
|
|
26
|
+
WorkflowCommandSelectionStateValue.ERROR,
|
|
27
|
+
WorkflowCommandSelectionStateValue.FINISH,
|
|
28
|
+
],
|
|
29
|
+
WORKFLOW_RUN_SELECTION: [
|
|
30
|
+
WorkflowCommandSelectionStateValue.WORKFLOW_JOB_SELECTION,
|
|
31
|
+
WorkflowCommandSelectionStateValue.ERROR,
|
|
32
|
+
],
|
|
33
|
+
WORKFLOW_STEP_SELECTION: [
|
|
34
|
+
WorkflowCommandSelectionStateValue.WORKFLOW_JOB_SELECTION,
|
|
35
|
+
WorkflowCommandSelectionStateValue.ERROR,
|
|
36
|
+
WorkflowCommandSelectionStateValue.FINISH,
|
|
37
|
+
],
|
|
38
|
+
ERROR: [WorkflowCommandSelectionStateValue.WORKFLOW_RUN_SELECTION],
|
|
39
|
+
FINISH: [],
|
|
40
|
+
};
|
|
41
|
+
function moveToNewWorkflowCommandSelectionState(previousState, newStateValue, parameters) {
|
|
42
|
+
if (!workflowCommandSelectionAllowedStateTransitions[previousState.state].includes(newStateValue)) {
|
|
43
|
+
const errorMessage = `Invalid state transition from ${previousState.state} to ${newStateValue}. Allowed transitions from ${previousState.state}: ${workflowCommandSelectionAllowedStateTransitions[previousState.state].join(', ')}`;
|
|
44
|
+
throw new Error(errorMessage);
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
...previousState,
|
|
48
|
+
state: newStateValue,
|
|
49
|
+
...parameters,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
exports.moveToNewWorkflowCommandSelectionState = moveToNewWorkflowCommandSelectionState;
|
|
53
|
+
function moveToWorkflowRunSelectionState(previousState, params) {
|
|
54
|
+
return moveToNewWorkflowCommandSelectionState(previousState, WorkflowCommandSelectionStateValue.WORKFLOW_RUN_SELECTION, {
|
|
55
|
+
runId: params?.runId,
|
|
56
|
+
jobId: undefined,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
exports.moveToWorkflowRunSelectionState = moveToWorkflowRunSelectionState;
|
|
60
|
+
function moveToWorkflowJobSelectionState(previousState, params) {
|
|
61
|
+
return moveToNewWorkflowCommandSelectionState(previousState, WorkflowCommandSelectionStateValue.WORKFLOW_JOB_SELECTION, params);
|
|
62
|
+
}
|
|
63
|
+
exports.moveToWorkflowJobSelectionState = moveToWorkflowJobSelectionState;
|
|
64
|
+
function moveToWorkflowStepSelectionState(previousState, params) {
|
|
65
|
+
return moveToNewWorkflowCommandSelectionState(previousState, WorkflowCommandSelectionStateValue.WORKFLOW_STEP_SELECTION, params);
|
|
66
|
+
}
|
|
67
|
+
exports.moveToWorkflowStepSelectionState = moveToWorkflowStepSelectionState;
|
|
68
|
+
function moveToWorkflowSelectionFinishedState(previousState, params) {
|
|
69
|
+
return moveToNewWorkflowCommandSelectionState(previousState, WorkflowCommandSelectionStateValue.FINISH, params);
|
|
70
|
+
}
|
|
71
|
+
exports.moveToWorkflowSelectionFinishedState = moveToWorkflowSelectionFinishedState;
|
|
72
|
+
function moveToWorkflowSelectionErrorState(previousState, message) {
|
|
73
|
+
return moveToNewWorkflowCommandSelectionState(previousState, WorkflowCommandSelectionStateValue.ERROR, {
|
|
74
|
+
message,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
exports.moveToWorkflowSelectionErrorState = moveToWorkflowSelectionErrorState;
|
|
78
|
+
// eslint-disable-next-line async-protect/async-suffix
|
|
79
|
+
const workflowRunSelectionAction = async (prevState) => {
|
|
80
|
+
const { graphqlClient, projectId, runId, jobId, allSteps } = prevState;
|
|
81
|
+
log_1.default.debug(`workflowRunSelectionAction: runId = ${runId}, jobId = ${jobId}, allSteps = ${allSteps}`);
|
|
82
|
+
if (runId) {
|
|
83
|
+
return moveToWorkflowJobSelectionState(prevState, { runId });
|
|
84
|
+
}
|
|
85
|
+
const runs = await AppQuery_1.AppQuery.byIdWorkflowRunsFilteredByStatusAsync(graphqlClient, projectId, undefined, 20);
|
|
86
|
+
if (runs.length === 0) {
|
|
87
|
+
return moveToWorkflowSelectionErrorState(prevState, 'No workflow runs found');
|
|
88
|
+
}
|
|
89
|
+
const processedRuns = (0, utils_1.processWorkflowRuns)(runs);
|
|
90
|
+
const choices = processedRuns.map(run => (0, utils_1.choiceFromWorkflowRun)(run));
|
|
91
|
+
const selectedId = (await (0, prompts_1.promptAsync)({
|
|
92
|
+
type: 'select',
|
|
93
|
+
name: 'selectedRun',
|
|
94
|
+
message: 'Select a workflow run:',
|
|
95
|
+
choices,
|
|
96
|
+
})).selectedRun;
|
|
97
|
+
return moveToWorkflowJobSelectionState(prevState, { runId: selectedId });
|
|
98
|
+
};
|
|
99
|
+
exports.workflowRunSelectionAction = workflowRunSelectionAction;
|
|
100
|
+
// eslint-disable-next-line async-protect/async-suffix
|
|
101
|
+
const workflowJobSelectionAction = async (prevState) => {
|
|
102
|
+
const { graphqlClient, runId, jobId, nonInteractive, allSteps } = prevState;
|
|
103
|
+
log_1.default.debug(`workflowJobSelectionAction: runId = ${runId}, jobId = ${jobId}, allSteps = ${allSteps}`);
|
|
104
|
+
if (jobId) {
|
|
105
|
+
let workflowJobResult = undefined;
|
|
106
|
+
try {
|
|
107
|
+
workflowJobResult = await WorkflowJobQuery_1.WorkflowJobQuery.byIdAsync(graphqlClient, jobId, {
|
|
108
|
+
useCache: false,
|
|
109
|
+
});
|
|
110
|
+
return moveToWorkflowStepSelectionState(prevState, { job: workflowJobResult });
|
|
111
|
+
}
|
|
112
|
+
catch { }
|
|
113
|
+
if (nonInteractive && !workflowJobResult) {
|
|
114
|
+
return moveToWorkflowSelectionErrorState(prevState, 'No workflow job found that matched the provided ID');
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
// The passed in ID may be a run ID, pass it back to run selection action
|
|
118
|
+
return moveToWorkflowRunSelectionState(prevState, { runId: jobId });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
// No job ID was passed in
|
|
123
|
+
if (nonInteractive) {
|
|
124
|
+
return moveToWorkflowSelectionErrorState(prevState, 'No workflow job ID provided in non-interactive mode');
|
|
125
|
+
}
|
|
126
|
+
else if (!runId) {
|
|
127
|
+
// If no jobId or runId, we should go back to run selection
|
|
128
|
+
return moveToWorkflowRunSelectionState(prevState);
|
|
129
|
+
}
|
|
130
|
+
const workflowRunResult = await WorkflowRunQuery_1.WorkflowRunQuery.withJobsByIdAsync(graphqlClient, runId, {
|
|
131
|
+
useCache: false,
|
|
132
|
+
});
|
|
133
|
+
if (!workflowRunResult) {
|
|
134
|
+
return moveToWorkflowSelectionErrorState(prevState, 'No workflow run found that matched the provided ID');
|
|
135
|
+
}
|
|
136
|
+
const choices = [
|
|
137
|
+
...workflowRunResult.jobs.map((job, i) => (0, utils_1.choiceFromWorkflowJob)(job, i)),
|
|
138
|
+
{
|
|
139
|
+
title: 'Go back and select a different workflow run',
|
|
140
|
+
value: -1,
|
|
141
|
+
},
|
|
142
|
+
];
|
|
143
|
+
const selectedJobIndex = (await (0, prompts_1.promptAsync)({
|
|
144
|
+
type: 'select',
|
|
145
|
+
name: 'selectedJob',
|
|
146
|
+
message: 'Select a job:',
|
|
147
|
+
choices,
|
|
148
|
+
})).selectedJob;
|
|
149
|
+
if (selectedJobIndex === -1) {
|
|
150
|
+
return moveToWorkflowRunSelectionState(prevState);
|
|
151
|
+
}
|
|
152
|
+
const selectedJob = workflowRunResult.jobs[selectedJobIndex];
|
|
153
|
+
return moveToWorkflowStepSelectionState(prevState, { job: selectedJob });
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
exports.workflowJobSelectionAction = workflowJobSelectionAction;
|
|
157
|
+
// eslint-disable-next-line async-protect/async-suffix
|
|
158
|
+
const workflowStepSelectionAction = async (prevState) => {
|
|
159
|
+
const { job, allSteps } = prevState;
|
|
160
|
+
log_1.default.debug(`workflowStepSelectionAction: job = ${job?.id}, allSteps = ${allSteps}`);
|
|
161
|
+
if (!job) {
|
|
162
|
+
return moveToWorkflowSelectionErrorState(prevState, 'No job found');
|
|
163
|
+
}
|
|
164
|
+
const logs = await (0, utils_1.processLogsFromJobAsync)(job);
|
|
165
|
+
if (!logs) {
|
|
166
|
+
return moveToWorkflowSelectionErrorState(prevState, 'No logs found');
|
|
167
|
+
}
|
|
168
|
+
if (allSteps) {
|
|
169
|
+
return moveToWorkflowSelectionFinishedState(prevState, { step: '', logs });
|
|
170
|
+
}
|
|
171
|
+
const choices = [
|
|
172
|
+
...(0, utils_1.choicesFromWorkflowLogs)(logs),
|
|
173
|
+
{
|
|
174
|
+
title: 'Go back and select a different workflow job',
|
|
175
|
+
value: 'go-back',
|
|
176
|
+
},
|
|
177
|
+
];
|
|
178
|
+
const selectedStep = (await (0, prompts_1.promptAsync)({
|
|
179
|
+
type: 'select',
|
|
180
|
+
name: 'selectedStep',
|
|
181
|
+
message: 'Select a step:',
|
|
182
|
+
choices,
|
|
183
|
+
})).selectedStep ?? '';
|
|
184
|
+
if (selectedStep === 'go-back') {
|
|
185
|
+
return moveToWorkflowJobSelectionState(prevState, {
|
|
186
|
+
runId: job.workflowRun.id,
|
|
187
|
+
jobId: undefined,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
return moveToWorkflowSelectionFinishedState(prevState, { step: selectedStep, logs });
|
|
191
|
+
};
|
|
192
|
+
exports.workflowStepSelectionAction = workflowStepSelectionAction;
|
|
193
|
+
const executeWorkflowSelectionActionsAsync = async (prevState) => {
|
|
194
|
+
let currentState = prevState;
|
|
195
|
+
while (currentState.state !== WorkflowCommandSelectionStateValue.FINISH &&
|
|
196
|
+
currentState.state !== WorkflowCommandSelectionStateValue.ERROR) {
|
|
197
|
+
log_1.default.debug(`${currentState.state}`);
|
|
198
|
+
switch (currentState.state) {
|
|
199
|
+
case WorkflowCommandSelectionStateValue.WORKFLOW_JOB_SELECTION:
|
|
200
|
+
currentState = await (0, exports.workflowJobSelectionAction)(currentState);
|
|
201
|
+
break;
|
|
202
|
+
case WorkflowCommandSelectionStateValue.WORKFLOW_RUN_SELECTION:
|
|
203
|
+
currentState = await (0, exports.workflowRunSelectionAction)(currentState);
|
|
204
|
+
break;
|
|
205
|
+
case WorkflowCommandSelectionStateValue.WORKFLOW_STEP_SELECTION:
|
|
206
|
+
currentState = await (0, exports.workflowStepSelectionAction)(currentState);
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return currentState;
|
|
211
|
+
};
|
|
212
|
+
exports.executeWorkflowSelectionActionsAsync = executeWorkflowSelectionActionsAsync;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { WorkflowJobByIdQuery, WorkflowRunByIdWithJobsQuery } from '../../graphql/generated';
|
|
2
|
+
export declare enum WorkflowTriggerType {
|
|
3
|
+
MANUAL = "Manual",
|
|
4
|
+
GITHUB = "GitHub",
|
|
5
|
+
SCHEDULED = "Scheduled",
|
|
6
|
+
OTHER = "Other"
|
|
7
|
+
}
|
|
8
|
+
export type WorkflowRunResult = {
|
|
9
|
+
id: string;
|
|
10
|
+
status: string;
|
|
11
|
+
gitCommitMessage: string | null;
|
|
12
|
+
gitCommitHash: string | null;
|
|
13
|
+
triggerType: WorkflowTriggerType;
|
|
14
|
+
trigger: string | null;
|
|
15
|
+
startedAt: string;
|
|
16
|
+
finishedAt: string;
|
|
17
|
+
workflowId: string;
|
|
18
|
+
workflowName: string | null;
|
|
19
|
+
workflowFileName: string;
|
|
20
|
+
};
|
|
21
|
+
export type WorkflowResult = {
|
|
22
|
+
id: string;
|
|
23
|
+
name?: string | null | undefined;
|
|
24
|
+
fileName: string;
|
|
25
|
+
createdAt: string;
|
|
26
|
+
updatedAt: string;
|
|
27
|
+
};
|
|
28
|
+
export type WorkflowJobResult = WorkflowRunByIdWithJobsQuery['workflowRuns']['byId']['jobs'][number] | WorkflowJobByIdQuery['workflowJobs']['byId'];
|
|
29
|
+
export type WorkflowRunWithJobsResult = WorkflowRunResult & {
|
|
30
|
+
jobs: WorkflowJobResult[];
|
|
31
|
+
logs?: string;
|
|
32
|
+
};
|
|
33
|
+
export type WorkflowLogLine = {
|
|
34
|
+
time: string;
|
|
35
|
+
msg: string;
|
|
36
|
+
result?: string;
|
|
37
|
+
marker?: string;
|
|
38
|
+
};
|
|
39
|
+
export type WorkflowLogs = Map<string, WorkflowLogLine[]>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WorkflowTriggerType = void 0;
|
|
4
|
+
/*
|
|
5
|
+
* Utility types for workflow commands
|
|
6
|
+
*/
|
|
7
|
+
var WorkflowTriggerType;
|
|
8
|
+
(function (WorkflowTriggerType) {
|
|
9
|
+
WorkflowTriggerType["MANUAL"] = "Manual";
|
|
10
|
+
WorkflowTriggerType["GITHUB"] = "GitHub";
|
|
11
|
+
WorkflowTriggerType["SCHEDULED"] = "Scheduled";
|
|
12
|
+
WorkflowTriggerType["OTHER"] = "Other";
|
|
13
|
+
})(WorkflowTriggerType || (exports.WorkflowTriggerType = WorkflowTriggerType = {}));
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { WorkflowJobResult, WorkflowLogs, WorkflowRunResult, WorkflowTriggerType } from './types';
|
|
2
|
+
import { WorkflowRunFragment } from '../../graphql/generated';
|
|
3
|
+
import { Choice } from '../../prompts';
|
|
4
|
+
export declare function computeTriggerInfoForWorkflowRun(run: WorkflowRunFragment): {
|
|
5
|
+
triggerType: WorkflowTriggerType;
|
|
6
|
+
trigger: string | null;
|
|
7
|
+
};
|
|
8
|
+
export declare function choiceFromWorkflowRun(run: WorkflowRunResult): Choice;
|
|
9
|
+
export declare function choiceFromWorkflowJob(job: WorkflowJobResult, index: number): Choice;
|
|
10
|
+
export declare function choicesFromWorkflowLogs(logs: WorkflowLogs): Choice[];
|
|
11
|
+
export declare function processWorkflowRuns(runs: WorkflowRunFragment[]): WorkflowRunResult[];
|
|
12
|
+
export declare function processLogsFromJobAsync(job: WorkflowJobResult): Promise<WorkflowLogs | null>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.processLogsFromJobAsync = exports.processWorkflowRuns = exports.choicesFromWorkflowLogs = exports.choiceFromWorkflowJob = exports.choiceFromWorkflowRun = exports.computeTriggerInfoForWorkflowRun = void 0;
|
|
4
|
+
const fetchLogs_1 = require("./fetchLogs");
|
|
5
|
+
const types_1 = require("./types");
|
|
6
|
+
const generated_1 = require("../../graphql/generated");
|
|
7
|
+
function computeTriggerInfoForWorkflowRun(run) {
|
|
8
|
+
let triggerType = types_1.WorkflowTriggerType.OTHER;
|
|
9
|
+
let trigger = '';
|
|
10
|
+
if (run.actor?.__typename === 'Robot') {
|
|
11
|
+
if (run.actor.firstName?.startsWith('GitHub App · ')) {
|
|
12
|
+
trigger = `${run.requestedGitRef ?? ''}@${run.gitCommitHash?.substring(0, 12) ?? ''}`;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
else if (run.actor?.__typename === 'User') {
|
|
16
|
+
trigger = run.actor.username;
|
|
17
|
+
}
|
|
18
|
+
switch (run.triggerEventType) {
|
|
19
|
+
case generated_1.WorkflowRunTriggerEventType.Manual:
|
|
20
|
+
triggerType = types_1.WorkflowTriggerType.MANUAL;
|
|
21
|
+
break;
|
|
22
|
+
case generated_1.WorkflowRunTriggerEventType.GithubPullRequestLabeled:
|
|
23
|
+
case generated_1.WorkflowRunTriggerEventType.GithubPullRequestOpened:
|
|
24
|
+
case generated_1.WorkflowRunTriggerEventType.GithubPullRequestReopened:
|
|
25
|
+
case generated_1.WorkflowRunTriggerEventType.GithubPullRequestSynchronize:
|
|
26
|
+
case generated_1.WorkflowRunTriggerEventType.GithubPush:
|
|
27
|
+
triggerType = types_1.WorkflowTriggerType.GITHUB;
|
|
28
|
+
break;
|
|
29
|
+
case generated_1.WorkflowRunTriggerEventType.Schedule:
|
|
30
|
+
triggerType = types_1.WorkflowTriggerType.SCHEDULED;
|
|
31
|
+
trigger = run.triggeringSchedule ?? '';
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
return { triggerType, trigger };
|
|
35
|
+
}
|
|
36
|
+
exports.computeTriggerInfoForWorkflowRun = computeTriggerInfoForWorkflowRun;
|
|
37
|
+
function choiceFromWorkflowRun(run) {
|
|
38
|
+
const titleArray = [
|
|
39
|
+
run.workflowFileName,
|
|
40
|
+
run.status,
|
|
41
|
+
run.startedAt,
|
|
42
|
+
run.triggerType,
|
|
43
|
+
run.trigger,
|
|
44
|
+
];
|
|
45
|
+
return {
|
|
46
|
+
title: titleArray.join(' - '),
|
|
47
|
+
value: run.id,
|
|
48
|
+
description: `ID: ${run.id}, Message: ${run.gitCommitMessage?.split('\n')[0] ?? ''}`,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
exports.choiceFromWorkflowRun = choiceFromWorkflowRun;
|
|
52
|
+
function choiceFromWorkflowJob(job, index) {
|
|
53
|
+
return {
|
|
54
|
+
title: `${job.name} - ${job.status}`,
|
|
55
|
+
value: index,
|
|
56
|
+
description: `ID: ${job.id}`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
exports.choiceFromWorkflowJob = choiceFromWorkflowJob;
|
|
60
|
+
function choicesFromWorkflowLogs(logs) {
|
|
61
|
+
return Array.from(logs.keys()).map(step => {
|
|
62
|
+
const logLines = logs.get(step);
|
|
63
|
+
const stepStatus = logLines?.filter((line) => line.marker === 'end-step')[0]?.result ?? '';
|
|
64
|
+
return {
|
|
65
|
+
title: `${step} - ${stepStatus}`,
|
|
66
|
+
value: step,
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
exports.choicesFromWorkflowLogs = choicesFromWorkflowLogs;
|
|
71
|
+
function processWorkflowRuns(runs) {
|
|
72
|
+
return runs.map(run => {
|
|
73
|
+
const finishedAt = run.status === generated_1.WorkflowRunStatus.InProgress ? null : run.updatedAt;
|
|
74
|
+
const { triggerType, trigger } = computeTriggerInfoForWorkflowRun(run);
|
|
75
|
+
return {
|
|
76
|
+
id: run.id,
|
|
77
|
+
status: run.status,
|
|
78
|
+
gitCommitMessage: run.gitCommitMessage?.split('\n')[0] ?? null,
|
|
79
|
+
gitCommitHash: run.gitCommitHash ?? null,
|
|
80
|
+
startedAt: run.createdAt,
|
|
81
|
+
finishedAt,
|
|
82
|
+
triggerType,
|
|
83
|
+
trigger,
|
|
84
|
+
workflowId: run.workflow.id,
|
|
85
|
+
workflowName: run.workflow.name ?? null,
|
|
86
|
+
workflowFileName: run.workflow.fileName,
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
exports.processWorkflowRuns = processWorkflowRuns;
|
|
91
|
+
async function processLogsFromJobAsync(job) {
|
|
92
|
+
const rawLogs = await (0, fetchLogs_1.fetchRawLogsForJobAsync)(job);
|
|
93
|
+
if (!rawLogs) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const logs = new Map();
|
|
97
|
+
const logKeys = new Set();
|
|
98
|
+
rawLogs.split('\n').forEach(line => {
|
|
99
|
+
try {
|
|
100
|
+
const parsedLine = JSON.parse(line);
|
|
101
|
+
const { result, marker } = parsedLine;
|
|
102
|
+
const { buildStepDisplayName, buildStepInternalId, time, msg } = parsedLine;
|
|
103
|
+
const stepId = buildStepDisplayName ?? buildStepInternalId;
|
|
104
|
+
if (stepId) {
|
|
105
|
+
if (!logKeys.has(stepId)) {
|
|
106
|
+
logKeys.add(stepId);
|
|
107
|
+
logs.set(stepId, []);
|
|
108
|
+
}
|
|
109
|
+
logs.get(stepId)?.push({ time, msg, result, marker });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch { }
|
|
113
|
+
});
|
|
114
|
+
return logs;
|
|
115
|
+
}
|
|
116
|
+
exports.processLogsFromJobAsync = processLogsFromJobAsync;
|
|
@@ -14,11 +14,11 @@ const log_1 = tslib_1.__importStar(require("../../log"));
|
|
|
14
14
|
const ora_1 = require("../../ora");
|
|
15
15
|
const projectUtils_1 = require("../../project/projectUtils");
|
|
16
16
|
const json_1 = require("../../utils/json");
|
|
17
|
-
const progress_1 = require("../../utils/progress");
|
|
18
17
|
const WorkerAssets = tslib_1.__importStar(require("../../worker/assets"));
|
|
19
18
|
const deployment_1 = require("../../worker/deployment");
|
|
20
19
|
const upload_1 = require("../../worker/upload");
|
|
21
20
|
const logs_1 = require("../../worker/utils/logs");
|
|
21
|
+
const MAX_UPLOAD_SIZE = 5e8; // 500MB
|
|
22
22
|
const isDirectory = (directoryPath) => node_fs_1.default.promises
|
|
23
23
|
.stat(directoryPath)
|
|
24
24
|
.then(stat => stat.isDirectory())
|
|
@@ -96,14 +96,11 @@ class WorkerDeploy extends EasCommand_1.default {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
async function uploadTarballAsync(tarPath, uploadUrl) {
|
|
99
|
+
const payload = { filePath: tarPath };
|
|
99
100
|
const { response } = await (0, upload_1.uploadAsync)({
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
headers: {
|
|
104
|
-
accept: 'application/json',
|
|
105
|
-
},
|
|
106
|
-
});
|
|
101
|
+
baseURL: uploadUrl,
|
|
102
|
+
method: 'POST',
|
|
103
|
+
}, payload);
|
|
107
104
|
if (response.status === 413) {
|
|
108
105
|
throw new Error('Upload failed! (Payload too large)\n' +
|
|
109
106
|
`The files in "${path.relative(projectDir, projectDist.path)}" (at: ${projectDir}) exceed the maximum file size (10MB gzip).`);
|
|
@@ -116,7 +113,7 @@ class WorkerDeploy extends EasCommand_1.default {
|
|
|
116
113
|
if (!json.success || !json.result || typeof json.result !== 'object') {
|
|
117
114
|
throw new Error(json.message ? `Upload failed: ${json.message}` : 'Upload failed!');
|
|
118
115
|
}
|
|
119
|
-
const { id, fullName, token } = json.result;
|
|
116
|
+
const { id, fullName, token, upload } = json.result;
|
|
120
117
|
if (typeof token !== 'string') {
|
|
121
118
|
throw new Error('Upload failed: API failed to return a deployment token');
|
|
122
119
|
}
|
|
@@ -126,56 +123,57 @@ class WorkerDeploy extends EasCommand_1.default {
|
|
|
126
123
|
else if (typeof fullName !== 'string') {
|
|
127
124
|
throw new Error('Upload failed: API failed to return a script name');
|
|
128
125
|
}
|
|
126
|
+
else if (!Array.isArray(upload) && upload !== undefined) {
|
|
127
|
+
throw new Error('Upload failed: API returned invalid asset upload instructions');
|
|
128
|
+
}
|
|
129
129
|
const baseURL = new URL('/', uploadUrl).toString();
|
|
130
|
-
return { id, fullName, baseURL, token };
|
|
130
|
+
return { id, fullName, baseURL, token, upload };
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
|
-
async function uploadAssetsAsync(
|
|
134
|
-
const
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
133
|
+
async function uploadAssetsAsync(assetFiles, deployParams) {
|
|
134
|
+
const baseURL = new URL('/asset/', deployParams.baseURL);
|
|
135
|
+
const uploadInit = { baseURL, method: 'POST' };
|
|
136
|
+
uploadInit.baseURL.searchParams.set('token', deployParams.token);
|
|
137
|
+
const uploadPayloads = [];
|
|
138
|
+
if (deployParams.upload) {
|
|
139
|
+
const assetsBySHA512 = assetFiles.reduce((map, asset) => {
|
|
140
|
+
map.set(asset.sha512, asset);
|
|
141
|
+
return map;
|
|
142
|
+
}, new Map());
|
|
143
|
+
const payloads = deployParams.upload
|
|
144
|
+
.map(instruction => instruction.sha512.map(sha512 => {
|
|
145
|
+
const asset = assetsBySHA512.get(sha512);
|
|
146
|
+
if (!asset) {
|
|
147
|
+
// NOTE(@kitten): This should never happen
|
|
148
|
+
throw new Error(`Uploading assets failed: API instructed us to upload an asset that does not exist`);
|
|
149
|
+
}
|
|
150
|
+
return asset;
|
|
151
|
+
}))
|
|
152
|
+
.filter(assets => assets && assets.length > 0)
|
|
153
|
+
.map(assets => (assets.length > 1 ? { multipart: assets } : { asset: assets[0] }));
|
|
154
|
+
uploadPayloads.push(...payloads);
|
|
138
155
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
uploadParams.push({ url: uploadURL.toString(), filePath: asset.path });
|
|
156
|
+
else {
|
|
157
|
+
// NOTE(@kitten): Legacy format which uploads assets one-by-one
|
|
158
|
+
uploadPayloads.push(...assetFiles.map(asset => ({ asset })));
|
|
143
159
|
}
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
pending: 0,
|
|
147
|
-
percent: 0,
|
|
148
|
-
transferred: 0,
|
|
149
|
-
};
|
|
150
|
-
const updateProgress = (0, progress_1.createProgressTracker)({
|
|
151
|
-
total: progress.total,
|
|
152
|
-
message(ratio) {
|
|
153
|
-
const percent = `${Math.floor(ratio * 100)}`;
|
|
154
|
-
const details = chalk_1.default.dim(`(${progress.pending} Pending, ${progress.transferred} Completed, ${progress.total} Total)`);
|
|
155
|
-
return `Uploading assets: ${percent.padStart(3)}% ${details}`;
|
|
156
|
-
},
|
|
157
|
-
completedMessage: 'Uploaded assets',
|
|
158
|
-
});
|
|
160
|
+
const progressTotal = uploadPayloads.reduce((acc, payload) => acc + ('multipart' in payload ? payload.multipart.length : 1), 0);
|
|
161
|
+
const progressTracker = (0, upload_1.createProgressBar)(`Uploading ${progressTotal} assets`);
|
|
159
162
|
try {
|
|
160
|
-
for await (const signal of (0, upload_1.batchUploadAsync)(
|
|
161
|
-
|
|
162
|
-
progress.pending--;
|
|
163
|
-
progress.percent = ++progress.transferred / progress.total;
|
|
164
|
-
}
|
|
165
|
-
else {
|
|
166
|
-
progress.pending++;
|
|
167
|
-
}
|
|
168
|
-
updateProgress({ progress });
|
|
163
|
+
for await (const signal of (0, upload_1.batchUploadAsync)(uploadInit, uploadPayloads, progressTracker.update)) {
|
|
164
|
+
progressTracker.update(signal.progress);
|
|
169
165
|
}
|
|
170
166
|
}
|
|
171
167
|
catch (error) {
|
|
172
|
-
|
|
168
|
+
progressTracker.stop();
|
|
173
169
|
throw error;
|
|
174
170
|
}
|
|
175
|
-
|
|
171
|
+
finally {
|
|
172
|
+
progressTracker.stop();
|
|
173
|
+
}
|
|
176
174
|
}
|
|
177
|
-
let assetMap;
|
|
178
175
|
let tarPath;
|
|
176
|
+
let assetFiles;
|
|
179
177
|
let deployResult;
|
|
180
178
|
let progress = (0, ora_1.ora)('Preparing project').start();
|
|
181
179
|
try {
|
|
@@ -189,9 +187,9 @@ class WorkerDeploy extends EasCommand_1.default {
|
|
|
189
187
|
'In case of conflict, the EAS environment variable values will be used: ' +
|
|
190
188
|
manifestResult.conflictingVariableNames.join(' '));
|
|
191
189
|
}
|
|
192
|
-
|
|
190
|
+
assetFiles = await WorkerAssets.collectAssetsAsync(projectDist.type === 'server' ? projectDist.clientPath : projectDist.path, { maxFileSize: MAX_UPLOAD_SIZE });
|
|
193
191
|
tarPath = await WorkerAssets.packFilesIterableAsync(emitWorkerTarballAsync({
|
|
194
|
-
assetMap,
|
|
192
|
+
assetMap: WorkerAssets.assetsToAssetsMap(assetFiles),
|
|
195
193
|
manifest: manifestResult.manifest,
|
|
196
194
|
}));
|
|
197
195
|
if (flags.dryRun) {
|
|
@@ -232,7 +230,7 @@ class WorkerDeploy extends EasCommand_1.default {
|
|
|
232
230
|
}
|
|
233
231
|
throw error;
|
|
234
232
|
}
|
|
235
|
-
await uploadAssetsAsync(
|
|
233
|
+
await uploadAssetsAsync(assetFiles, deployResult);
|
|
236
234
|
await finalizeDeployAsync(deployResult);
|
|
237
235
|
let deploymentAlias = null;
|
|
238
236
|
if (flags.aliasName) {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
|
|
5
5
|
const flags_1 = require("../../commandUtils/flags");
|
|
6
|
-
const
|
|
6
|
+
const utils_1 = require("../../commandUtils/workflow/utils");
|
|
7
7
|
const generated_1 = require("../../graphql/generated");
|
|
8
8
|
const WorkflowRunMutation_1 = require("../../graphql/mutations/WorkflowRunMutation");
|
|
9
9
|
const AppQuery_1 = require("../../graphql/queries/AppQuery");
|
|
@@ -44,7 +44,7 @@ class WorkflowRunCancel extends EasCommand_1.default {
|
|
|
44
44
|
}
|
|
45
45
|
// Run the workflow run list query and select runs to cancel
|
|
46
46
|
const queryResult = await AppQuery_1.AppQuery.byIdWorkflowRunsFilteredByStatusAsync(graphqlClient, projectId, generated_1.WorkflowRunStatus.InProgress, 50);
|
|
47
|
-
const runs = (0,
|
|
47
|
+
const runs = (0, utils_1.processWorkflowRuns)(queryResult);
|
|
48
48
|
if (runs.length === 0) {
|
|
49
49
|
log_1.default.warn('No workflow runs to cancel');
|
|
50
50
|
return;
|
|
@@ -53,10 +53,7 @@ class WorkflowRunCancel extends EasCommand_1.default {
|
|
|
53
53
|
type: 'multiselect',
|
|
54
54
|
name: 'selectedRuns',
|
|
55
55
|
message: 'Select IN_PROGRESS workflow runs to cancel',
|
|
56
|
-
choices: runs.map(run => (
|
|
57
|
-
title: `${run.id} - ${run.workflowFileName}, ${run.gitCommitMessage ?? ''}, ${run.startedAt}`,
|
|
58
|
-
value: run.id,
|
|
59
|
-
})),
|
|
56
|
+
choices: runs.map(run => (0, utils_1.choiceFromWorkflowRun)(run)),
|
|
60
57
|
});
|
|
61
58
|
answers.selectedRuns.forEach((id) => {
|
|
62
59
|
workflowRunIds.add(id);
|