eas-cli 12.3.0 → 12.4.1
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 +60 -60
- package/build/build/ios/version.js +11 -6
- package/build/commandUtils/context/contextUtils/getProjectIdAsync.d.ts +1 -0
- package/build/commandUtils/context/contextUtils/getProjectIdAsync.js +3 -1
- package/build/commands/worker/alias.d.ts +22 -0
- package/build/commands/worker/alias.js +168 -0
- package/build/commands/worker/deploy.d.ts +62 -1
- package/build/commands/worker/deploy.js +186 -65
- package/build/graphql/generated.d.ts +372 -146
- package/build/graphql/generated.js +46 -44
- package/build/project/expoConfig.d.ts +1 -0
- package/build/project/expoConfig.js +1 -0
- package/build/worker/assets.d.ts +12 -0
- package/build/worker/assets.js +20 -1
- package/build/worker/deployment.d.ts +25 -2
- package/build/worker/deployment.js +106 -15
- package/build/worker/fragments/WorkerDeployment.d.ts +1 -0
- package/build/worker/fragments/WorkerDeployment.js +14 -0
- package/build/worker/fragments/WorkerDeploymentAlias.d.ts +1 -0
- package/build/worker/fragments/WorkerDeploymentAlias.js +12 -0
- package/build/worker/mutations.d.ts +6 -0
- package/build/worker/mutations.js +33 -0
- package/build/worker/queries.d.ts +7 -0
- package/build/worker/queries.js +61 -0
- package/build/worker/utils/logs.d.ts +35 -0
- package/build/worker/utils/logs.js +54 -0
- package/oclif.manifest.json +129 -3
- package/package.json +4 -3
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const core_1 = require("@oclif/core");
|
|
6
|
+
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
7
|
+
const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
|
|
8
|
+
const flags_1 = require("../../commandUtils/flags");
|
|
9
|
+
const log_1 = tslib_1.__importDefault(require("../../log"));
|
|
10
|
+
const ora_1 = require("../../ora");
|
|
11
|
+
const prompts_1 = require("../../prompts");
|
|
12
|
+
const json_1 = require("../../utils/json");
|
|
13
|
+
const deployment_1 = require("../../worker/deployment");
|
|
14
|
+
const logs_1 = require("../../worker/utils/logs");
|
|
15
|
+
class WorkerAlias extends EasCommand_1.default {
|
|
16
|
+
async runAsync() {
|
|
17
|
+
const { flags: rawFlags } = await this.parse(_a);
|
|
18
|
+
const flags = this.sanitizeFlags(rawFlags);
|
|
19
|
+
if (flags.json) {
|
|
20
|
+
(0, json_1.enableJsonOutput)();
|
|
21
|
+
}
|
|
22
|
+
log_1.default.warn('EAS Worker Deployments are in beta and subject to breaking changes.');
|
|
23
|
+
const { getDynamicPrivateProjectConfigAsync, loggedIn: { graphqlClient }, } = await this.getContextAsync(_a, {
|
|
24
|
+
nonInteractive: true,
|
|
25
|
+
});
|
|
26
|
+
const { projectId } = await getDynamicPrivateProjectConfigAsync();
|
|
27
|
+
const aliasName = await resolveDeploymentAliasAsync(flags);
|
|
28
|
+
const deploymentId = await resolveDeploymentIdAsync({
|
|
29
|
+
...flags,
|
|
30
|
+
graphqlClient,
|
|
31
|
+
projectId,
|
|
32
|
+
aliasName,
|
|
33
|
+
});
|
|
34
|
+
let progress = null;
|
|
35
|
+
let deploymentAlias = null;
|
|
36
|
+
if (aliasName) {
|
|
37
|
+
try {
|
|
38
|
+
progress = (0, ora_1.ora)((0, chalk_1.default) `Assigning alias {bold ${aliasName}} to deployment`).start();
|
|
39
|
+
deploymentAlias = await (0, deployment_1.assignWorkerDeploymentAliasAsync)({
|
|
40
|
+
graphqlClient,
|
|
41
|
+
appId: projectId,
|
|
42
|
+
deploymentId,
|
|
43
|
+
aliasName,
|
|
44
|
+
});
|
|
45
|
+
progress.text = (0, chalk_1.default) `Assigned alias {bold ${aliasName}} to deployment`;
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
progress?.fail((0, chalk_1.default) `Failed to assign {bold ${aliasName}} alias to deployment`);
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
let deploymentProdAlias = null;
|
|
53
|
+
if (flags.isProduction) {
|
|
54
|
+
try {
|
|
55
|
+
progress = (progress ?? (0, ora_1.ora)()).start((0, chalk_1.default) `Promoting deployment to {bold production}`);
|
|
56
|
+
deploymentProdAlias = await (0, deployment_1.assignWorkerDeploymentProductionAsync)({
|
|
57
|
+
graphqlClient,
|
|
58
|
+
appId: projectId,
|
|
59
|
+
deploymentId,
|
|
60
|
+
});
|
|
61
|
+
progress.text = (0, chalk_1.default) `Promoted deployment to {bold production}`;
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
progress?.fail((0, chalk_1.default) `Failed to promote deployment to {bold production}`);
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
progress?.succeed(!deploymentAlias
|
|
69
|
+
? (0, chalk_1.default) `Promoted deployment to {bold production}`
|
|
70
|
+
: (0, chalk_1.default) `Promoted deployment to {bold production} with alias {bold ${deploymentAlias.aliasName}}`);
|
|
71
|
+
// Either use the alias, or production deployment information
|
|
72
|
+
const deployment = deploymentAlias?.workerDeployment ?? deploymentProdAlias?.workerDeployment;
|
|
73
|
+
if (flags.json) {
|
|
74
|
+
(0, json_1.printJsonOnlyOutput)((0, logs_1.formatWorkerDeploymentJson)({
|
|
75
|
+
projectId,
|
|
76
|
+
deployment: deployment,
|
|
77
|
+
aliases: [deploymentAlias].filter(Boolean),
|
|
78
|
+
production: deploymentProdAlias,
|
|
79
|
+
}));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
log_1.default.addNewLineIfNone();
|
|
83
|
+
log_1.default.log(`🎉 Your deployment is modified`);
|
|
84
|
+
log_1.default.addNewLineIfNone();
|
|
85
|
+
log_1.default.log((0, logs_1.formatWorkerDeploymentTable)({
|
|
86
|
+
projectId,
|
|
87
|
+
deployment: deployment,
|
|
88
|
+
aliases: [deploymentAlias].filter(Boolean),
|
|
89
|
+
production: deploymentProdAlias,
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
sanitizeFlags(flags) {
|
|
93
|
+
return {
|
|
94
|
+
nonInteractive: flags['non-interactive'],
|
|
95
|
+
json: flags['json'],
|
|
96
|
+
aliasName: flags.alias?.trim().toLowerCase(),
|
|
97
|
+
deploymentIdentifier: flags.id?.trim().toLowerCase(),
|
|
98
|
+
isProduction: flags.prod,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
_a = WorkerAlias;
|
|
103
|
+
WorkerAlias.description = 'Assign deployment aliases';
|
|
104
|
+
WorkerAlias.aliases = ['deploy:alias', 'deploy:promote'];
|
|
105
|
+
// TODO(@kitten): Keep command hidden until worker deployments are live
|
|
106
|
+
WorkerAlias.hidden = true;
|
|
107
|
+
WorkerAlias.state = 'beta';
|
|
108
|
+
WorkerAlias.flags = {
|
|
109
|
+
prod: core_1.Flags.boolean({
|
|
110
|
+
aliases: ['production'],
|
|
111
|
+
description: 'Promote an existing deployment to production.',
|
|
112
|
+
default: false,
|
|
113
|
+
}),
|
|
114
|
+
alias: core_1.Flags.string({
|
|
115
|
+
description: 'Custom alias to assign to the existing deployment.',
|
|
116
|
+
helpValue: 'name',
|
|
117
|
+
required: false,
|
|
118
|
+
}),
|
|
119
|
+
id: core_1.Flags.string({
|
|
120
|
+
description: 'Unique identifier of an existing deployment.',
|
|
121
|
+
helpValue: 'xyz123',
|
|
122
|
+
required: false,
|
|
123
|
+
}),
|
|
124
|
+
...flags_1.EasNonInteractiveAndJsonFlags,
|
|
125
|
+
};
|
|
126
|
+
WorkerAlias.contextDefinition = {
|
|
127
|
+
..._a.ContextOptions.DynamicProjectConfig,
|
|
128
|
+
..._a.ContextOptions.ProjectDir,
|
|
129
|
+
..._a.ContextOptions.LoggedIn,
|
|
130
|
+
};
|
|
131
|
+
exports.default = WorkerAlias;
|
|
132
|
+
async function resolveDeploymentAliasAsync(flags) {
|
|
133
|
+
if (flags.aliasName?.trim()) {
|
|
134
|
+
return flags.aliasName.trim().toLowerCase();
|
|
135
|
+
}
|
|
136
|
+
// Skip alias prompt when promoting deployments to prod
|
|
137
|
+
if (flags.isProduction) {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
if (flags.nonInteractive) {
|
|
141
|
+
throw new Error('The `--alias` flag must be set when running in `--non-interactive` mode.');
|
|
142
|
+
}
|
|
143
|
+
const { alias: aliasName } = await (0, prompts_1.promptAsync)({
|
|
144
|
+
type: 'text',
|
|
145
|
+
name: 'alias',
|
|
146
|
+
message: 'Enter the alias to assign to a deployment',
|
|
147
|
+
validate: (value) => !!value.trim(),
|
|
148
|
+
hint: 'The alias name is case insensitive and must be URL safe',
|
|
149
|
+
});
|
|
150
|
+
return aliasName.trim().toLowerCase();
|
|
151
|
+
}
|
|
152
|
+
async function resolveDeploymentIdAsync({ graphqlClient, deploymentIdentifier, aliasName, projectId, nonInteractive, }) {
|
|
153
|
+
if (deploymentIdentifier) {
|
|
154
|
+
return deploymentIdentifier;
|
|
155
|
+
}
|
|
156
|
+
if (nonInteractive) {
|
|
157
|
+
throw new Error('The `--id` flag must be set when running in `--non-interactive` mode.');
|
|
158
|
+
}
|
|
159
|
+
const deployment = await (0, deployment_1.selectWorkerDeploymentOnAppAsync)({
|
|
160
|
+
graphqlClient,
|
|
161
|
+
appId: projectId,
|
|
162
|
+
selectTitle: (0, chalk_1.default) `deployment to assign the {underline ${aliasName}} alias`,
|
|
163
|
+
});
|
|
164
|
+
if (!deployment) {
|
|
165
|
+
throw new Error('No deployments found for this project, create a new deployment with "eas deploy"');
|
|
166
|
+
}
|
|
167
|
+
return deployment.deploymentIdentifier;
|
|
168
|
+
}
|
|
@@ -1,10 +1,70 @@
|
|
|
1
1
|
import EasCommand from '../../commandUtils/EasCommand';
|
|
2
|
+
import { EnvironmentVariableEnvironment } from '../../graphql/generated';
|
|
2
3
|
export default class WorkerDeploy extends EasCommand {
|
|
3
4
|
static description: string;
|
|
4
5
|
static aliases: string[];
|
|
6
|
+
static usage: string[];
|
|
5
7
|
static hidden: boolean;
|
|
6
8
|
static state: string;
|
|
7
|
-
static flags: {
|
|
9
|
+
static flags: {
|
|
10
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
'non-interactive': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
prod: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
alias: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined>;
|
|
14
|
+
id: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined>;
|
|
15
|
+
'export-dir': import("@oclif/core/lib/interfaces").OptionFlag<string>;
|
|
16
|
+
environment: {
|
|
17
|
+
description: string;
|
|
18
|
+
name: string;
|
|
19
|
+
char?: import("@oclif/core/lib/interfaces").AlphabetUppercase | import("@oclif/core/lib/interfaces").AlphabetLowercase | undefined;
|
|
20
|
+
summary?: string | undefined;
|
|
21
|
+
helpLabel?: string | undefined;
|
|
22
|
+
helpGroup?: string | undefined;
|
|
23
|
+
env?: string | undefined;
|
|
24
|
+
hidden?: boolean | undefined;
|
|
25
|
+
required?: boolean | undefined;
|
|
26
|
+
dependsOn?: string[] | undefined;
|
|
27
|
+
exclusive?: string[] | undefined;
|
|
28
|
+
exactlyOne?: string[] | undefined;
|
|
29
|
+
relationships?: import("@oclif/core/lib/interfaces/parser").Relationship[] | undefined;
|
|
30
|
+
deprecated?: true | import("@oclif/core/lib/interfaces/parser").Deprecation | undefined;
|
|
31
|
+
aliases?: string[] | undefined;
|
|
32
|
+
deprecateAliases?: boolean | undefined;
|
|
33
|
+
parse: import("@oclif/core/lib/interfaces/parser").FlagParser<EnvironmentVariableEnvironment | undefined, string, any>;
|
|
34
|
+
type: "option";
|
|
35
|
+
helpValue?: string | undefined;
|
|
36
|
+
options?: string[] | undefined;
|
|
37
|
+
multiple: false;
|
|
38
|
+
defaultHelp?: import("@oclif/core/lib/interfaces/parser").DefaultHelp<EnvironmentVariableEnvironment | undefined, Record<string, unknown>>;
|
|
39
|
+
input: string[];
|
|
40
|
+
default?: import("@oclif/core/lib/interfaces").Default<EnvironmentVariableEnvironment | undefined, Record<string, unknown>>;
|
|
41
|
+
} | {
|
|
42
|
+
description: string;
|
|
43
|
+
name: string;
|
|
44
|
+
char?: import("@oclif/core/lib/interfaces").AlphabetUppercase | import("@oclif/core/lib/interfaces").AlphabetLowercase | undefined;
|
|
45
|
+
summary?: string | undefined;
|
|
46
|
+
helpLabel?: string | undefined;
|
|
47
|
+
helpGroup?: string | undefined;
|
|
48
|
+
env?: string | undefined;
|
|
49
|
+
hidden?: boolean | undefined;
|
|
50
|
+
required?: boolean | undefined;
|
|
51
|
+
dependsOn?: string[] | undefined;
|
|
52
|
+
exclusive?: string[] | undefined;
|
|
53
|
+
exactlyOne?: string[] | undefined;
|
|
54
|
+
relationships?: import("@oclif/core/lib/interfaces/parser").Relationship[] | undefined;
|
|
55
|
+
deprecated?: true | import("@oclif/core/lib/interfaces/parser").Deprecation | undefined;
|
|
56
|
+
aliases?: string[] | undefined;
|
|
57
|
+
deprecateAliases?: boolean | undefined;
|
|
58
|
+
parse: import("@oclif/core/lib/interfaces/parser").FlagParser<EnvironmentVariableEnvironment | undefined, string, any>;
|
|
59
|
+
type: "option";
|
|
60
|
+
helpValue?: string | undefined;
|
|
61
|
+
options?: string[] | undefined;
|
|
62
|
+
multiple: true;
|
|
63
|
+
defaultHelp?: import("@oclif/core/lib/interfaces/parser").DefaultHelp<EnvironmentVariableEnvironment | undefined, Record<string, unknown>>;
|
|
64
|
+
input: string[];
|
|
65
|
+
default?: import("@oclif/core/lib/interfaces").Default<(EnvironmentVariableEnvironment | undefined)[] | undefined, Record<string, unknown>>;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
8
68
|
static contextDefinition: {
|
|
9
69
|
loggedIn: import("../../commandUtils/context/LoggedInContextField").default;
|
|
10
70
|
projectDir: import("../../commandUtils/context/ProjectDirContextField").default;
|
|
@@ -12,4 +72,5 @@ export default class WorkerDeploy extends EasCommand {
|
|
|
12
72
|
getDynamicPrivateProjectConfigAsync: import("../../commandUtils/context/DynamicProjectConfigContextField").DynamicPrivateProjectConfigContextField;
|
|
13
73
|
};
|
|
14
74
|
runAsync(): Promise<void>;
|
|
75
|
+
private sanitizeFlags;
|
|
15
76
|
}
|
|
@@ -2,68 +2,50 @@
|
|
|
2
2
|
var _a;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
+
const timeago_js_1 = require("@expo/timeago.js");
|
|
6
|
+
const core_1 = require("@oclif/core");
|
|
5
7
|
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
6
8
|
const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
|
|
7
9
|
const path = tslib_1.__importStar(require("node:path"));
|
|
8
10
|
const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
|
|
11
|
+
const flags_1 = require("../../commandUtils/flags");
|
|
9
12
|
const log_1 = tslib_1.__importDefault(require("../../log"));
|
|
10
13
|
const ora_1 = require("../../ora");
|
|
14
|
+
const json_1 = require("../../utils/json");
|
|
11
15
|
const progress_1 = require("../../utils/progress");
|
|
12
16
|
const WorkerAssets = tslib_1.__importStar(require("../../worker/assets"));
|
|
13
17
|
const deployment_1 = require("../../worker/deployment");
|
|
14
18
|
const upload_1 = require("../../worker/upload");
|
|
19
|
+
const logs_1 = require("../../worker/utils/logs");
|
|
15
20
|
const isDirectory = (directoryPath) => node_fs_1.default.promises
|
|
16
21
|
.stat(directoryPath)
|
|
17
22
|
.then(stat => stat.isDirectory())
|
|
18
23
|
.catch(() => false);
|
|
19
24
|
class WorkerDeploy extends EasCommand_1.default {
|
|
20
25
|
async runAsync() {
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const { projectId, projectDir, exp } = await getDynamicPrivateProjectConfigAsync();
|
|
26
|
-
const distPath = path.resolve(projectDir, 'dist');
|
|
27
|
-
let distServerPath;
|
|
28
|
-
let distClientPath;
|
|
29
|
-
if (exp.web?.output === 'static') {
|
|
30
|
-
distClientPath = distPath;
|
|
31
|
-
distServerPath = null;
|
|
32
|
-
if (!(await isDirectory(distClientPath))) {
|
|
33
|
-
throw new Error(`No "dist/" folder found. Prepare your project for deployment with "npx expo export"`);
|
|
34
|
-
}
|
|
35
|
-
log_1.default.log('Detected "static" worker deployment');
|
|
36
|
-
}
|
|
37
|
-
else if (exp.web?.output === 'server') {
|
|
38
|
-
distClientPath = path.resolve(distPath, 'client');
|
|
39
|
-
distServerPath = path.resolve(distPath, 'server');
|
|
40
|
-
if (!(await isDirectory(distClientPath))) {
|
|
41
|
-
throw new Error(`No "dist/client/" folder found. Prepare your project for deployment with "npx expo export"`);
|
|
42
|
-
}
|
|
43
|
-
else if (!(await isDirectory(distServerPath))) {
|
|
44
|
-
throw new Error(`No "dist/server/" folder found. Prepare your project for deployment with "npx expo export"`);
|
|
45
|
-
}
|
|
46
|
-
log_1.default.log('Detected "server" worker deployment');
|
|
26
|
+
const { flags: rawFlags } = await this.parse(_a);
|
|
27
|
+
const flags = this.sanitizeFlags(rawFlags);
|
|
28
|
+
if (flags.json) {
|
|
29
|
+
(0, json_1.enableJsonOutput)();
|
|
47
30
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
31
|
+
log_1.default.warn('EAS Worker Deployments are in beta and subject to breaking changes.');
|
|
32
|
+
const { getDynamicPrivateProjectConfigAsync, loggedIn: { graphqlClient }, projectDir, } = await this.getContextAsync(_a, flags);
|
|
33
|
+
const [{ projectId }, projectDist] = await Promise.all([
|
|
34
|
+
getDynamicPrivateProjectConfigAsync(),
|
|
35
|
+
resolveExportedProjectAsync(flags, projectDir),
|
|
36
|
+
]);
|
|
37
|
+
logExportedProjectInfo(projectDist);
|
|
38
|
+
async function* emitWorkerTarballAsync(params) {
|
|
39
|
+
yield ['assets.json', JSON.stringify(params.assetMap)];
|
|
40
|
+
yield ['manifest.json', JSON.stringify(params.manifest)];
|
|
41
|
+
if (projectDist.type === 'server' && projectDist.serverPath) {
|
|
42
|
+
const workerFiles = WorkerAssets.listWorkerFilesAsync(projectDist.serverPath);
|
|
58
43
|
for await (const workerFile of workerFiles) {
|
|
59
44
|
yield [`server/${workerFile.normalizedPath}`, workerFile.data];
|
|
60
45
|
}
|
|
61
46
|
}
|
|
62
47
|
}
|
|
63
|
-
async function uploadTarballAsync(tarPath) {
|
|
64
|
-
const uploadUrl = await (0, deployment_1.getSignedDeploymentUrlAsync)(graphqlClient, exp, {
|
|
65
|
-
appId: projectId,
|
|
66
|
-
});
|
|
48
|
+
async function uploadTarballAsync(tarPath, uploadUrl) {
|
|
67
49
|
const { response } = await (0, upload_1.uploadAsync)({
|
|
68
50
|
url: uploadUrl,
|
|
69
51
|
filePath: tarPath,
|
|
@@ -74,7 +56,7 @@ class WorkerDeploy extends EasCommand_1.default {
|
|
|
74
56
|
});
|
|
75
57
|
if (response.status === 413) {
|
|
76
58
|
throw new Error('Upload failed! (Payload too large)\n' +
|
|
77
|
-
`The files in "
|
|
59
|
+
`The files in "${path.relative(projectDir, projectDist.path)}" (at: ${projectDir}) exceed the maximum file size (10MB gzip).`);
|
|
78
60
|
}
|
|
79
61
|
else if (!response.ok) {
|
|
80
62
|
throw new Error(`Upload failed! (${response.statusText})`);
|
|
@@ -93,7 +75,8 @@ class WorkerDeploy extends EasCommand_1.default {
|
|
|
93
75
|
}
|
|
94
76
|
// TODO(@kitten): Batch and upload multiple files in parallel
|
|
95
77
|
const uploadParams = [];
|
|
96
|
-
|
|
78
|
+
const assetPath = projectDist.type === 'server' ? projectDist.clientPath : projectDist.path;
|
|
79
|
+
for await (const asset of WorkerAssets.listAssetMapFilesAsync(assetPath, assetMap)) {
|
|
97
80
|
const uploadURL = uploads[asset.normalizedPath];
|
|
98
81
|
if (uploadURL) {
|
|
99
82
|
uploadParams.push({ url: uploadURL, filePath: asset.path });
|
|
@@ -110,9 +93,9 @@ class WorkerDeploy extends EasCommand_1.default {
|
|
|
110
93
|
message(ratio) {
|
|
111
94
|
const percent = `${Math.floor(ratio * 100)}`;
|
|
112
95
|
const details = chalk_1.default.dim(`(${progress.pending} Pending, ${progress.transferred} Completed, ${progress.total} Total)`);
|
|
113
|
-
return `Uploading
|
|
96
|
+
return `Uploading assets: ${percent.padStart(3)}% ${details}`;
|
|
114
97
|
},
|
|
115
|
-
completedMessage: 'Uploaded assets
|
|
98
|
+
completedMessage: 'Uploaded assets',
|
|
116
99
|
});
|
|
117
100
|
try {
|
|
118
101
|
for await (const signal of (0, upload_1.batchUploadAsync)(uploadParams)) {
|
|
@@ -132,46 +115,153 @@ class WorkerDeploy extends EasCommand_1.default {
|
|
|
132
115
|
}
|
|
133
116
|
updateProgress({ isComplete: true });
|
|
134
117
|
}
|
|
135
|
-
let progress = (0, ora_1.ora)('Preparing worker upload');
|
|
136
118
|
let assetMap;
|
|
137
119
|
let tarPath;
|
|
138
|
-
try {
|
|
139
|
-
assetMap = await WorkerAssets.createAssetMapAsync(distClientPath);
|
|
140
|
-
tarPath = await WorkerAssets.packFilesIterableAsync(emitWorkerTarballAsync(assetMap));
|
|
141
|
-
}
|
|
142
|
-
catch (error) {
|
|
143
|
-
progress.fail('Failed to prepare worker upload');
|
|
144
|
-
throw error;
|
|
145
|
-
}
|
|
146
|
-
progress.succeed('Prepared worker upload');
|
|
147
|
-
progress = (0, ora_1.ora)('Creating worker deployment');
|
|
148
120
|
let deployResult;
|
|
121
|
+
let progress = (0, ora_1.ora)('Preparing project').start();
|
|
149
122
|
try {
|
|
150
|
-
|
|
123
|
+
const manifest = await WorkerAssets.createManifestAsync({
|
|
124
|
+
environment: flags.environment,
|
|
125
|
+
projectDir,
|
|
126
|
+
projectId,
|
|
127
|
+
}, graphqlClient);
|
|
128
|
+
assetMap = await WorkerAssets.createAssetMapAsync(projectDist.type === 'server' ? projectDist.clientPath : projectDist.path);
|
|
129
|
+
tarPath = await WorkerAssets.packFilesIterableAsync(emitWorkerTarballAsync({
|
|
130
|
+
assetMap,
|
|
131
|
+
manifest,
|
|
132
|
+
}));
|
|
133
|
+
const uploadUrl = await (0, deployment_1.getSignedDeploymentUrlAsync)(graphqlClient, {
|
|
134
|
+
appId: projectId,
|
|
135
|
+
deploymentIdentifier: flags.deploymentIdentifier,
|
|
136
|
+
// NOTE(cedric): this function might ask the user for a dev-domain name,
|
|
137
|
+
// when that happens, no ora spinner should be running.
|
|
138
|
+
onSetupDevDomain: () => progress.stop(),
|
|
139
|
+
nonInteractive: flags.nonInteractive,
|
|
140
|
+
});
|
|
141
|
+
progress.start('Creating deployment');
|
|
142
|
+
deployResult = await uploadTarballAsync(tarPath, uploadUrl);
|
|
143
|
+
progress.succeed('Created deployment');
|
|
151
144
|
}
|
|
152
145
|
catch (error) {
|
|
153
|
-
progress.fail('Failed to create
|
|
146
|
+
progress.fail('Failed to create deployment');
|
|
154
147
|
throw error;
|
|
155
148
|
}
|
|
156
|
-
progress.succeed('Created worker deployment');
|
|
157
149
|
await uploadAssetsAsync(assetMap, deployResult.uploads);
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
150
|
+
let deploymentAlias = null;
|
|
151
|
+
if (flags.aliasName) {
|
|
152
|
+
progress = (0, ora_1.ora)((0, chalk_1.default) `Assigning alias {bold ${flags.aliasName}} to deployment`).start();
|
|
153
|
+
try {
|
|
154
|
+
deploymentAlias = await (0, deployment_1.assignWorkerDeploymentAliasAsync)({
|
|
155
|
+
graphqlClient,
|
|
156
|
+
appId: projectId,
|
|
157
|
+
deploymentId: deployResult.id,
|
|
158
|
+
aliasName: flags.aliasName,
|
|
159
|
+
});
|
|
160
|
+
// Only stop the spinner when not promoting to production
|
|
161
|
+
if (!flags.isProduction) {
|
|
162
|
+
progress.succeed((0, chalk_1.default) `Assigned alias {bold ${flags.aliasName}} to deployment`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
progress.fail((0, chalk_1.default) `Failed to assign {bold ${flags.aliasName}} alias to deployment`);
|
|
167
|
+
throw error;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
let deploymentProdAlias = null;
|
|
171
|
+
if (flags.isProduction) {
|
|
172
|
+
try {
|
|
173
|
+
if (!flags.aliasName) {
|
|
174
|
+
progress = (0, ora_1.ora)((0, chalk_1.default) `Promoting deployment to {bold production}`).start();
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
progress.text = (0, chalk_1.default) `Promoting deployment to {bold production}`;
|
|
178
|
+
}
|
|
179
|
+
deploymentProdAlias = await (0, deployment_1.assignWorkerDeploymentProductionAsync)({
|
|
180
|
+
graphqlClient,
|
|
181
|
+
appId: projectId,
|
|
182
|
+
deploymentId: deployResult.id,
|
|
183
|
+
});
|
|
184
|
+
progress.succeed(!flags.aliasName
|
|
185
|
+
? (0, chalk_1.default) `Promoted deployment to {bold production}`
|
|
186
|
+
: (0, chalk_1.default) `Promoted deployment to {bold production} with alias {bold ${flags.aliasName}}`);
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
progress.fail('Failed to promote deployment to production');
|
|
190
|
+
throw error;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (flags.json) {
|
|
194
|
+
(0, json_1.printJsonOnlyOutput)((0, logs_1.formatWorkerDeploymentJson)({
|
|
195
|
+
projectId,
|
|
196
|
+
deployment: {
|
|
197
|
+
deploymentIdentifier: deployResult.id,
|
|
198
|
+
url: (0, logs_1.getDeploymentUrlFromFullName)(deployResult.fullName),
|
|
199
|
+
},
|
|
200
|
+
aliases: [deploymentAlias].filter(Boolean),
|
|
201
|
+
production: deploymentProdAlias,
|
|
202
|
+
}));
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
161
205
|
log_1.default.addNewLineIfNone();
|
|
162
|
-
log_1.default.log(`🎉 Your
|
|
206
|
+
log_1.default.log(`🎉 Your deployment is ready`);
|
|
163
207
|
log_1.default.addNewLineIfNone();
|
|
164
|
-
log_1.default.log(
|
|
208
|
+
log_1.default.log((0, logs_1.formatWorkerDeploymentTable)({
|
|
209
|
+
projectId,
|
|
210
|
+
deployment: {
|
|
211
|
+
deploymentIdentifier: deployResult.id,
|
|
212
|
+
url: (0, logs_1.getDeploymentUrlFromFullName)(deployResult.fullName),
|
|
213
|
+
},
|
|
214
|
+
aliases: [deploymentAlias].filter(Boolean),
|
|
215
|
+
production: deploymentProdAlias,
|
|
216
|
+
}));
|
|
217
|
+
if (!deploymentProdAlias) {
|
|
218
|
+
log_1.default.addNewLineIfNone();
|
|
219
|
+
log_1.default.log('🚀 When you are ready to deploy to production:');
|
|
220
|
+
log_1.default.log((0, chalk_1.default) ` $ eas deploy {bold --prod}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
sanitizeFlags(flags) {
|
|
224
|
+
return {
|
|
225
|
+
nonInteractive: flags['non-interactive'],
|
|
226
|
+
json: flags['json'],
|
|
227
|
+
isProduction: !!flags.prod,
|
|
228
|
+
aliasName: flags.alias?.trim().toLowerCase(),
|
|
229
|
+
deploymentIdentifier: flags.id?.trim(),
|
|
230
|
+
exportDir: flags['export-dir'],
|
|
231
|
+
};
|
|
165
232
|
}
|
|
166
233
|
}
|
|
167
234
|
_a = WorkerDeploy;
|
|
168
|
-
WorkerDeploy.description = '
|
|
235
|
+
WorkerDeploy.description = 'Deploy your Expo web build';
|
|
169
236
|
WorkerDeploy.aliases = ['deploy'];
|
|
237
|
+
WorkerDeploy.usage = [(0, chalk_1.default) `deploy {dim [options]}`, `deploy --prod`];
|
|
170
238
|
// TODO(@kitten): Keep command hidden until worker deployments are live
|
|
171
239
|
WorkerDeploy.hidden = true;
|
|
172
240
|
WorkerDeploy.state = 'beta';
|
|
173
241
|
WorkerDeploy.flags = {
|
|
174
|
-
|
|
242
|
+
prod: core_1.Flags.boolean({
|
|
243
|
+
aliases: ['production'],
|
|
244
|
+
description: 'Create a new production deployment.',
|
|
245
|
+
default: false,
|
|
246
|
+
}),
|
|
247
|
+
alias: core_1.Flags.string({
|
|
248
|
+
description: 'Custom alias to assign to the new deployment.',
|
|
249
|
+
helpValue: 'name',
|
|
250
|
+
}),
|
|
251
|
+
id: core_1.Flags.string({
|
|
252
|
+
description: 'Custom unique identifier for the new deployment.',
|
|
253
|
+
helpValue: 'xyz123',
|
|
254
|
+
}),
|
|
255
|
+
'export-dir': core_1.Flags.string({
|
|
256
|
+
description: 'Directory where the Expo project was exported.',
|
|
257
|
+
helpValue: 'dir',
|
|
258
|
+
default: 'dist',
|
|
259
|
+
}),
|
|
260
|
+
environment: {
|
|
261
|
+
...flags_1.EASEnvironmentFlag.environment,
|
|
262
|
+
description: 'Deploy with EAS Environment Variables matching the specified environment.',
|
|
263
|
+
},
|
|
264
|
+
...flags_1.EasNonInteractiveAndJsonFlags,
|
|
175
265
|
};
|
|
176
266
|
WorkerDeploy.contextDefinition = {
|
|
177
267
|
..._a.ContextOptions.DynamicProjectConfig,
|
|
@@ -179,3 +269,34 @@ WorkerDeploy.contextDefinition = {
|
|
|
179
269
|
..._a.ContextOptions.LoggedIn,
|
|
180
270
|
};
|
|
181
271
|
exports.default = WorkerDeploy;
|
|
272
|
+
async function resolveExportedProjectAsync(flags, projectDir) {
|
|
273
|
+
const exportPath = path.join(projectDir, flags.exportDir);
|
|
274
|
+
const serverPath = path.join(exportPath, 'server');
|
|
275
|
+
const clientPath = path.join(exportPath, 'client');
|
|
276
|
+
const [hasServerPath, hasClientPath, exportStat] = await Promise.all([
|
|
277
|
+
isDirectory(serverPath),
|
|
278
|
+
isDirectory(clientPath),
|
|
279
|
+
node_fs_1.default.promises.stat(exportPath).catch(() => null),
|
|
280
|
+
]);
|
|
281
|
+
if (!exportStat?.isDirectory()) {
|
|
282
|
+
throw new Error(`No "${flags.exportDir}/" folder found. Prepare your project for deployment with "npx expo export --platform web"`);
|
|
283
|
+
}
|
|
284
|
+
if (hasServerPath && hasClientPath) {
|
|
285
|
+
return {
|
|
286
|
+
type: 'server',
|
|
287
|
+
path: exportPath,
|
|
288
|
+
modifiedAt: exportStat.mtime,
|
|
289
|
+
serverPath,
|
|
290
|
+
clientPath,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
return { type: 'static', path: exportPath, modifiedAt: exportStat.mtime };
|
|
294
|
+
}
|
|
295
|
+
function logExportedProjectInfo(project) {
|
|
296
|
+
let modifiedAgo = '';
|
|
297
|
+
// Only show the timestamp for exports older than 1 minute
|
|
298
|
+
if (project.modifiedAt && Date.now() - project.modifiedAt.getTime() > 60000) {
|
|
299
|
+
modifiedAgo = ` - exported ${(0, timeago_js_1.format)(project.modifiedAt)}`;
|
|
300
|
+
}
|
|
301
|
+
log_1.default.log((0, chalk_1.default) `{dim > Project export: ${project.type}${modifiedAgo}}`);
|
|
302
|
+
}
|