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.
Files changed (40) hide show
  1. package/README.md +137 -84
  2. package/build/commandUtils/workflow/fetchLogs.d.ts +2 -0
  3. package/build/commandUtils/workflow/fetchLogs.js +16 -0
  4. package/build/commandUtils/workflow/stateMachine.d.ts +44 -0
  5. package/build/commandUtils/workflow/stateMachine.js +212 -0
  6. package/build/commandUtils/workflow/types.d.ts +39 -0
  7. package/build/commandUtils/workflow/types.js +13 -0
  8. package/build/commandUtils/workflow/utils.d.ts +12 -0
  9. package/build/commandUtils/workflow/utils.js +116 -0
  10. package/build/commands/deploy/index.js +47 -49
  11. package/build/commands/workflow/cancel.js +3 -6
  12. package/build/commands/workflow/logs.d.ts +18 -0
  13. package/build/commands/workflow/logs.js +94 -0
  14. package/build/commands/workflow/run.d.ts +105 -0
  15. package/build/commands/workflow/run.js +280 -0
  16. package/build/commands/workflow/runs.js +4 -3
  17. package/build/commands/workflow/view.d.ts +17 -0
  18. package/build/commands/workflow/view.js +95 -0
  19. package/build/credentials/ios/appstore/bundleIdCapabilities.d.ts +4 -17
  20. package/build/credentials/ios/appstore/bundleIdCapabilities.js +45 -625
  21. package/build/credentials/ios/appstore/capabilityIdentifiers.js +33 -34
  22. package/build/credentials/ios/appstore/capabilityList.d.ts +33 -0
  23. package/build/credentials/ios/appstore/capabilityList.js +646 -0
  24. package/build/graphql/generated.d.ts +236 -19
  25. package/build/graphql/queries/WorkflowJobQuery.d.ts +7 -0
  26. package/build/graphql/queries/WorkflowJobQuery.js +29 -0
  27. package/build/graphql/queries/WorkflowRunQuery.js +13 -13
  28. package/build/graphql/types/WorkflowJob.d.ts +1 -0
  29. package/build/graphql/types/WorkflowJob.js +32 -0
  30. package/build/graphql/types/WorkflowRun.js +18 -0
  31. package/build/worker/assets.d.ts +19 -16
  32. package/build/worker/assets.js +51 -22
  33. package/build/worker/upload.d.ts +21 -9
  34. package/build/worker/upload.js +98 -80
  35. package/build/worker/utils/multipart.d.ts +11 -0
  36. package/build/worker/utils/multipart.js +98 -0
  37. package/oclif.manifest.json +85 -1
  38. package/package.json +2 -2
  39. package/build/commandUtils/workflows.d.ts +0 -20
  40. package/build/commandUtils/workflows.js +0 -21
@@ -0,0 +1,2 @@
1
+ import { WorkflowJobResult } from './types';
2
+ export declare function fetchRawLogsForJobAsync(job: WorkflowJobResult): Promise<string | null>;
@@ -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
- url: uploadUrl,
101
- filePath: tarPath,
102
- compress: false,
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(assetMap, deployParams) {
134
- const uploadParams = [];
135
- const assetPath = projectDist.type === 'server' ? projectDist.clientPath : projectDist.path;
136
- if (!assetPath) {
137
- return;
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
- for await (const asset of WorkerAssets.listAssetMapFilesAsync(assetPath, assetMap)) {
140
- const uploadURL = new URL(`/asset/${asset.sha512}`, deployParams.baseURL);
141
- uploadURL.searchParams.set('token', deployParams.token);
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 progress = {
145
- total: uploadParams.length,
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)(uploadParams)) {
161
- if ('response' in signal) {
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
- updateProgress({ isComplete: true, error });
168
+ progressTracker.stop();
173
169
  throw error;
174
170
  }
175
- updateProgress({ isComplete: true });
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
- assetMap = await WorkerAssets.createAssetMapAsync(projectDist.type === 'server' ? projectDist.clientPath : projectDist.path);
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(assetMap, deployResult);
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 workflows_1 = require("../../commandUtils/workflows");
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, workflows_1.processWorkflowRuns)(queryResult);
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);