@cedarjs/cli 4.2.0 → 4.2.1-next.258
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/dist/cfw.js +8 -6
- package/dist/commands/build/buildHandler.js +43 -42
- package/dist/commands/build/buildPackagesTask.js +6 -6
- package/dist/commands/build.js +7 -1
- package/dist/commands/deploy/baremetal/SshExecutor.js +13 -4
- package/dist/commands/deploy/baremetal/baremetalHandler.js +117 -65
- package/dist/commands/deploy/baremetal.js +24 -3
- package/dist/commands/deploy/flightcontrolHandler.js +16 -14
- package/dist/commands/deploy/helpers/deployHandler.js +10 -5
- package/dist/commands/deploy/packing/nft.js +1 -2
- package/dist/commands/deploy/render.js +1 -1
- package/dist/commands/deploy/renderHandler.js +22 -12
- package/dist/commands/deploy/serverlessHandler.js +67 -25
- package/dist/commands/destroy/component/component.js +2 -3
- package/dist/commands/destroy/directive/directive.js +1 -3
- package/dist/commands/destroy/directive/directiveHandler.js +2 -4
- package/dist/commands/destroy/function/function.js +1 -3
- package/dist/commands/destroy/handlerHelpers.js +16 -16
- package/dist/commands/destroy/helpers.js +8 -2
- package/dist/commands/destroy/layout/layout.js +1 -2
- package/dist/commands/destroy/page/pageHandler.js +1 -1
- package/dist/commands/destroy/scaffold/scaffoldHandler.js +28 -9
- package/dist/commands/destroy/sdl/sdlHandler.js +1 -1
- package/dist/commands/dev/devHandler.js +25 -25
- package/dist/commands/dev.js +3 -0
- package/dist/commands/experimental/live-queries/liveQueriesHandler.js +110 -4
- package/dist/commands/experimental/setupInngest.js +1 -1
- package/dist/commands/experimental/setupInngestHandler.js +12 -11
- package/dist/commands/experimental/setupOpentelemetry.js +1 -1
- package/dist/commands/experimental/setupOpentelemetryHandler.js +11 -7
- package/dist/commands/experimental/setupReactCompiler.js +1 -1
- package/dist/commands/experimental/setupReactCompilerHandler.js +45 -30
- package/dist/commands/experimental/setupRscHandler.js +14 -11
- package/dist/commands/experimental/setupStreamingSsr.js +1 -1
- package/dist/commands/experimental/setupStreamingSsrHandler.js +46 -31
- package/dist/commands/experimental/templates/rsc/Document.tsx.template +1 -1
- package/dist/commands/experimental/templates/rsc/entry.client.tsx.template +8 -8
- package/dist/commands/experimental/templates/streamingSsr/Document.tsx.template +1 -1
- package/dist/commands/experimental/templates/streamingSsr/entry.client.tsx.template +6 -6
- package/dist/commands/experimental/util.js +3 -2
- package/dist/commands/generate/cell/cellHandler.js +22 -21
- package/dist/commands/generate/component/componentHandler.js +14 -16
- package/dist/commands/generate/dataMigration/dataMigration.js +24 -13
- package/dist/commands/generate/dbAuth/dbAuth.js +1 -0
- package/dist/commands/generate/dbAuth/dbAuthHandler.js +40 -30
- package/dist/commands/generate/directive/directiveHandler.js +12 -14
- package/dist/commands/generate/function/function.js +1 -0
- package/dist/commands/generate/function/functionHandler.js +12 -17
- package/dist/commands/generate/helpers.js +17 -17
- package/dist/commands/generate/job/job.js +1 -0
- package/dist/commands/generate/job/jobHandler.js +15 -17
- package/dist/commands/generate/layout/layoutHandler.js +13 -16
- package/dist/commands/generate/model/model.js +1 -0
- package/dist/commands/generate/model/modelHandler.js +9 -3
- package/dist/commands/generate/ogImage/ogImage.js +1 -0
- package/dist/commands/generate/ogImage/ogImageHandler.js +16 -9
- package/dist/commands/generate/package/packageHandler.js +32 -49
- package/dist/commands/generate/page/pageHandler.js +25 -22
- package/dist/commands/generate/realtime/realtime.js +1 -1
- package/dist/commands/generate/realtime/realtimeHandler.js +46 -20
- package/dist/commands/generate/scaffold/scaffold.js +1 -0
- package/dist/commands/generate/scaffold/scaffoldHandler.js +35 -27
- package/dist/commands/generate/script/script.js +1 -0
- package/dist/commands/generate/script/templates/tsconfig.json.template +14 -0
- package/dist/commands/generate/sdl/sdl.js +4 -3
- package/dist/commands/generate/sdl/sdlHandler.js +38 -18
- package/dist/commands/generate/secret/secret.js +19 -19
- package/dist/commands/generate/service/service.js +5 -5
- package/dist/commands/generate/service/serviceHandler.js +59 -22
- package/dist/commands/generate/yargsCommandHelpers.js +6 -1
- package/dist/commands/generate/yargsHandlerHelpers.js +18 -10
- package/dist/commands/generate.js +3 -10
- package/dist/commands/jobsHandler.js +3 -2
- package/dist/commands/prismaHandler.js +10 -9
- package/dist/commands/serve.js +84 -137
- package/dist/commands/serveApiHandler.js +5 -5
- package/dist/commands/serveBothHandler.js +10 -7
- package/dist/commands/serveWebHandler.js +2 -2
- package/dist/commands/setup/auth/auth.js +12 -6
- package/dist/commands/setup/cache/cacheHandler.js +11 -6
- package/dist/commands/setup/deploy/deploy.js +4 -3
- package/dist/commands/setup/deploy/helpers/helpers.js +5 -1
- package/dist/commands/setup/deploy/helpers/index.js +157 -5
- package/dist/commands/setup/deploy/providers/baremetalHandler.js +26 -4
- package/dist/commands/setup/deploy/providers/coherenceHandler.js +53 -25
- package/dist/commands/setup/deploy/providers/flightcontrolHandler.js +33 -23
- package/dist/commands/setup/deploy/providers/netlify.js +6 -0
- package/dist/commands/setup/deploy/providers/netlifyHandler.js +112 -11
- package/dist/commands/setup/deploy/providers/renderHandler.js +10 -5
- package/dist/commands/setup/deploy/providers/serverlessHandler.js +5 -3
- package/dist/commands/setup/deploy/providers/universal-deploy.js +11 -0
- package/dist/commands/setup/deploy/providers/universalDeployHandler.js +188 -0
- package/dist/commands/setup/deploy/providers/vercel.js +6 -0
- package/dist/commands/setup/deploy/providers/vercelHandler.js +113 -12
- package/dist/commands/setup/deploy/templates/baremetal.js +3 -2
- package/dist/commands/setup/deploy/templates/flightcontrol.js +60 -49
- package/dist/commands/setup/deploy/templates/netlify.js +2 -1
- package/dist/commands/setup/deploy/templates/netlifyUD.js +31 -0
- package/dist/commands/setup/docker/docker.js +1 -1
- package/dist/commands/setup/docker/dockerHandler.js +72 -37
- package/dist/commands/setup/docker/templates/Dockerfile.npm +119 -0
- package/dist/commands/setup/docker/templates/Dockerfile.pnpm +112 -0
- package/dist/commands/setup/docker/templates/{Dockerfile → Dockerfile.yarn} +1 -1
- package/dist/commands/setup/docker/templates/docker-compose.dev.yml +2 -2
- package/dist/commands/setup/generator/generatorHandler.js +4 -3
- package/dist/commands/setup/graphql/features/fragments/fragmentsHandler.js +2 -2
- package/dist/commands/setup/graphql/features/trustedDocuments/trustedDocumentsHandler.js +2 -2
- package/dist/commands/setup/i18n/i18nHandler.js +18 -15
- package/dist/commands/setup/jobs/jobsHandler.js +10 -5
- package/dist/commands/setup/mailer/mailerHandler.js +11 -9
- package/dist/commands/setup/package/packageHandler.js +14 -10
- package/dist/commands/setup/realtime/realtimeHandler.js +22 -20
- package/dist/commands/setup/server-file/serverFileHandler.js +16 -8
- package/dist/commands/setup/tsconfig/tsconfigHandler.js +5 -3
- package/dist/commands/setup/ui/helpers/helpers.js +5 -1
- package/dist/commands/setup/ui/libraries/chakra-uiHandler.js +11 -5
- package/dist/commands/setup/ui/libraries/mantineHandler.js +21 -13
- package/dist/commands/setup/ui/libraries/tailwindcssHandler.js +38 -26
- package/dist/commands/setup/uploads/uploadsHandler.js +7 -4
- package/dist/commands/setup.js +1 -2
- package/dist/commands/test/testHandler.js +2 -1
- package/dist/commands/test/testHandlerEsm.js +2 -2
- package/dist/commands/type-checkHandler.js +4 -6
- package/dist/commands/upgrade/upgradeHandler.js +2 -4
- package/dist/index.js +10 -4
- package/dist/lib/configureStorybook.js +2 -2
- package/dist/lib/exec.js +36 -24
- package/dist/lib/exit.js +19 -4
- package/dist/lib/extendFile.js +22 -12
- package/dist/lib/index.js +119 -85
- package/dist/lib/merge/algorithms.js +4 -1
- package/dist/lib/merge/index.js +76 -41
- package/dist/lib/merge/semanticIdentity.js +18 -6
- package/dist/lib/merge/strategy.js +86 -36
- package/dist/lib/packages.js +23 -13
- package/dist/lib/plugin.js +12 -5
- package/dist/lib/pluralHelpers.js +1 -1
- package/dist/lib/project.js +3 -1
- package/dist/lib/rollback.js +7 -7
- package/dist/lib/schemaHelpers.js +12 -12
- package/dist/lib/test.js +4 -0
- package/dist/lib/updateCheck.js +6 -4
- package/dist/middleware/checkNodeVersion.js +5 -0
- package/dist/plugin.js +18 -12
- package/dist/telemetry/exporter.js +12 -5
- package/dist/telemetry/index.js +4 -3
- package/dist/telemetry/resource.js +9 -5
- package/dist/telemetry/send.js +14 -10
- package/package.json +15 -12
- package/dist/commands/setup/vite/templates/vite.config.ts.template +0 -19
- package/dist/commands/setup/vite/vite.js +0 -38
- package/dist/commands/setup/vite/viteHandler.js +0 -82
- /package/dist/{index.d.js → global.d.js} +0 -0
package/dist/cfw.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import Configstore from "configstore";
|
|
5
|
-
import execa from "execa";
|
|
6
5
|
import { terminalLink } from "termi-link";
|
|
6
|
+
import { runScriptSync } from "@cedarjs/cli-helpers/packageManager/exec";
|
|
7
7
|
import { getConfigPath } from "@cedarjs/project-config";
|
|
8
8
|
const config = new Configstore("@cedarjs/cli");
|
|
9
9
|
const CFW_PATH = process.env.CFW_PATH || config.get("CFW_PATH");
|
|
@@ -30,14 +30,16 @@ const helpCommands = ["help", "--help"];
|
|
|
30
30
|
if (!command.length || command.some((cmd) => helpCommands.includes(cmd))) {
|
|
31
31
|
command = ["run"];
|
|
32
32
|
}
|
|
33
|
+
const script = command[0];
|
|
34
|
+
const args = command.slice(1);
|
|
33
35
|
try {
|
|
34
|
-
|
|
36
|
+
runScriptSync(script, args, {
|
|
35
37
|
stdio: "inherit",
|
|
36
38
|
cwd: absCfwPath,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
39
|
+
// @ts-expect-error - testUtils.d.ts augments ProcessEnv with
|
|
40
|
+
// CEDAR_DISABLE_TELEMETRY
|
|
41
|
+
env: { CEDAR_CWD: projectPath }
|
|
40
42
|
});
|
|
41
|
-
} catch
|
|
43
|
+
} catch {
|
|
42
44
|
console.log();
|
|
43
45
|
}
|
|
@@ -19,10 +19,8 @@ import { generate } from "@cedarjs/internal/dist/generate/generate";
|
|
|
19
19
|
import { generateGqlormArtifacts } from "@cedarjs/internal/dist/generate/gqlormSchema";
|
|
20
20
|
import { loadAndValidateSdls } from "@cedarjs/internal/dist/validateSchema";
|
|
21
21
|
import { detectPrerenderRoutes } from "@cedarjs/prerender/detection";
|
|
22
|
-
import {} from "@cedarjs/project-config";
|
|
23
22
|
import { timedTelemetry } from "@cedarjs/telemetry";
|
|
24
23
|
import { buildCedarApp } from "@cedarjs/vite/build";
|
|
25
|
-
import { buildUDApiServer } from "@cedarjs/vite/buildUDApiServer";
|
|
26
24
|
import { generatePrismaCommand } from "../../lib/generatePrismaClient.js";
|
|
27
25
|
import { getPaths, getConfig } from "../../lib/index.js";
|
|
28
26
|
import { buildPackagesTask } from "./buildPackagesTask.js";
|
|
@@ -80,14 +78,16 @@ const handler = async ({
|
|
|
80
78
|
verbose = false,
|
|
81
79
|
prisma = true,
|
|
82
80
|
prerender = true,
|
|
83
|
-
ud = false
|
|
81
|
+
ud = false,
|
|
82
|
+
apiRootPath
|
|
84
83
|
}) => {
|
|
85
84
|
recordTelemetryAttributes({
|
|
86
85
|
command: "build",
|
|
87
86
|
workspace: JSON.stringify(workspace),
|
|
88
87
|
verbose,
|
|
89
88
|
prisma,
|
|
90
|
-
prerender
|
|
89
|
+
prerender,
|
|
90
|
+
apiRootPath
|
|
91
91
|
});
|
|
92
92
|
const cedarPaths = getPaths();
|
|
93
93
|
const cedarConfig = getConfig();
|
|
@@ -97,12 +97,9 @@ const handler = async ({
|
|
|
97
97
|
const prismaSchemaExists = fs.existsSync(cedarPaths.api.prismaConfig);
|
|
98
98
|
const prerenderRoutes = prerender && workspace.includes("web") ? detectPrerenderRoutes() : [];
|
|
99
99
|
const shouldGeneratePrismaClient = prisma && prismaSchemaExists && (workspace.includes("api") || prerenderRoutes.length > 0);
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
fs.readFileSync(packageJsonPath, "utf8")
|
|
100
|
+
const nonApiWebWorkspaces = workspace.filter(
|
|
101
|
+
(w) => w !== "api" && w !== "web"
|
|
103
102
|
);
|
|
104
|
-
const packageJsonWorkspaces = packageJson.workspaces;
|
|
105
|
-
const nonApiWebWorkspaces = Array.isArray(packageJsonWorkspaces) && packageJsonWorkspaces.length > 2 ? workspace.filter((w) => w !== "api" && w !== "web") : [];
|
|
106
103
|
const gqlFeaturesTaskTitle = `Generating types needed for ${[
|
|
107
104
|
useFragments && "GraphQL Fragments",
|
|
108
105
|
useTrustedDocuments && "Trusted Documents"
|
|
@@ -230,7 +227,8 @@ Run ` + c.info(formatCedarCommand(["build"])) + " (without specifying a workspac
|
|
|
230
227
|
{
|
|
231
228
|
stdio: verbose ? "inherit" : "pipe",
|
|
232
229
|
shell: true,
|
|
233
|
-
// `cwd` is needed for yarn to find the
|
|
230
|
+
// `cwd` is needed for the package manager (e.g. yarn) to find the
|
|
231
|
+
// cedar-vite-build binary
|
|
234
232
|
// It won't change process.cwd for anything else here, in this
|
|
235
233
|
// process
|
|
236
234
|
cwd: cedarPaths.web.base
|
|
@@ -255,7 +253,7 @@ Run ` + c.info(formatCedarCommand(["build"])) + " (without specifying a workspac
|
|
|
255
253
|
const originalCwd = process.cwd();
|
|
256
254
|
process.chdir(cedarPaths.web.base);
|
|
257
255
|
try {
|
|
258
|
-
await buildCedarApp({ verbose, workspace });
|
|
256
|
+
await buildCedarApp({ verbose, workspace, ud: true });
|
|
259
257
|
} finally {
|
|
260
258
|
process.chdir(originalCwd);
|
|
261
259
|
}
|
|
@@ -268,40 +266,43 @@ Run ` + c.info(formatCedarCommand(["build"])) + " (without specifying a workspac
|
|
|
268
266
|
);
|
|
269
267
|
}
|
|
270
268
|
}
|
|
271
|
-
},
|
|
272
|
-
ud && workspace.includes("api") && {
|
|
273
|
-
title: "Bundling API server entry (Universal Deploy)...",
|
|
274
|
-
task: async () => {
|
|
275
|
-
await buildUDApiServer({ verbose });
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
].filter((t) => Boolean(t));
|
|
279
|
-
const triggerPrerender = async () => {
|
|
280
|
-
console.log("Starting prerendering...");
|
|
281
|
-
if (prerenderRoutes.length === 0) {
|
|
282
|
-
console.log(
|
|
283
|
-
`You have not marked any routes to "prerender" in your ${terminalLink(
|
|
284
|
-
"Routes",
|
|
285
|
-
"file://" + cedarPaths.web.routes
|
|
286
|
-
)}.`
|
|
287
|
-
);
|
|
288
|
-
return;
|
|
289
269
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
270
|
+
];
|
|
271
|
+
if (apiRootPath !== void 0) {
|
|
272
|
+
process.env.CEDAR_API_ROOT_PATH = apiRootPath;
|
|
273
|
+
}
|
|
274
|
+
try {
|
|
275
|
+
await timedTelemetry(process.argv, { type: "build" }, async () => {
|
|
276
|
+
const listrTasks = tasks.filter((t) => Boolean(t));
|
|
277
|
+
const jobs = new Listr(listrTasks, {
|
|
278
|
+
renderer: verbose ? "verbose" : void 0
|
|
279
|
+
});
|
|
280
|
+
await jobs.run();
|
|
281
|
+
if (workspace.includes("web") && prerender && prismaSchemaExists) {
|
|
282
|
+
await triggerPrerender(prerenderRoutes);
|
|
283
|
+
}
|
|
293
284
|
});
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
});
|
|
298
|
-
await timedTelemetry(process.argv, { type: "build" }, async () => {
|
|
299
|
-
await jobs.run();
|
|
300
|
-
if (workspace.includes("web") && prerender && prismaSchemaExists) {
|
|
301
|
-
await triggerPrerender();
|
|
302
|
-
}
|
|
303
|
-
});
|
|
285
|
+
} finally {
|
|
286
|
+
delete process.env.CEDAR_API_ROOT_PATH;
|
|
287
|
+
}
|
|
304
288
|
};
|
|
289
|
+
async function triggerPrerender(prerenderRoutes) {
|
|
290
|
+
const cedarPaths = getPaths();
|
|
291
|
+
console.log("Starting prerendering...");
|
|
292
|
+
if (prerenderRoutes.length === 0) {
|
|
293
|
+
console.log(
|
|
294
|
+
`You have not marked any routes to "prerender" in your ${terminalLink(
|
|
295
|
+
"Routes",
|
|
296
|
+
"file://" + cedarPaths.web.routes
|
|
297
|
+
)}.`
|
|
298
|
+
);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
await runBin("cedar", ["prerender"], {
|
|
302
|
+
stdio: "inherit",
|
|
303
|
+
cwd: cedarPaths.web.base
|
|
304
|
+
});
|
|
305
|
+
}
|
|
305
306
|
export {
|
|
306
307
|
handler
|
|
307
308
|
};
|
|
@@ -10,7 +10,7 @@ async function buildPackagesTask(task, nonApiWebWorkspaces) {
|
|
|
10
10
|
const workspacePaths = nonApiWebWorkspaces.some((w) => w === "packages/*") ? await Array.fromAsync(fs.promises.glob(globPattern)) : nonApiWebWorkspaces.map((w) => {
|
|
11
11
|
const workspacePath = path.join(
|
|
12
12
|
cedarPaths.packages,
|
|
13
|
-
w.split("/").at(-1)
|
|
13
|
+
w.split("/").at(-1) ?? ""
|
|
14
14
|
);
|
|
15
15
|
if (!fs.existsSync(workspacePath)) {
|
|
16
16
|
return "";
|
|
@@ -30,15 +30,15 @@ async function buildPackagesTask(task, nonApiWebWorkspaces) {
|
|
|
30
30
|
try {
|
|
31
31
|
await runScript("build", [], { cwd: workspacePath });
|
|
32
32
|
} catch (e) {
|
|
33
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
34
|
+
const stderr = e instanceof Error && "stderr" in e && typeof e.stderr === "string" ? e.stderr : void 0;
|
|
33
35
|
errorTelemetry(
|
|
34
36
|
process.argv,
|
|
35
|
-
`Error building package "${name}": ${
|
|
37
|
+
`Error building package "${name}": ${message}`
|
|
36
38
|
);
|
|
37
|
-
throw new Error(
|
|
38
|
-
`Building "${name}" failed
|
|
39
|
+
throw new Error(`Building "${name}" failed
|
|
39
40
|
|
|
40
|
-
${
|
|
41
|
-
);
|
|
41
|
+
${stderr || message}`);
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
};
|
package/dist/commands/build.js
CHANGED
|
@@ -28,7 +28,10 @@ const builder = (yargs) => {
|
|
|
28
28
|
}).option("ud", {
|
|
29
29
|
type: "boolean",
|
|
30
30
|
default: false,
|
|
31
|
-
description: "Build the Universal Deploy server entry (api/dist/ud/
|
|
31
|
+
description: "Build the Universal Deploy server entry (api/dist/ud/)."
|
|
32
|
+
}).option("apiRootPath", {
|
|
33
|
+
type: "string",
|
|
34
|
+
description: 'Root path where API functions are served. Overrides the apiRootPath option on cedarUniversalDeployPlugin() in your vite config. Defaults to "/".'
|
|
32
35
|
}).middleware(() => {
|
|
33
36
|
const check = checkNodeVersion();
|
|
34
37
|
if (check.ok) {
|
|
@@ -43,6 +46,9 @@ const builder = (yargs) => {
|
|
|
43
46
|
if (!Array.isArray(workspacesArg)) {
|
|
44
47
|
return "Workspace must be an array";
|
|
45
48
|
}
|
|
49
|
+
if (argv.apiRootPath && !argv.ud) {
|
|
50
|
+
return c.error("Error:") + " --apiRootPath requires --ud.\n Use --ud to build the Universal Deploy server entry.";
|
|
51
|
+
}
|
|
46
52
|
const filtered = workspacesArg.filter(
|
|
47
53
|
(item) => item !== "api" && item !== "web" && item !== "packages/*"
|
|
48
54
|
);
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import { NodeSSH } from "node-ssh";
|
|
2
|
+
class ExecError extends Error {
|
|
3
|
+
exitCode;
|
|
4
|
+
constructor(message, exitCode) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = "ExecError";
|
|
7
|
+
this.exitCode = exitCode;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
2
10
|
class SshExecutor {
|
|
11
|
+
ssh;
|
|
12
|
+
verbose;
|
|
3
13
|
constructor(verbose) {
|
|
4
14
|
this.ssh = new NodeSSH();
|
|
5
15
|
this.verbose = verbose;
|
|
@@ -20,12 +30,11 @@ class SshExecutor {
|
|
|
20
30
|
cwd: path
|
|
21
31
|
});
|
|
22
32
|
if (result.code !== 0) {
|
|
23
|
-
|
|
33
|
+
throw new ExecError(
|
|
24
34
|
`Error while running command \`${sshCommand}\` in ${path}
|
|
25
|
-
` + result.stderr
|
|
35
|
+
` + result.stderr,
|
|
36
|
+
result.code
|
|
26
37
|
);
|
|
27
|
-
error.exitCode = result.code;
|
|
28
|
-
throw error;
|
|
29
38
|
}
|
|
30
39
|
return result;
|
|
31
40
|
}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import boxen from "boxen";
|
|
4
|
+
import execa from "execa";
|
|
4
5
|
import { Listr } from "listr2";
|
|
5
6
|
import * as toml from "smol-toml";
|
|
6
7
|
import { env as envInterpolation } from "string-env-interpolation";
|
|
7
8
|
import { titleCase } from "title-case";
|
|
8
|
-
import { colors as c
|
|
9
|
+
import { colors as c } from "@cedarjs/cli-helpers";
|
|
10
|
+
import { formatCedarCommand } from "@cedarjs/cli-helpers/packageManager/display";
|
|
11
|
+
import { getPackageManager } from "@cedarjs/project-config/packageManager";
|
|
9
12
|
import { getPaths } from "../../../lib/index.js";
|
|
10
|
-
import { SshExecutor } from "./SshExecutor.js";
|
|
11
13
|
const CONFIG_FILENAME = "deploy.toml";
|
|
12
14
|
const SYMLINK_FLAGS = "-nsf";
|
|
13
15
|
const CURRENT_RELEASE_SYMLINK_NAME = "current";
|
|
@@ -15,7 +17,7 @@ const LIFECYCLE_HOOKS = ["before", "after"];
|
|
|
15
17
|
const DEFAULT_SERVER_CONFIG = {
|
|
16
18
|
port: 22,
|
|
17
19
|
branch: "main",
|
|
18
|
-
packageManagerCommand:
|
|
20
|
+
packageManagerCommand: getPackageManager(),
|
|
19
21
|
monitorCommand: "pm2",
|
|
20
22
|
sides: ["api", "web"],
|
|
21
23
|
keepReleases: 5,
|
|
@@ -30,7 +32,7 @@ const throwMissingConfig = (name) => {
|
|
|
30
32
|
const verifyConfig = (config, yargs) => {
|
|
31
33
|
if (!yargs.environment) {
|
|
32
34
|
throw new Error(
|
|
33
|
-
|
|
35
|
+
`Must specify an environment to deploy to, ex: \`${formatCedarCommand(["deploy", "baremetal", "production"])}\``
|
|
34
36
|
);
|
|
35
37
|
}
|
|
36
38
|
if (!config[yargs.environment]) {
|
|
@@ -48,20 +50,20 @@ const verifyServerConfig = (config) => {
|
|
|
48
50
|
if (!config.repo) {
|
|
49
51
|
throwMissingConfig("repo");
|
|
50
52
|
}
|
|
51
|
-
if (!/^\d+$/.test(config.freeSpaceRequired)) {
|
|
53
|
+
if (!/^\d+$/.test(String(config.freeSpaceRequired))) {
|
|
52
54
|
throw new Error('"freeSpaceRequired" must be an integer >= 0');
|
|
53
55
|
}
|
|
54
56
|
return true;
|
|
55
57
|
};
|
|
56
|
-
const symlinkCurrentCommand = async (dir, ssh,
|
|
57
|
-
return await ssh.exec(
|
|
58
|
+
const symlinkCurrentCommand = async (dir, ssh, deployPath) => {
|
|
59
|
+
return await ssh.exec(deployPath, "ln", [
|
|
58
60
|
SYMLINK_FLAGS,
|
|
59
61
|
dir,
|
|
60
62
|
CURRENT_RELEASE_SYMLINK_NAME
|
|
61
63
|
]);
|
|
62
64
|
};
|
|
63
|
-
const restartProcessCommand = async (processName, ssh, serverConfig,
|
|
64
|
-
return await ssh.exec(
|
|
65
|
+
const restartProcessCommand = async (processName, ssh, serverConfig, deployPath) => {
|
|
66
|
+
return await ssh.exec(deployPath, serverConfig.monitorCommand, [
|
|
65
67
|
"restart",
|
|
66
68
|
processName
|
|
67
69
|
]);
|
|
@@ -104,7 +106,7 @@ const maintenanceTasks = (status, ssh, serverConfig) => {
|
|
|
104
106
|
}
|
|
105
107
|
} else if (status === "down") {
|
|
106
108
|
tasks.push({
|
|
107
|
-
title: `Starting ${serverConfig.processNames
|
|
109
|
+
title: `Starting ${serverConfig.processNames?.join(", ")} processes...`,
|
|
108
110
|
task: async () => {
|
|
109
111
|
await ssh.exec(serverConfig.path, serverConfig.monitorCommand, [
|
|
110
112
|
"start",
|
|
@@ -131,7 +133,7 @@ const maintenanceTasks = (status, ssh, serverConfig) => {
|
|
|
131
133
|
};
|
|
132
134
|
const rollbackTasks = (count, ssh, serverConfig) => {
|
|
133
135
|
let rollbackCount = 1;
|
|
134
|
-
if (parseInt(count) === count) {
|
|
136
|
+
if (parseInt(String(count)) === count) {
|
|
135
137
|
rollbackCount = count;
|
|
136
138
|
}
|
|
137
139
|
const tasks = [
|
|
@@ -140,7 +142,7 @@ const rollbackTasks = (count, ssh, serverConfig) => {
|
|
|
140
142
|
task: async () => {
|
|
141
143
|
const currentLink = (await ssh.exec(serverConfig.path, "readlink", ["-f", "current"])).stdout.split("/").pop();
|
|
142
144
|
const dirs = (await ssh.exec(serverConfig.path, "ls", ["-t"])).stdout.split("\n").filter((dirs2) => !dirs2.match(/current/));
|
|
143
|
-
const deployedIndex = dirs.indexOf(currentLink);
|
|
145
|
+
const deployedIndex = dirs.indexOf(currentLink ?? "");
|
|
144
146
|
const rollbackIndex = deployedIndex + rollbackCount;
|
|
145
147
|
if (dirs[rollbackIndex]) {
|
|
146
148
|
console.info("Setting symlink");
|
|
@@ -151,7 +153,7 @@ const rollbackTasks = (count, ssh, serverConfig) => {
|
|
|
151
153
|
);
|
|
152
154
|
} else {
|
|
153
155
|
throw new Error(
|
|
154
|
-
`Cannot rollback ${rollbackCount} release(s): ${dirs.length - dirs.indexOf(currentLink) - 1} previous release(s) available`
|
|
156
|
+
`Cannot rollback ${rollbackCount} release(s): ${dirs.length - dirs.indexOf(currentLink ?? "") - 1} previous release(s) available`
|
|
155
157
|
);
|
|
156
158
|
}
|
|
157
159
|
}
|
|
@@ -189,19 +191,30 @@ const lifecycleTask = (lifecycle, task, skip, { serverLifecycle, ssh, cmdPath })
|
|
|
189
191
|
return tasks;
|
|
190
192
|
}
|
|
191
193
|
};
|
|
192
|
-
const commandWithLifecycleEvents = ({
|
|
194
|
+
const commandWithLifecycleEvents = ({
|
|
195
|
+
name,
|
|
196
|
+
config,
|
|
197
|
+
skip,
|
|
198
|
+
command
|
|
199
|
+
}) => {
|
|
193
200
|
const tasks = [];
|
|
194
201
|
tasks.push(lifecycleTask("before", name, skip, config));
|
|
195
202
|
tasks.push({ ...command, skip: () => skip });
|
|
196
203
|
tasks.push(lifecycleTask("after", name, skip, config));
|
|
197
|
-
return tasks.flat().filter((t) => t);
|
|
204
|
+
return tasks.flat().filter((t) => Boolean(t));
|
|
198
205
|
};
|
|
199
206
|
const deployTasks = (yargs, ssh, serverConfig, serverLifecycle) => {
|
|
200
207
|
const cmdPath = pathJoin(serverConfig.path, yargs.releaseDir);
|
|
201
|
-
const config = {
|
|
208
|
+
const config = {
|
|
209
|
+
yargs,
|
|
210
|
+
ssh,
|
|
211
|
+
serverConfig,
|
|
212
|
+
serverLifecycle,
|
|
213
|
+
cmdPath
|
|
214
|
+
};
|
|
202
215
|
const tasks = [];
|
|
203
216
|
tasks.push(
|
|
204
|
-
commandWithLifecycleEvents({
|
|
217
|
+
...commandWithLifecycleEvents({
|
|
205
218
|
name: "df",
|
|
206
219
|
config: { ...config, cmdPath: serverConfig.path },
|
|
207
220
|
skip: !yargs.df || serverConfig.freeSpaceRequired === 0 || serverConfig.freeSpaceRequired === "0",
|
|
@@ -228,7 +241,7 @@ const deployTasks = (yargs, ssh, serverConfig, serverLifecycle) => {
|
|
|
228
241
|
}
|
|
229
242
|
task.output = `Available disk space: ${dfMb}MB`;
|
|
230
243
|
const freeSpaceRequired = parseInt(
|
|
231
|
-
serverConfig.freeSpaceRequired ?? 2048,
|
|
244
|
+
String(serverConfig.freeSpaceRequired ?? 2048),
|
|
232
245
|
10
|
|
233
246
|
);
|
|
234
247
|
if (dfMb < freeSpaceRequired) {
|
|
@@ -241,7 +254,7 @@ const deployTasks = (yargs, ssh, serverConfig, serverLifecycle) => {
|
|
|
241
254
|
})
|
|
242
255
|
);
|
|
243
256
|
tasks.push(
|
|
244
|
-
commandWithLifecycleEvents({
|
|
257
|
+
...commandWithLifecycleEvents({
|
|
245
258
|
name: "update",
|
|
246
259
|
config: { ...config, cmdPath: serverConfig.path },
|
|
247
260
|
skip: !yargs.update,
|
|
@@ -260,7 +273,7 @@ const deployTasks = (yargs, ssh, serverConfig, serverLifecycle) => {
|
|
|
260
273
|
})
|
|
261
274
|
);
|
|
262
275
|
tasks.push(
|
|
263
|
-
commandWithLifecycleEvents({
|
|
276
|
+
...commandWithLifecycleEvents({
|
|
264
277
|
name: "symlinkEnv",
|
|
265
278
|
config,
|
|
266
279
|
skip: !yargs.update,
|
|
@@ -273,7 +286,7 @@ const deployTasks = (yargs, ssh, serverConfig, serverLifecycle) => {
|
|
|
273
286
|
})
|
|
274
287
|
);
|
|
275
288
|
tasks.push(
|
|
276
|
-
commandWithLifecycleEvents({
|
|
289
|
+
...commandWithLifecycleEvents({
|
|
277
290
|
name: "install",
|
|
278
291
|
config,
|
|
279
292
|
skip: !yargs.install,
|
|
@@ -288,7 +301,7 @@ const deployTasks = (yargs, ssh, serverConfig, serverLifecycle) => {
|
|
|
288
301
|
})
|
|
289
302
|
);
|
|
290
303
|
tasks.push(
|
|
291
|
-
commandWithLifecycleEvents({
|
|
304
|
+
...commandWithLifecycleEvents({
|
|
292
305
|
name: "migrate",
|
|
293
306
|
config,
|
|
294
307
|
skip: !yargs.migrate || serverConfig?.migrate === false,
|
|
@@ -296,17 +309,20 @@ const deployTasks = (yargs, ssh, serverConfig, serverLifecycle) => {
|
|
|
296
309
|
title: `DB Migrations...`,
|
|
297
310
|
task: async () => {
|
|
298
311
|
await ssh.exec(cmdPath, serverConfig.packageManagerCommand, [
|
|
312
|
+
"exec",
|
|
299
313
|
"cedar",
|
|
300
314
|
"prisma",
|
|
301
315
|
"migrate",
|
|
302
316
|
"deploy"
|
|
303
317
|
]);
|
|
304
318
|
await ssh.exec(cmdPath, serverConfig.packageManagerCommand, [
|
|
319
|
+
"exec",
|
|
305
320
|
"cedar",
|
|
306
321
|
"prisma",
|
|
307
322
|
"generate"
|
|
308
323
|
]);
|
|
309
324
|
await ssh.exec(cmdPath, serverConfig.packageManagerCommand, [
|
|
325
|
+
"exec",
|
|
310
326
|
"cedar",
|
|
311
327
|
"dataMigrate",
|
|
312
328
|
"up"
|
|
@@ -317,7 +333,7 @@ const deployTasks = (yargs, ssh, serverConfig, serverLifecycle) => {
|
|
|
317
333
|
);
|
|
318
334
|
for (const side of serverConfig.sides) {
|
|
319
335
|
tasks.push(
|
|
320
|
-
commandWithLifecycleEvents({
|
|
336
|
+
...commandWithLifecycleEvents({
|
|
321
337
|
name: "build",
|
|
322
338
|
config,
|
|
323
339
|
skip: !yargs.build,
|
|
@@ -325,6 +341,7 @@ const deployTasks = (yargs, ssh, serverConfig, serverLifecycle) => {
|
|
|
325
341
|
title: `Building ${side}...`,
|
|
326
342
|
task: async () => {
|
|
327
343
|
await ssh.exec(cmdPath, serverConfig.packageManagerCommand, [
|
|
344
|
+
"exec",
|
|
328
345
|
"cedar",
|
|
329
346
|
"build",
|
|
330
347
|
side
|
|
@@ -335,7 +352,7 @@ const deployTasks = (yargs, ssh, serverConfig, serverLifecycle) => {
|
|
|
335
352
|
);
|
|
336
353
|
}
|
|
337
354
|
tasks.push(
|
|
338
|
-
commandWithLifecycleEvents({
|
|
355
|
+
...commandWithLifecycleEvents({
|
|
339
356
|
name: "symlinkCurrent",
|
|
340
357
|
config,
|
|
341
358
|
skip: !yargs.update,
|
|
@@ -352,7 +369,7 @@ const deployTasks = (yargs, ssh, serverConfig, serverLifecycle) => {
|
|
|
352
369
|
for (const processName of serverConfig.processNames) {
|
|
353
370
|
if (yargs.firstRun) {
|
|
354
371
|
tasks.push(
|
|
355
|
-
commandWithLifecycleEvents({
|
|
372
|
+
...commandWithLifecycleEvents({
|
|
356
373
|
name: "restart",
|
|
357
374
|
config,
|
|
358
375
|
skip: !yargs.restart,
|
|
@@ -380,7 +397,7 @@ const deployTasks = (yargs, ssh, serverConfig, serverLifecycle) => {
|
|
|
380
397
|
});
|
|
381
398
|
} else {
|
|
382
399
|
tasks.push(
|
|
383
|
-
commandWithLifecycleEvents({
|
|
400
|
+
...commandWithLifecycleEvents({
|
|
384
401
|
name: "restart",
|
|
385
402
|
config,
|
|
386
403
|
skip: !yargs.restart,
|
|
@@ -401,7 +418,7 @@ const deployTasks = (yargs, ssh, serverConfig, serverLifecycle) => {
|
|
|
401
418
|
}
|
|
402
419
|
}
|
|
403
420
|
tasks.push(
|
|
404
|
-
commandWithLifecycleEvents({
|
|
421
|
+
...commandWithLifecycleEvents({
|
|
405
422
|
name: "cleanup",
|
|
406
423
|
config: { ...config, cmdPath: serverConfig.path },
|
|
407
424
|
skip: !yargs.cleanup,
|
|
@@ -417,14 +434,15 @@ const deployTasks = (yargs, ssh, serverConfig, serverLifecycle) => {
|
|
|
417
434
|
}
|
|
418
435
|
})
|
|
419
436
|
);
|
|
420
|
-
return tasks
|
|
437
|
+
return tasks;
|
|
421
438
|
};
|
|
422
439
|
const mergeLifecycleEvents = (lifecycle, other) => {
|
|
423
|
-
|
|
440
|
+
const lifecycleCopy = JSON.parse(JSON.stringify(lifecycle));
|
|
424
441
|
for (const hook of LIFECYCLE_HOOKS) {
|
|
425
|
-
|
|
442
|
+
const otherHook = other[hook] ?? {};
|
|
443
|
+
for (const key in otherHook) {
|
|
426
444
|
lifecycleCopy[hook][key] = (lifecycleCopy[hook][key] || []).concat(
|
|
427
|
-
|
|
445
|
+
otherHook[key]
|
|
428
446
|
);
|
|
429
447
|
}
|
|
430
448
|
}
|
|
@@ -433,26 +451,26 @@ const mergeLifecycleEvents = (lifecycle, other) => {
|
|
|
433
451
|
const parseConfig = (yargs, rawConfigToml) => {
|
|
434
452
|
const configToml = envInterpolation(rawConfigToml);
|
|
435
453
|
const config = toml.parse(configToml);
|
|
436
|
-
|
|
437
|
-
const emptyLifecycle = {};
|
|
454
|
+
const emptyLifecycle = { before: {}, after: {} };
|
|
438
455
|
verifyConfig(config, yargs);
|
|
439
|
-
for (const hook of LIFECYCLE_HOOKS) {
|
|
440
|
-
emptyLifecycle[hook] = {};
|
|
441
|
-
}
|
|
442
456
|
let envLifecycle = mergeLifecycleEvents(emptyLifecycle, config);
|
|
443
|
-
envConfig = config[yargs.environment];
|
|
457
|
+
const envConfig = config[yargs.environment];
|
|
444
458
|
envLifecycle = mergeLifecycleEvents(envLifecycle, envConfig);
|
|
445
459
|
return { envConfig, envLifecycle };
|
|
446
460
|
};
|
|
447
461
|
const commands = (yargs, ssh) => {
|
|
448
462
|
const deployConfig = fs.readFileSync(pathJoin(getPaths().base, CONFIG_FILENAME)).toString();
|
|
449
|
-
|
|
450
|
-
|
|
463
|
+
const { envConfig, envLifecycle } = parseConfig(yargs, deployConfig);
|
|
464
|
+
const servers = [];
|
|
451
465
|
let tasks = [];
|
|
452
|
-
|
|
466
|
+
const serverList = envConfig.servers ?? [];
|
|
467
|
+
for (const config of serverList) {
|
|
453
468
|
const serverConfig = serverConfigWithDefaults(config, yargs);
|
|
454
469
|
verifyServerConfig(serverConfig);
|
|
455
|
-
const serverLifecycle = mergeLifecycleEvents(
|
|
470
|
+
const serverLifecycle = mergeLifecycleEvents(
|
|
471
|
+
envLifecycle,
|
|
472
|
+
serverConfig
|
|
473
|
+
);
|
|
456
474
|
tasks.push({
|
|
457
475
|
title: "Connecting...",
|
|
458
476
|
task: () => ssh.connect({
|
|
@@ -461,9 +479,10 @@ const commands = (yargs, ssh) => {
|
|
|
461
479
|
username: serverConfig.username,
|
|
462
480
|
password: serverConfig.password,
|
|
463
481
|
privateKey: serverConfig.privateKey,
|
|
482
|
+
// @ts-expect-error - node-ssh Config doesn't expose privateKeyPath but it is supported at runtime
|
|
464
483
|
privateKeyPath: serverConfig.privateKeyPath,
|
|
465
484
|
passphrase: serverConfig.passphrase,
|
|
466
|
-
agent: serverConfig.agentForward
|
|
485
|
+
agent: serverConfig.agentForward ? process.env.SSH_AUTH_SOCK : void 0,
|
|
467
486
|
agentForward: serverConfig.agentForward
|
|
468
487
|
})
|
|
469
488
|
});
|
|
@@ -482,56 +501,88 @@ const commands = (yargs, ssh) => {
|
|
|
482
501
|
title: "Disconnecting...",
|
|
483
502
|
task: () => ssh.dispose()
|
|
484
503
|
});
|
|
504
|
+
const tasksCopy = [...tasks];
|
|
485
505
|
servers.push({
|
|
486
506
|
title: serverConfig.host,
|
|
487
507
|
task: () => {
|
|
488
|
-
return new Listr(
|
|
508
|
+
return new Listr(tasksCopy);
|
|
489
509
|
}
|
|
490
510
|
});
|
|
511
|
+
tasks = [];
|
|
491
512
|
}
|
|
492
513
|
return servers;
|
|
493
514
|
};
|
|
515
|
+
const warnIfUnpushedCommits = async () => {
|
|
516
|
+
try {
|
|
517
|
+
const { stdout } = await execa("git", ["log", "@{u}..", "--oneline"], {
|
|
518
|
+
cwd: getPaths().base
|
|
519
|
+
});
|
|
520
|
+
const unpushedCommits = stdout.trim();
|
|
521
|
+
if (!unpushedCommits) {
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
console.warn(
|
|
525
|
+
c.warning("\nWarning: You have local commits that have not been pushed:")
|
|
526
|
+
);
|
|
527
|
+
console.warn(
|
|
528
|
+
unpushedCommits.split("\n").map((line) => ` ${line}`).join("\n")
|
|
529
|
+
);
|
|
530
|
+
console.warn(
|
|
531
|
+
c.warning(
|
|
532
|
+
"The server will pull from the remote, so these commits will not be deployed.\n"
|
|
533
|
+
)
|
|
534
|
+
);
|
|
535
|
+
const { default: prompts } = await import("prompts");
|
|
536
|
+
const { confirmed } = await prompts({
|
|
537
|
+
type: "confirm",
|
|
538
|
+
name: "confirmed",
|
|
539
|
+
message: "Deploy anyway?",
|
|
540
|
+
initial: false
|
|
541
|
+
});
|
|
542
|
+
if (!confirmed) {
|
|
543
|
+
console.log("Aborting deploy. Push your commits and try again.");
|
|
544
|
+
process.exit(1);
|
|
545
|
+
}
|
|
546
|
+
} catch (e) {
|
|
547
|
+
console.error(
|
|
548
|
+
c.error("\nCould not check for unpushed commits before deploying.")
|
|
549
|
+
);
|
|
550
|
+
throw e;
|
|
551
|
+
}
|
|
552
|
+
};
|
|
494
553
|
const handler = async (yargs) => {
|
|
495
|
-
|
|
496
|
-
command: "deploy baremetal",
|
|
497
|
-
firstRun: yargs.firstRun,
|
|
498
|
-
df: yargs.df,
|
|
499
|
-
update: yargs.update,
|
|
500
|
-
install: yargs.install,
|
|
501
|
-
migrate: yargs.migrate,
|
|
502
|
-
build: yargs.build,
|
|
503
|
-
restart: yargs.restart,
|
|
504
|
-
cleanup: yargs.cleanup,
|
|
505
|
-
maintenance: yargs.maintenance,
|
|
506
|
-
rollback: yargs.rollback,
|
|
507
|
-
verbose: yargs.verbose
|
|
508
|
-
});
|
|
554
|
+
const { SshExecutor } = await import("./SshExecutor.js");
|
|
509
555
|
const tomlPath = path.join(getPaths().base, "deploy.toml");
|
|
510
556
|
const ecosystemPath = path.join(getPaths().base, "ecosystem.config.js");
|
|
511
557
|
if (!fs.existsSync(tomlPath) || !fs.existsSync(ecosystemPath)) {
|
|
512
558
|
console.error(
|
|
513
|
-
c.error("\nError: Baremetal deploy has not been properly setup.\n") +
|
|
559
|
+
c.error("\nError: Baremetal deploy has not been properly setup.\n") + `Please run \`${formatCedarCommand(["setup", "deploy", "baremetal"])}\` before deploying`
|
|
514
560
|
);
|
|
515
561
|
process.exit(1);
|
|
516
562
|
}
|
|
517
|
-
|
|
563
|
+
if (yargs.gitCheck) {
|
|
564
|
+
await warnIfUnpushedCommits();
|
|
565
|
+
}
|
|
566
|
+
const ssh = new SshExecutor(yargs.verbose ?? false);
|
|
518
567
|
try {
|
|
519
|
-
const
|
|
568
|
+
const listrTasks = new Listr(commands(yargs, ssh), {
|
|
520
569
|
concurrent: true,
|
|
521
570
|
exitOnError: true,
|
|
522
|
-
renderer: yargs.verbose
|
|
571
|
+
renderer: yargs.verbose ? "verbose" : void 0
|
|
523
572
|
});
|
|
524
|
-
await
|
|
573
|
+
await listrTasks.run();
|
|
525
574
|
} catch (e) {
|
|
526
575
|
console.error(c.error("\nDeploy failed:"));
|
|
576
|
+
const errMessage = e instanceof Error && "stderr" in e ? e.stderr ?? e.message : e instanceof Error ? e.message : String(e);
|
|
577
|
+
const exitCode = e instanceof Error && "exitCode" in e ? e.exitCode ?? 1 : 1;
|
|
527
578
|
console.error(
|
|
528
|
-
boxen(
|
|
579
|
+
boxen(errMessage, {
|
|
529
580
|
padding: { top: 0, bottom: 0, right: 1, left: 1 },
|
|
530
581
|
margin: 0,
|
|
531
582
|
borderColor: "red"
|
|
532
583
|
})
|
|
533
584
|
);
|
|
534
|
-
process.exit(
|
|
585
|
+
process.exit(exitCode);
|
|
535
586
|
}
|
|
536
587
|
};
|
|
537
588
|
export {
|
|
@@ -547,5 +598,6 @@ export {
|
|
|
547
598
|
serverConfigWithDefaults,
|
|
548
599
|
throwMissingConfig,
|
|
549
600
|
verifyConfig,
|
|
550
|
-
verifyServerConfig
|
|
601
|
+
verifyServerConfig,
|
|
602
|
+
warnIfUnpushedCommits
|
|
551
603
|
};
|