@gadgetinc/ggt 0.4.10 → 1.0.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 +165 -93
- package/lib/__generated__/graphql.js +66 -1
- package/lib/__generated__/graphql.js.map +1 -1
- package/lib/commands/deploy.js +328 -230
- package/lib/commands/deploy.js.map +1 -1
- package/lib/commands/dev.js +445 -0
- package/lib/commands/dev.js.map +1 -0
- package/lib/commands/list.js +27 -19
- package/lib/commands/list.js.map +1 -1
- package/lib/commands/login.js +15 -11
- package/lib/commands/login.js.map +1 -1
- package/lib/commands/logout.js +5 -5
- package/lib/commands/logout.js.map +1 -1
- package/lib/commands/open.js +200 -0
- package/lib/commands/open.js.map +1 -0
- package/lib/commands/pull.js +128 -0
- package/lib/commands/pull.js.map +1 -0
- package/lib/commands/push.js +126 -0
- package/lib/commands/push.js.map +1 -0
- package/lib/commands/root.js +46 -28
- package/lib/commands/root.js.map +1 -1
- package/lib/commands/status.js +61 -0
- package/lib/commands/status.js.map +1 -0
- package/lib/commands/version.js +6 -6
- package/lib/commands/version.js.map +1 -1
- package/lib/commands/whoami.js +6 -6
- package/lib/commands/whoami.js.map +1 -1
- package/lib/ggt.js +33 -8
- package/lib/ggt.js.map +1 -1
- package/lib/main.js +5 -0
- package/lib/main.js.map +1 -0
- package/lib/services/app/api/api.js +191 -0
- package/lib/services/app/api/api.js.map +1 -0
- package/lib/services/app/api/operation.js +12 -0
- package/lib/services/app/api/operation.js.map +1 -0
- package/lib/services/app/app.js +44 -10
- package/lib/services/app/app.js.map +1 -1
- package/lib/services/app/{edit/client.js → client.js} +29 -19
- package/lib/services/app/client.js.map +1 -0
- package/lib/services/app/edit/edit.js +67 -31
- package/lib/services/app/edit/edit.js.map +1 -1
- package/lib/services/app/edit/operation.js +4 -3
- package/lib/services/app/edit/operation.js.map +1 -1
- package/lib/services/app/{edit/error.js → error.js} +6 -6
- package/lib/services/app/error.js.map +1 -0
- package/lib/services/command/arg.js +4 -4
- package/lib/services/command/arg.js.map +1 -1
- package/lib/services/command/command.js +9 -7
- package/lib/services/command/command.js.map +1 -1
- package/lib/services/command/context.js +82 -20
- package/lib/services/command/context.js.map +1 -1
- package/lib/services/config/config.js +4 -7
- package/lib/services/config/config.js.map +1 -1
- package/lib/services/config/env.js +1 -1
- package/lib/services/config/env.js.map +1 -1
- package/lib/services/filesync/changes.js +76 -37
- package/lib/services/filesync/changes.js.map +1 -1
- package/lib/services/filesync/conflicts.js +10 -9
- package/lib/services/filesync/conflicts.js.map +1 -1
- package/lib/services/filesync/directory.js +16 -1
- package/lib/services/filesync/directory.js.map +1 -1
- package/lib/services/filesync/error.js +96 -27
- package/lib/services/filesync/error.js.map +1 -1
- package/lib/services/filesync/filesync.js +448 -490
- package/lib/services/filesync/filesync.js.map +1 -1
- package/lib/services/filesync/hashes.js +8 -5
- package/lib/services/filesync/hashes.js.map +1 -1
- package/lib/services/filesync/strategy.js +59 -0
- package/lib/services/filesync/strategy.js.map +1 -0
- package/lib/services/filesync/sync-json.js +475 -0
- package/lib/services/filesync/sync-json.js.map +1 -0
- package/lib/services/http/auth.js +30 -1
- package/lib/services/http/auth.js.map +1 -1
- package/lib/services/http/http.js +5 -0
- package/lib/services/http/http.js.map +1 -1
- package/lib/services/output/confirm.js +149 -0
- package/lib/services/output/confirm.js.map +1 -0
- package/lib/services/output/footer.js +22 -0
- package/lib/services/output/footer.js.map +1 -0
- package/lib/services/output/log/format/pretty.js +2 -1
- package/lib/services/output/log/format/pretty.js.map +1 -1
- package/lib/services/output/log/logger.js +13 -5
- package/lib/services/output/log/logger.js.map +1 -1
- package/lib/services/output/log/structured.js +2 -2
- package/lib/services/output/log/structured.js.map +1 -1
- package/lib/services/output/output.js +197 -0
- package/lib/services/output/output.js.map +1 -0
- package/lib/services/output/print.js +31 -0
- package/lib/services/output/print.js.map +1 -0
- package/lib/services/output/problems.js +84 -0
- package/lib/services/output/problems.js.map +1 -0
- package/lib/services/output/prompt.js +173 -40
- package/lib/services/output/prompt.js.map +1 -1
- package/lib/services/output/report.js +63 -19
- package/lib/services/output/report.js.map +1 -1
- package/lib/services/output/select.js +198 -0
- package/lib/services/output/select.js.map +1 -0
- package/lib/services/output/spinner.js +141 -0
- package/lib/services/output/spinner.js.map +1 -0
- package/lib/services/output/sprint.js +38 -15
- package/lib/services/output/sprint.js.map +1 -1
- package/lib/services/output/symbols.js +23 -0
- package/lib/services/output/symbols.js.map +1 -0
- package/lib/services/output/table.js +98 -0
- package/lib/services/output/table.js.map +1 -0
- package/lib/services/output/timestamp.js +12 -0
- package/lib/services/output/timestamp.js.map +1 -0
- package/lib/services/output/update.js +29 -9
- package/lib/services/output/update.js.map +1 -1
- package/lib/services/user/session.js +4 -0
- package/lib/services/user/session.js.map +1 -1
- package/lib/services/user/user.js +15 -10
- package/lib/services/user/user.js.map +1 -1
- package/lib/services/util/assert.js +11 -0
- package/lib/services/util/assert.js.map +1 -0
- package/lib/services/util/boolean.js +2 -2
- package/lib/services/util/boolean.js.map +1 -1
- package/lib/services/util/function.js +45 -7
- package/lib/services/util/function.js.map +1 -1
- package/lib/services/util/is.js +23 -2
- package/lib/services/util/is.js.map +1 -1
- package/lib/services/util/json.js +16 -13
- package/lib/services/util/json.js.map +1 -1
- package/lib/services/util/object.js +2 -2
- package/lib/services/util/object.js.map +1 -1
- package/lib/services/util/promise.js +5 -2
- package/lib/services/util/promise.js.map +1 -1
- package/lib/services/util/types.js.map +1 -1
- package/npm-shrinkwrap.json +3415 -2973
- package/package.json +47 -40
- package/bin/dev.cmd +0 -3
- package/bin/dev.js +0 -14
- package/bin/run.cmd +0 -3
- package/bin/run.js +0 -5
- package/lib/commands/sync.js +0 -284
- package/lib/commands/sync.js.map +0 -1
- package/lib/services/app/edit/client.js.map +0 -1
- package/lib/services/app/edit/error.js.map +0 -1
- package/lib/services/output/log/printer.js +0 -120
- package/lib/services/output/log/printer.js.map +0 -1
- package/lib/services/output/stream.js +0 -54
- package/lib/services/output/stream.js.map +0 -1
package/lib/commands/deploy.js
CHANGED
|
@@ -1,271 +1,369 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import terminalLink from "terminal-link";
|
|
3
|
+
import { PUBLISH_STATUS_SUBSCRIPTION } from "../services/app/edit/operation.js";
|
|
4
|
+
import { DeployDisallowedError } from "../services/filesync/error.js";
|
|
5
|
+
import { FileSync } from "../services/filesync/filesync.js";
|
|
6
|
+
import { SyncJson, loadSyncJsonDirectory } from "../services/filesync/sync-json.js";
|
|
7
|
+
import { confirm } from "../services/output/confirm.js";
|
|
8
|
+
import { output } from "../services/output/output.js";
|
|
9
|
+
import { println } from "../services/output/print.js";
|
|
10
|
+
import { ProblemSeverity, printProblems, publishIssuesToProblems } from "../services/output/problems.js";
|
|
11
|
+
import { reportErrorAndExit } from "../services/output/report.js";
|
|
12
|
+
import { spin } from "../services/output/spinner.js";
|
|
6
13
|
import { sprint } from "../services/output/sprint.js";
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
14
|
+
import { ts } from "../services/output/timestamp.js";
|
|
15
|
+
import { unreachable } from "../services/util/assert.js";
|
|
16
|
+
import { isGraphQLErrors } from "../services/util/is.js";
|
|
17
|
+
import { args as PushArgs } from "./push.js";
|
|
18
|
+
export const args = {
|
|
19
|
+
...PushArgs,
|
|
20
|
+
"--env": {
|
|
21
|
+
type: String,
|
|
22
|
+
alias: [
|
|
23
|
+
"-e",
|
|
24
|
+
"--environment",
|
|
25
|
+
"--from"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
"--allow-problems": {
|
|
29
|
+
type: Boolean,
|
|
30
|
+
alias: "--allow-issues"
|
|
31
|
+
},
|
|
32
|
+
"--allow-charges": {
|
|
33
|
+
type: Boolean
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
export const usage = (ctx)=>{
|
|
37
|
+
if (ctx.args["-h"]) {
|
|
38
|
+
return sprint`
|
|
39
|
+
Deploy an environment to production.
|
|
40
|
+
|
|
41
|
+
Your local files must match your environment's files
|
|
42
|
+
before you can deploy. Changes are tracked from
|
|
43
|
+
the last "ggt dev", "ggt push", or "ggt pull" run locally.
|
|
44
|
+
|
|
45
|
+
{bold USAGE}
|
|
46
|
+
ggt deploy
|
|
47
|
+
|
|
48
|
+
{bold EXAMPLES}
|
|
49
|
+
$ ggt deploy
|
|
50
|
+
$ ggt deploy --from=staging
|
|
51
|
+
$ ggt deploy --from=staging --force
|
|
52
|
+
$ ggt deploy --from=staging --force --allow-problems
|
|
53
|
+
|
|
54
|
+
{bold FLAGS}
|
|
55
|
+
-a, --app=<name> The application to deploy
|
|
56
|
+
-e, --from=<env> The environment to deploy from
|
|
57
|
+
--force Discard changes to your environment's filesystem
|
|
58
|
+
--allow-problems Deploy regardless of any problems the environment has
|
|
59
|
+
--allow-charges Deploy even if doing so will add charges to your account
|
|
60
|
+
|
|
61
|
+
Run "ggt deploy --help" for more information.
|
|
62
|
+
`;
|
|
63
|
+
}
|
|
64
|
+
return sprint`
|
|
65
|
+
Deploy an environment to production.
|
|
66
|
+
|
|
67
|
+
Your local files must match your environment's files
|
|
68
|
+
before you can deploy. Changes are tracked from
|
|
69
|
+
the last "ggt dev", "ggt push", or "ggt pull" run locally.
|
|
70
|
+
|
|
71
|
+
If your local files don't match your environment's files, you will
|
|
72
|
+
be prompted to push your local files before you can deploy.
|
|
73
|
+
|
|
74
|
+
If your environment has un-pulled changes, and "--force" is not
|
|
75
|
+
passed, you will be prompted to {underline discard them} or abort the deploy.
|
|
10
76
|
|
|
11
77
|
{bold USAGE}
|
|
12
|
-
ggt deploy [DIRECTORY] [--app=<name>]
|
|
13
78
|
|
|
14
|
-
|
|
15
|
-
|
|
79
|
+
ggt deploy [--app=<name>] [--from=<env>] [--force]
|
|
80
|
+
[--allow-problems] [--allow-charges]
|
|
81
|
+
|
|
82
|
+
{bold EXAMPLES}
|
|
83
|
+
|
|
84
|
+
$ ggt deploy
|
|
85
|
+
$ ggt deploy --from=staging
|
|
86
|
+
$ ggt deploy --from=staging --force
|
|
87
|
+
$ ggt deploy --from=staging --force --allow-problems
|
|
88
|
+
$ ggt deploy --from=staging --force --allow-problems --allow-charges
|
|
16
89
|
|
|
17
90
|
{bold FLAGS}
|
|
18
|
-
-a, --app=<name> The Gadget application to deploy
|
|
19
|
-
--force Deploy the Gadget application regardless of any issues it may have
|
|
20
91
|
|
|
21
|
-
|
|
22
|
-
|
|
92
|
+
-a, --app, --application=<name>
|
|
93
|
+
The application to deploy.
|
|
94
|
+
|
|
95
|
+
Defaults to the application within the ".gadget/sync.json"
|
|
96
|
+
file in the current directory or any parent directories.
|
|
23
97
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
you would like to deploy anyways.
|
|
98
|
+
-e, --env, --environment, --from=<name>
|
|
99
|
+
The environment to deploy from.
|
|
27
100
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
you will be prompted to run a one-time sync to ensure the files remain consistent with
|
|
31
|
-
what is on the remote.
|
|
32
|
-
• You may wish to keep ggt sync running in the background before trying to run ggt deploy
|
|
101
|
+
Defaults to the environment within the ".gadget/sync.json"
|
|
102
|
+
file in the current directory or any parent directories.
|
|
33
103
|
|
|
34
|
-
|
|
35
|
-
|
|
104
|
+
-f, --force
|
|
105
|
+
Discard any changes made to your environment's filesystem
|
|
106
|
+
since the last "ggt dev", "ggt push", or "ggt pull".
|
|
36
107
|
|
|
37
|
-
|
|
38
|
-
Editor https://example.gadget.app/edit
|
|
39
|
-
Playground https://example.gadget.app/api/graphql/playground
|
|
40
|
-
Docs https://docs.gadget.dev/api/example
|
|
108
|
+
Defaults to false.
|
|
41
109
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
110
|
+
--allow-problems, --allow-issues
|
|
111
|
+
Deploy your environment to production regardless of any problems
|
|
112
|
+
it may have.
|
|
45
113
|
|
|
114
|
+
These problems may include:
|
|
115
|
+
• Gelly syntax errors
|
|
116
|
+
• TypeScript errors
|
|
117
|
+
• Models with missing fields
|
|
46
118
|
|
|
47
|
-
|
|
48
|
-
✔ DONE
|
|
119
|
+
Defaults to false.
|
|
49
120
|
|
|
50
|
-
|
|
51
|
-
|
|
121
|
+
--allow-charges
|
|
122
|
+
Allows "ggt deploy" to continue when deploying your environment
|
|
123
|
+
to production will add charges to your account.
|
|
52
124
|
|
|
53
|
-
|
|
54
|
-
✔ DONE
|
|
125
|
+
Defaults to false.
|
|
55
126
|
|
|
56
|
-
|
|
57
|
-
|
|
127
|
+
--allow-unknown-directory
|
|
128
|
+
Allows "ggt deploy" to continue when the current directory, nor
|
|
129
|
+
any parent directories, contain a ".gadget/sync.json" file
|
|
130
|
+
within it.
|
|
58
131
|
|
|
59
|
-
|
|
132
|
+
Defaults to false.
|
|
133
|
+
|
|
134
|
+
--allow-different-app
|
|
135
|
+
Allows "ggt deploy" to continue with a different "--app" than the
|
|
136
|
+
one found within the ".gadget/sync.json" file.
|
|
137
|
+
|
|
138
|
+
Defaults to false.
|
|
139
|
+
|
|
140
|
+
Run "ggt deploy -h" for less information.
|
|
60
141
|
`;
|
|
61
|
-
export const args = {
|
|
62
|
-
...FileSyncArgs
|
|
63
|
-
};
|
|
64
|
-
export var Action;
|
|
65
|
-
(function(Action) {
|
|
66
|
-
Action["DEPLOY_ANYWAYS"] = "Deploy anyways";
|
|
67
|
-
Action["SYNC_ONCE"] = "Sync once";
|
|
68
|
-
Action["CANCEL"] = "Cancel (Ctrl+C)";
|
|
69
|
-
})(Action || (Action = {}));
|
|
70
|
-
const AppDeploymentStepsToAppDeployState = (step)=>{
|
|
71
|
-
switch(step){
|
|
72
|
-
case "NOT_STARTED":
|
|
73
|
-
return "Deploy not started";
|
|
74
|
-
case "STARTING":
|
|
75
|
-
case "BUILDING_ASSETS":
|
|
76
|
-
case "UPLOADING_ASSETS":
|
|
77
|
-
return "Building frontend assets";
|
|
78
|
-
case "CONVERGING_STORAGE":
|
|
79
|
-
return "Setting up database";
|
|
80
|
-
case "PUBLISHING_TREE":
|
|
81
|
-
return "Copying development";
|
|
82
|
-
case "RELOADING_SANDBOX":
|
|
83
|
-
return "Restarting app";
|
|
84
|
-
case "COMPLETED":
|
|
85
|
-
return "Deploy completed";
|
|
86
|
-
default:
|
|
87
|
-
return "Unknown step";
|
|
88
|
-
}
|
|
89
142
|
};
|
|
90
|
-
|
|
91
|
-
(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
143
|
+
export const command = async (ctx)=>{
|
|
144
|
+
const directory = await loadSyncJsonDirectory(process.cwd());
|
|
145
|
+
const syncJson = await SyncJson.loadOrInit(ctx, {
|
|
146
|
+
directory
|
|
147
|
+
});
|
|
148
|
+
println({
|
|
149
|
+
ensureEmptyLineAbove: true
|
|
150
|
+
})`
|
|
151
|
+
Deploying ${syncJson.env.name} to ${terminalLink(syncJson.app.primaryDomain, `https://${syncJson.app.primaryDomain}/`)}
|
|
152
|
+
`;
|
|
153
|
+
const filesync = new FileSync(syncJson);
|
|
154
|
+
const hashes = await filesync.hashes(ctx);
|
|
155
|
+
if (!hashes.inSync && (hashes.localChangesToPush.size > 0 || !hashes.onlyDotGadgetFilesChanged)) {
|
|
156
|
+
// the following is true:
|
|
157
|
+
// 1. our local files don't match our environment's files
|
|
158
|
+
// 2. we have local changes to push or non .gadget/ files have changed on our environment
|
|
159
|
+
// therefor, we need to push before we can deploy
|
|
160
|
+
await filesync.print(ctx, {
|
|
161
|
+
hashes
|
|
162
|
+
});
|
|
163
|
+
println({
|
|
164
|
+
ensureEmptyLineAbove: true
|
|
165
|
+
})`
|
|
166
|
+
Your environment's files must match your local files before you can deploy.
|
|
167
|
+
`;
|
|
168
|
+
// some scenarios make the confirmation to push changes imply the
|
|
169
|
+
// --force flag (e.g. when both local and environment files have
|
|
170
|
+
// changed, or when only environment files have changed)
|
|
171
|
+
let implicitForce = false;
|
|
172
|
+
if (output.isInteractive) {
|
|
173
|
+
let message;
|
|
174
|
+
switch(true){
|
|
175
|
+
case hashes.bothChanged:
|
|
176
|
+
message = sprint`Would you like to push your local changes and {underline discard your environment's} changes now?`;
|
|
177
|
+
implicitForce = true;
|
|
178
|
+
break;
|
|
179
|
+
case hashes.localChangesToPush.size > 0:
|
|
180
|
+
message = sprint`Would you like to push your local changes now?`;
|
|
181
|
+
break;
|
|
182
|
+
case hashes.environmentChanges.size > 0:
|
|
183
|
+
message = sprint`Do you want to {underline discard your environment's} changes now?`;
|
|
184
|
+
implicitForce = true;
|
|
185
|
+
break;
|
|
186
|
+
default:
|
|
187
|
+
unreachable("no changes to push or discard");
|
|
112
188
|
}
|
|
189
|
+
await confirm({
|
|
190
|
+
ensureEmptyLineAbove: true
|
|
191
|
+
})(message);
|
|
113
192
|
} else {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
|
|
193
|
+
println({
|
|
194
|
+
ensureEmptyLineAbove: true
|
|
195
|
+
})`
|
|
196
|
+
Assuming you want to push your local files now.
|
|
197
|
+
`;
|
|
118
198
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Runs the deploy process.
|
|
124
|
-
*/ export const command = async (ctx, firstRun = true)=>{
|
|
125
|
-
const spinner = ora();
|
|
126
|
-
let prevProgress = AppDeploymentStepsToAppDeployState("NOT_STARTED");
|
|
127
|
-
let action;
|
|
128
|
-
// deploy --force != sync --force
|
|
129
|
-
const filesync = await FileSync.init(ctx.child({
|
|
130
|
-
overwrite: {
|
|
131
|
-
"--force": false
|
|
132
|
-
}
|
|
133
|
-
}));
|
|
134
|
-
if (firstRun) {
|
|
135
|
-
ctx.log.printlns`App: ${filesync.app.slug}`;
|
|
136
|
-
}
|
|
137
|
-
const { inSync } = await filesync.hashes();
|
|
138
|
-
if (!inSync) {
|
|
139
|
-
ctx.log.printlns`
|
|
140
|
-
Local files have diverged from remote. Run a sync once to converge your files or keep {italic ggt sync} running in the background.
|
|
141
|
-
`;
|
|
142
|
-
action = await select(ctx, {
|
|
143
|
-
message: "How would you like to proceed?",
|
|
144
|
-
choices: [
|
|
145
|
-
"Cancel (Ctrl+C)",
|
|
146
|
-
"Sync once"
|
|
147
|
-
]
|
|
199
|
+
await filesync.push(ctx, {
|
|
200
|
+
hashes,
|
|
201
|
+
force: implicitForce || ctx.args["--force"]
|
|
148
202
|
});
|
|
149
|
-
switch(action){
|
|
150
|
-
case "Sync once":
|
|
151
|
-
{
|
|
152
|
-
await filesync.sync();
|
|
153
|
-
break;
|
|
154
|
-
}
|
|
155
|
-
case "Cancel (Ctrl+C)":
|
|
156
|
-
{
|
|
157
|
-
process.exit(0);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
203
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const message = error.cause[0]?.message;
|
|
174
|
-
if (message && message.includes("GGT_PAYMENT_REQUIRED")) {
|
|
175
|
-
ctx.log.println("Production environment limit reached. Upgrade your plan to deploy");
|
|
176
|
-
} else {
|
|
177
|
-
ctx.log.println(`${message}`);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
204
|
+
const variables = {
|
|
205
|
+
localFilesVersion: String(syncJson.filesVersion),
|
|
206
|
+
force: ctx.args["--allow-problems"],
|
|
207
|
+
allowCharges: ctx.args["--allow-charges"]
|
|
208
|
+
};
|
|
209
|
+
let spinner;
|
|
210
|
+
let currentStep = AppDeploymentSteps.NOT_STARTED;
|
|
211
|
+
let printedProblems = false;
|
|
212
|
+
const subscription = syncJson.edit.subscribe({
|
|
213
|
+
subscription: PUBLISH_STATUS_SUBSCRIPTION,
|
|
214
|
+
variables,
|
|
215
|
+
onError: async (error)=>{
|
|
180
216
|
ctx.log.error("failed to deploy", {
|
|
181
217
|
error
|
|
182
218
|
});
|
|
183
|
-
|
|
184
|
-
|
|
219
|
+
spinner?.fail(stepToSpinnerStart(syncJson, currentStep) + " " + ts());
|
|
220
|
+
if (isGraphQLErrors(error.cause)) {
|
|
221
|
+
const graphqlError = error.cause[0];
|
|
222
|
+
assert(graphqlError, "expected graphqlError to be defined");
|
|
223
|
+
switch(true){
|
|
224
|
+
case graphqlError.extensions["requiresUpgrade"]:
|
|
225
|
+
println({
|
|
226
|
+
ensureEmptyLineAbove: true
|
|
227
|
+
})(graphqlError.message.replace(/GGT_PAYMENT_REQUIRED:?\s*/, ""));
|
|
228
|
+
process.exit(1);
|
|
229
|
+
break;
|
|
230
|
+
case graphqlError.extensions["requiresAdditionalCharge"]:
|
|
231
|
+
println({
|
|
232
|
+
ensureEmptyLineAbove: true
|
|
233
|
+
})(graphqlError.message.replace(/GGT_PAYMENT_REQUIRED:?\s*/, ""));
|
|
234
|
+
await confirm({
|
|
235
|
+
ensureEmptyLineAbove: true
|
|
236
|
+
})("Do you want to continue?");
|
|
237
|
+
subscription.resubscribe({
|
|
238
|
+
...variables,
|
|
239
|
+
allowCharges: true
|
|
240
|
+
});
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
await reportErrorAndExit(ctx, error);
|
|
185
245
|
},
|
|
186
246
|
onData: async ({ publishStatus })=>{
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
return `\n\t ${chalk.red("✖")} ${titleFormatter(e)}: ${e.nodeLabels?.map((label)=>`${chalk.bgWhite.black(label.type.toLowerCase())} ${chalk.white.bold(label.identifier)}`).join("")}`;
|
|
198
|
-
}).join("")}`);
|
|
199
|
-
}
|
|
200
|
-
};
|
|
201
|
-
const titleFormatter = (e)=>{
|
|
202
|
-
if (e.node?.type === "SourceFile") {
|
|
203
|
-
return `${chalk.magentaBright("Typescript")} ${e.message.replace(/[.,]+$/, "")}`;
|
|
204
|
-
}
|
|
205
|
-
return e.message.replace(/[.,]+$/, "");
|
|
206
|
-
};
|
|
207
|
-
const issuesWithNoNode = issues.filter((item)=>item.node?.apiIdentifier);
|
|
208
|
-
const groupedByApiIdentifier = groupByProperty(issuesWithNoNode, "apiIdentifier");
|
|
209
|
-
printIssues(groupedByApiIdentifier);
|
|
210
|
-
const remainingItems = issues.filter((item)=>!item.node?.apiIdentifier);
|
|
211
|
-
const groupedByName = groupByProperty(remainingItems, "name");
|
|
212
|
-
printIssues(groupedByName);
|
|
213
|
-
if (!ctx.args["--force"]) {
|
|
214
|
-
unsubscribe();
|
|
215
|
-
action = await select(ctx, {
|
|
216
|
-
message: "Detected some issues with your app. How would you like to proceed?",
|
|
217
|
-
choices: [
|
|
218
|
-
"Cancel (Ctrl+C)",
|
|
219
|
-
"Deploy anyways"
|
|
220
|
-
]
|
|
221
|
-
});
|
|
222
|
-
switch(action){
|
|
223
|
-
case "Deploy anyways":
|
|
224
|
-
{
|
|
225
|
-
ctx.args["--force"] = true;
|
|
226
|
-
await command(ctx, false);
|
|
227
|
-
break;
|
|
228
|
-
}
|
|
229
|
-
case "Cancel (Ctrl+C)":
|
|
230
|
-
{
|
|
231
|
-
process.exit(0);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
247
|
+
if (!publishStatus) {
|
|
248
|
+
ctx.log.warn("received empty publish status");
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const { publishStarted, progress: step, issues, status } = publishStatus;
|
|
252
|
+
if (!printedProblems && issues.length > 0) {
|
|
253
|
+
printedProblems = true;
|
|
254
|
+
const fatalIssues = issues.filter((issue)=>issue.severity === ProblemSeverity.Fatal);
|
|
255
|
+
if (fatalIssues.length > 0) {
|
|
256
|
+
await reportErrorAndExit(ctx, new DeployDisallowedError(publishIssuesToProblems(fatalIssues)));
|
|
234
257
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
258
|
+
println({
|
|
259
|
+
ensureEmptyLineAbove: true
|
|
260
|
+
})`{bold Problems found.}`;
|
|
261
|
+
printProblems({
|
|
262
|
+
problems: publishIssuesToProblems(issues)
|
|
263
|
+
});
|
|
264
|
+
if (!publishStarted) {
|
|
265
|
+
await confirm("Do you want to continue?");
|
|
266
|
+
subscription.resubscribe({
|
|
267
|
+
...variables,
|
|
268
|
+
force: true
|
|
242
269
|
});
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
270
|
+
} else {
|
|
271
|
+
assert(ctx.args["--allow-problems"], "expected --allow-problems to be true");
|
|
272
|
+
println({
|
|
273
|
+
ensureEmptyLineAbove: true
|
|
274
|
+
})`Deploying regardless of problems because {bold "--allow-problems"} was passed.`;
|
|
275
|
+
}
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (status?.code === "Errored") {
|
|
279
|
+
subscription.unsubscribe();
|
|
280
|
+
spinner?.fail(stepToSpinnerStart(syncJson, currentStep) + " " + ts());
|
|
281
|
+
if (status.message) {
|
|
282
|
+
println({
|
|
283
|
+
ensureEmptyLineAbove: true
|
|
284
|
+
})`{red ${status.message}}`;
|
|
252
285
|
}
|
|
253
|
-
if (
|
|
254
|
-
|
|
255
|
-
|
|
286
|
+
if (status.output) {
|
|
287
|
+
println({
|
|
288
|
+
ensureEmptyLineAbove: true
|
|
289
|
+
})`${terminalLink("Check logs", status.output)}`;
|
|
256
290
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
if (step === AppDeploymentSteps.COMPLETED) {
|
|
294
|
+
subscription.unsubscribe();
|
|
295
|
+
spinner?.succeed(stepToSpinnerEnd(syncJson, currentStep));
|
|
296
|
+
let message = sprint`{green Deploy successful!}`;
|
|
297
|
+
if (status?.output) {
|
|
298
|
+
message += ` ${terminalLink("Check logs", status.output)}.`;
|
|
299
|
+
}
|
|
300
|
+
println({
|
|
301
|
+
ensureEmptyLineAbove: true
|
|
302
|
+
})(message);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
if (step !== currentStep) {
|
|
306
|
+
const spinnerText = stepToSpinnerStart(syncJson, step);
|
|
307
|
+
if (spinnerText !== spinner?.text) {
|
|
308
|
+
// stop the current spinner, if any, and start a new one
|
|
309
|
+
spinner?.succeed(stepToSpinnerEnd(syncJson, currentStep));
|
|
310
|
+
const ensureEmptyLineAbove = currentStep === AppDeploymentSteps.NOT_STARTED || !output.isInteractive;
|
|
311
|
+
spinner = spin({
|
|
312
|
+
ensureEmptyLineAbove
|
|
313
|
+
})(spinnerText);
|
|
265
314
|
}
|
|
315
|
+
currentStep = step;
|
|
266
316
|
}
|
|
267
317
|
}
|
|
268
318
|
});
|
|
269
319
|
};
|
|
320
|
+
export const AppDeploymentSteps = Object.freeze({
|
|
321
|
+
NOT_STARTED: "NOT_STARTED",
|
|
322
|
+
STARTING: "STARTING",
|
|
323
|
+
BUILDING_ASSETS: "BUILDING_ASSETS",
|
|
324
|
+
UPLOADING_ASSETS: "UPLOADING_ASSETS",
|
|
325
|
+
CONVERGING_STORAGE: "CONVERGING_STORAGE",
|
|
326
|
+
PUBLISHING_TREE: "PUBLISHING_TREE",
|
|
327
|
+
RELOADING_SANDBOX: "RELOADING_SANDBOX",
|
|
328
|
+
COMPLETED: "COMPLETED"
|
|
329
|
+
});
|
|
330
|
+
export const stepToSpinnerStart = (syncJson, step)=>{
|
|
331
|
+
switch(step){
|
|
332
|
+
case AppDeploymentSteps.NOT_STARTED:
|
|
333
|
+
case AppDeploymentSteps.STARTING:
|
|
334
|
+
case AppDeploymentSteps.BUILDING_ASSETS:
|
|
335
|
+
case AppDeploymentSteps.UPLOADING_ASSETS:
|
|
336
|
+
return "Building frontend assets.";
|
|
337
|
+
case AppDeploymentSteps.CONVERGING_STORAGE:
|
|
338
|
+
return "Setting up database.";
|
|
339
|
+
case AppDeploymentSteps.PUBLISHING_TREE:
|
|
340
|
+
return `Copying ${syncJson.env.name}.`;
|
|
341
|
+
case AppDeploymentSteps.RELOADING_SANDBOX:
|
|
342
|
+
return "Restarting app.";
|
|
343
|
+
case AppDeploymentSteps.COMPLETED:
|
|
344
|
+
return "Deploy complete!";
|
|
345
|
+
default:
|
|
346
|
+
return "Unknown step.";
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
export const stepToSpinnerEnd = (syncJson, step)=>{
|
|
350
|
+
switch(step){
|
|
351
|
+
case AppDeploymentSteps.NOT_STARTED:
|
|
352
|
+
case AppDeploymentSteps.STARTING:
|
|
353
|
+
case AppDeploymentSteps.BUILDING_ASSETS:
|
|
354
|
+
case AppDeploymentSteps.UPLOADING_ASSETS:
|
|
355
|
+
return `Built frontend assets. ${ts()}`;
|
|
356
|
+
case AppDeploymentSteps.CONVERGING_STORAGE:
|
|
357
|
+
return `Setup database. ${ts()}`;
|
|
358
|
+
case AppDeploymentSteps.PUBLISHING_TREE:
|
|
359
|
+
return `Copied ${syncJson.env.name}. ${ts()}`;
|
|
360
|
+
case AppDeploymentSteps.RELOADING_SANDBOX:
|
|
361
|
+
return `Restarted app. ${ts()}`;
|
|
362
|
+
case AppDeploymentSteps.COMPLETED:
|
|
363
|
+
return "Deploy successful!";
|
|
364
|
+
default:
|
|
365
|
+
return `Completed unknown step. ${ts()}`;
|
|
366
|
+
}
|
|
367
|
+
};
|
|
270
368
|
|
|
271
369
|
//# sourceMappingURL=deploy.js.map
|