listpage_cli 0.0.294 → 0.0.296
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/bin/{prompts.js → adapters/cli-interaction.js} +6 -15
- package/bin/adapters/dockerode-client.js +295 -0
- package/bin/app/parse-args.js +92 -1
- package/bin/cli.js +16 -7
- package/bin/commands/deploy-project-command.js +24 -0
- package/bin/commands/release-project-command.js +24 -0
- package/bin/domain/package-name.js +12 -0
- package/bin/ports/release-project-command.js +2 -0
- package/bin/services/build-artifact-validator.js +47 -0
- package/bin/services/command-runner.js +4 -3
- package/bin/services/config-value-utils.js +44 -0
- package/bin/services/deploy-project-service.js +390 -0
- package/bin/services/filesystem-capability-service.js +7 -11
- package/bin/services/init-service.js +0 -7
- package/bin/services/release-project-service.js +239 -0
- package/bin/shared/json-with-comments.js +9 -0
- package/bin/types/deploy-config.js +2 -0
- package/package.json +6 -4
- package/templates/backend-template/package.json.tmpl +1 -1
- package/templates/backend-template/tsconfig.build.json +12 -2
- package/templates/frontend-template/package.json.tmpl +2 -2
- package/templates/rush-template/listpage.config.json.tmpl +89 -0
- package/bin/copy.js +0 -40
- package/templates/package-app-template/.gitignore.tmpl +0 -28
- package/templates/package-app-template/README.md +0 -33
- package/templates/package-app-template/package.json +0 -27
- package/templates/package-app-template/src/build.ts +0 -6
- package/templates/package-app-template/src/config.ts.tmpl +0 -45
- package/templates/package-app-template/src/package.ts +0 -5
- package/templates/package-app-template/src/publish.ts +0 -6
- package/templates/package-app-template/tsconfig.json +0 -25
- /package/bin/{services/artifact-validator.js → ports/deploy-project-command.js} +0 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runReleaseProjectFlow = runReleaseProjectFlow;
|
|
4
|
+
const command_result_1 = require("../domain/command-result");
|
|
5
|
+
const config_loader_1 = require("./config-loader");
|
|
6
|
+
const command_runner_1 = require("./command-runner");
|
|
7
|
+
const build_artifact_validator_1 = require("./build-artifact-validator");
|
|
8
|
+
const config_value_utils_1 = require("./config-value-utils");
|
|
9
|
+
const RELEASE_STAGE = "release";
|
|
10
|
+
const CONFIG_ERROR_CODE_MAP = {
|
|
11
|
+
CONFIG_NOT_FOUND: "E_CONFIG_NOT_FOUND",
|
|
12
|
+
CONFIG_READ_FAILED: "E_CONFIG_READ_FAILED",
|
|
13
|
+
CONFIG_INVALID_JSON: "E_CONFIG_INVALID_JSON",
|
|
14
|
+
CONFIG_REQUIRED_FIELD_MISSING: "E_CONFIG_REQUIRED_FIELD_MISSING",
|
|
15
|
+
};
|
|
16
|
+
async function runReleaseProjectFlow(deps) {
|
|
17
|
+
const projectRoot = deps.fs.cwd();
|
|
18
|
+
const configPath = (0, config_loader_1.getDefaultConfigPath)(projectRoot, deps.fs.join);
|
|
19
|
+
let configResult;
|
|
20
|
+
try {
|
|
21
|
+
configResult = (0, config_loader_1.loadProjectConfig)({
|
|
22
|
+
readText: deps.fs.readText,
|
|
23
|
+
}, configPath);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (error instanceof config_loader_1.ConfigLoaderError) {
|
|
27
|
+
return (0, command_result_1.commandError)(error.message, CONFIG_ERROR_CODE_MAP[error.code], 1);
|
|
28
|
+
}
|
|
29
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
30
|
+
return (0, command_result_1.commandError)(message, command_result_1.COMMAND_ERROR_CODES.invalidPath, 1);
|
|
31
|
+
}
|
|
32
|
+
let executionInput;
|
|
33
|
+
try {
|
|
34
|
+
executionInput = parseReleaseInput(projectRoot, configResult.config, deps.fs.resolve, deps.cliOverrides);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
38
|
+
return (0, command_result_1.commandError)(`[${RELEASE_STAGE}] 发布配置无效: ${message}`, "E_CONFIG_REQUIRED_FIELD_MISSING", 1);
|
|
39
|
+
}
|
|
40
|
+
const validator = (0, build_artifact_validator_1.createBuildArtifactValidator)({
|
|
41
|
+
resolve: deps.fs.resolve,
|
|
42
|
+
exists: deps.fs.exists,
|
|
43
|
+
isDirectory: deps.fs.isDirectory,
|
|
44
|
+
readDir: deps.fs.readDir,
|
|
45
|
+
});
|
|
46
|
+
const validationResult = validator({
|
|
47
|
+
outputDir: executionInput.outputDir,
|
|
48
|
+
requiredRelativePaths: collectRequiredArtifacts(configResult.config),
|
|
49
|
+
});
|
|
50
|
+
if (!validationResult.ok) {
|
|
51
|
+
const message = validationResult.issues.map((issue) => issue.message).join("; ");
|
|
52
|
+
return (0, command_result_1.commandError)(message, command_result_1.COMMAND_ERROR_CODES.executionFailed, 1);
|
|
53
|
+
}
|
|
54
|
+
if (deps.executeRelease) {
|
|
55
|
+
try {
|
|
56
|
+
const result = await deps.executeRelease({
|
|
57
|
+
projectRoot,
|
|
58
|
+
configPath: configResult.configPath,
|
|
59
|
+
config: configResult.config,
|
|
60
|
+
outputDir: executionInput.outputDir,
|
|
61
|
+
remoteImage: executionInput.remoteImage,
|
|
62
|
+
docker: executionInput.docker,
|
|
63
|
+
});
|
|
64
|
+
return normalizeReleaseResult(result);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
return (0, command_result_1.commandError)(formatReleaseThrownError(error), command_result_1.COMMAND_ERROR_CODES.executionFailed, getNonZeroExitCode(error));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const commandRunner = deps.createRunner
|
|
71
|
+
? deps.createRunner()
|
|
72
|
+
: (0, command_runner_1.createCommandRunner)({ stage: RELEASE_STAGE });
|
|
73
|
+
return runDockerRelease(commandRunner, executionInput);
|
|
74
|
+
}
|
|
75
|
+
function parseReleaseInput(projectRoot, config, resolve, cliOverrides) {
|
|
76
|
+
const typedConfig = config;
|
|
77
|
+
const dockerRaw = (0, config_value_utils_1.asObject)(typedConfig.docker, "docker");
|
|
78
|
+
const registry = (0, config_value_utils_1.asObject)(dockerRaw.registry, "docker.registry");
|
|
79
|
+
const build = ((0, config_value_utils_1.asOptionalObject)(dockerRaw.build) ?? {});
|
|
80
|
+
const releaseProfiles = ((0, config_value_utils_1.asOptionalObject)(dockerRaw.releaseProfiles) ??
|
|
81
|
+
{});
|
|
82
|
+
const profile = cliOverrides?.profile?.trim() || "dev";
|
|
83
|
+
const profileConfig = (0, config_value_utils_1.asOptionalObject)(releaseProfiles[profile]);
|
|
84
|
+
const imageName = (0, config_value_utils_1.asRequiredString)(dockerRaw.imageName ?? dockerRaw.appName, "docker.imageName/appName");
|
|
85
|
+
const imageTag = resolveImageTag(cliOverrides?.tag, (0, config_value_utils_1.asOptionalString)(profileConfig?.tag), (0, config_value_utils_1.asOptionalString)(dockerRaw.imageTag));
|
|
86
|
+
const registryUrl = (0, config_value_utils_1.asRequiredString)(registry.url, "docker.registry.url");
|
|
87
|
+
const registryNamespace = (0, config_value_utils_1.asOptionalString)(registry.namespace);
|
|
88
|
+
const username = (0, config_value_utils_1.asRequiredString)(registry.username, "docker.registry.username");
|
|
89
|
+
const password = (0, config_value_utils_1.asOptionalString)(registry.password);
|
|
90
|
+
const profileBuild = ((0, config_value_utils_1.asOptionalObject)(profileConfig?.buildOverrides) ??
|
|
91
|
+
{});
|
|
92
|
+
const platform = cliOverrides?.platform ??
|
|
93
|
+
(0, config_value_utils_1.asOptionalString)(profileBuild.platform) ??
|
|
94
|
+
(0, config_value_utils_1.asOptionalString)(build.platform);
|
|
95
|
+
const outputDir = resolve(projectRoot, ".listpage", "output");
|
|
96
|
+
const repositoryPath = registryNamespace && registryNamespace !== ""
|
|
97
|
+
? `${registryNamespace}/${imageName}`
|
|
98
|
+
: imageName;
|
|
99
|
+
return {
|
|
100
|
+
outputDir,
|
|
101
|
+
remoteImage: `${registryUrl}/${repositoryPath}:${imageTag}`,
|
|
102
|
+
docker: {
|
|
103
|
+
imageName,
|
|
104
|
+
imageTag,
|
|
105
|
+
registryUrl,
|
|
106
|
+
registryNamespace,
|
|
107
|
+
username,
|
|
108
|
+
password,
|
|
109
|
+
platform,
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function resolveImageTag(cliTag, profileTag, fallbackTag) {
|
|
114
|
+
const normalizedCli = cliTag?.trim();
|
|
115
|
+
if (normalizedCli) {
|
|
116
|
+
return normalizedCli;
|
|
117
|
+
}
|
|
118
|
+
if (profileTag && profileTag.trim() !== "") {
|
|
119
|
+
return profileTag;
|
|
120
|
+
}
|
|
121
|
+
if (fallbackTag && fallbackTag.trim() !== "") {
|
|
122
|
+
return fallbackTag;
|
|
123
|
+
}
|
|
124
|
+
throw new Error("缺少字段: docker.releaseProfiles.<profile>.tag");
|
|
125
|
+
}
|
|
126
|
+
function collectRequiredArtifacts(config) {
|
|
127
|
+
const required = new Set(["Dockerfile"]);
|
|
128
|
+
const artifacts = (0, config_value_utils_1.asOptionalObject)(config.artifacts);
|
|
129
|
+
const frontend = artifacts?.frontend ?? config.frontend;
|
|
130
|
+
if (Array.isArray(frontend)) {
|
|
131
|
+
for (const item of frontend) {
|
|
132
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const record = item;
|
|
136
|
+
const packageSubDir = (0, config_value_utils_1.asOptionalString)(record.packageSubDir) ?? "public";
|
|
137
|
+
const artifactAlias = (0, config_value_utils_1.asOptionalString)(record.artifactAlias) ?? "dist";
|
|
138
|
+
required.add(`${packageSubDir}/${artifactAlias}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const backendRaw = artifacts?.backend ?? config.backend;
|
|
142
|
+
if (backendRaw && typeof backendRaw === "object" && !Array.isArray(backendRaw)) {
|
|
143
|
+
const backend = backendRaw;
|
|
144
|
+
const packageSubDir = (0, config_value_utils_1.asOptionalString)(backend.packageSubDir) ?? "server";
|
|
145
|
+
const artifactAlias = (0, config_value_utils_1.asOptionalString)(backend.artifactAlias) ?? "dist";
|
|
146
|
+
required.add(`${packageSubDir}/${artifactAlias}`);
|
|
147
|
+
}
|
|
148
|
+
return [...required];
|
|
149
|
+
}
|
|
150
|
+
async function runDockerRelease(runner, input) {
|
|
151
|
+
const { docker } = input;
|
|
152
|
+
const localImage = `${docker.imageName}:${docker.imageTag}`;
|
|
153
|
+
const loginArgs = docker.password
|
|
154
|
+
? [
|
|
155
|
+
"login",
|
|
156
|
+
`--username=${docker.username}`,
|
|
157
|
+
`--password=${docker.password}`,
|
|
158
|
+
docker.registryUrl,
|
|
159
|
+
]
|
|
160
|
+
: [
|
|
161
|
+
"login",
|
|
162
|
+
`--username=${docker.username}`,
|
|
163
|
+
"--password-stdin",
|
|
164
|
+
docker.registryUrl,
|
|
165
|
+
];
|
|
166
|
+
const buildArgs = [
|
|
167
|
+
"buildx",
|
|
168
|
+
"build",
|
|
169
|
+
...(docker.platform ? ["--platform", docker.platform] : []),
|
|
170
|
+
"-t",
|
|
171
|
+
localImage,
|
|
172
|
+
".",
|
|
173
|
+
];
|
|
174
|
+
const stageCommands = [
|
|
175
|
+
{ stage: "login", args: loginArgs, cwd: input.outputDir },
|
|
176
|
+
{ stage: "build", args: buildArgs, cwd: input.outputDir },
|
|
177
|
+
{
|
|
178
|
+
stage: "tag",
|
|
179
|
+
args: ["tag", localImage, input.remoteImage],
|
|
180
|
+
cwd: input.outputDir,
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
stage: "push",
|
|
184
|
+
args: ["push", input.remoteImage],
|
|
185
|
+
cwd: input.outputDir,
|
|
186
|
+
},
|
|
187
|
+
];
|
|
188
|
+
try {
|
|
189
|
+
for (const command of stageCommands) {
|
|
190
|
+
const result = await runner({
|
|
191
|
+
command: "docker",
|
|
192
|
+
args: command.args,
|
|
193
|
+
cwd: command.cwd,
|
|
194
|
+
});
|
|
195
|
+
if (result.exitCode !== 0) {
|
|
196
|
+
return (0, command_result_1.commandError)(`[${RELEASE_STAGE}][${command.stage}] Docker 命令执行失败: docker ${command.args.join(" ")} (exit=${result.exitCode})`, command_result_1.COMMAND_ERROR_CODES.executionFailed, result.exitCode);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
if (error instanceof command_runner_1.ExecutionError) {
|
|
202
|
+
return (0, command_result_1.commandError)(`[${RELEASE_STAGE}] ${error.message}`, command_result_1.COMMAND_ERROR_CODES.executionFailed, error.exitCode);
|
|
203
|
+
}
|
|
204
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
205
|
+
return (0, command_result_1.commandError)(`[${RELEASE_STAGE}] 发布命令执行异常: ${message}`, command_result_1.COMMAND_ERROR_CODES.executionFailed, 1);
|
|
206
|
+
}
|
|
207
|
+
return (0, command_result_1.commandOk)(`[${RELEASE_STAGE}] 发布完成: ${input.remoteImage}\n` +
|
|
208
|
+
`[${RELEASE_STAGE}] 运行示例: docker run -d -p 3000:3000 --name ${docker.imageName}-container ${input.remoteImage}`);
|
|
209
|
+
}
|
|
210
|
+
function normalizeReleaseResult(result) {
|
|
211
|
+
if (result.ok) {
|
|
212
|
+
if (result.exitCode === 0) {
|
|
213
|
+
return result;
|
|
214
|
+
}
|
|
215
|
+
return (0, command_result_1.commandError)(`[${RELEASE_STAGE}] 发布执行器返回成功但退出码非零 (exit=${result.exitCode})`, command_result_1.COMMAND_ERROR_CODES.executionFailed, result.exitCode);
|
|
216
|
+
}
|
|
217
|
+
if (result.exitCode !== 0) {
|
|
218
|
+
return result;
|
|
219
|
+
}
|
|
220
|
+
return (0, command_result_1.commandError)(result.message ??
|
|
221
|
+
`[${RELEASE_STAGE}] 发布执行器返回失败但退出码为 0`, result.errorCode ?? command_result_1.COMMAND_ERROR_CODES.executionFailed, 1);
|
|
222
|
+
}
|
|
223
|
+
function formatReleaseThrownError(error) {
|
|
224
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
225
|
+
return `[${RELEASE_STAGE}] 发布执行异常: ${message}`;
|
|
226
|
+
}
|
|
227
|
+
function getNonZeroExitCode(error) {
|
|
228
|
+
if (!error || typeof error !== "object") {
|
|
229
|
+
return 1;
|
|
230
|
+
}
|
|
231
|
+
const candidate = error;
|
|
232
|
+
if (typeof candidate.exitCode === "number" && candidate.exitCode !== 0) {
|
|
233
|
+
return candidate.exitCode;
|
|
234
|
+
}
|
|
235
|
+
if (typeof candidate.status === "number" && candidate.status !== 0) {
|
|
236
|
+
return candidate.status;
|
|
237
|
+
}
|
|
238
|
+
return 1;
|
|
239
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseJsonWithComments = parseJsonWithComments;
|
|
4
|
+
function parseJsonWithComments(str) {
|
|
5
|
+
const noBlock = str.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
6
|
+
const noLine = noBlock.replace(/(^|\s)\/\/.*$/gm, "");
|
|
7
|
+
const noTrailingComma = noLine.replace(/,\s*([}\]])/g, "$1");
|
|
8
|
+
return JSON.parse(noTrailingComma);
|
|
9
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "listpage_cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.296",
|
|
4
4
|
"private": false,
|
|
5
5
|
"bin": {
|
|
6
6
|
"listpage_cli": "bin/cli.js"
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"build:tests": "tsc -p tsconfig.tests.json",
|
|
11
11
|
"test:unit": "npm run build:tests && node --test .tmp-tests/tests/unit/**/*.test.js",
|
|
12
12
|
"test:integration": "npm run build && npm run build:tests && node --test .tmp-tests/tests/integration/**/*.test.js",
|
|
13
|
-
"test:
|
|
13
|
+
"test:integration:deploy-live": "npm run build && npm run build:tests && node --test .tmp-tests/tests/integration/deploy-project.live.integration.test.js",
|
|
14
14
|
"prepublishOnly": "npm run build",
|
|
15
15
|
"start": "node bin/cli.js init",
|
|
16
16
|
"test": "node bin/cli.js --help"
|
|
@@ -20,10 +20,12 @@
|
|
|
20
20
|
"templates"
|
|
21
21
|
],
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"
|
|
24
|
-
"
|
|
23
|
+
"@types/node": "^22.8.6",
|
|
24
|
+
"typescript": "^5.6.2"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
+
"@types/dockerode": "^4.0.1",
|
|
28
|
+
"dockerode": "^4.0.9",
|
|
27
29
|
"enquirer": "^2.4.1"
|
|
28
30
|
}
|
|
29
31
|
}
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"extends": "./tsconfig.json",
|
|
3
|
-
"
|
|
4
|
-
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"rootDir": "src",
|
|
5
|
+
"incremental": false
|
|
6
|
+
},
|
|
7
|
+
"exclude": [
|
|
8
|
+
"node_modules",
|
|
9
|
+
"test",
|
|
10
|
+
"**/*spec.ts",
|
|
11
|
+
"prisma",
|
|
12
|
+
"prisma.config.ts"
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"react": "^19.2.0",
|
|
14
14
|
"react-dom": "^19.2.0",
|
|
15
|
-
"listpage-next": "~0.0.
|
|
15
|
+
"listpage-next": "~0.0.296",
|
|
16
16
|
"react-router-dom": ">=6.0.0",
|
|
17
17
|
"@ant-design/v5-patch-for-react-19": "~1.0.3",
|
|
18
18
|
"ahooks": "^3.9.5",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"styled-components": "^6.1.19",
|
|
24
24
|
"mobx": "~6.15.0",
|
|
25
25
|
"@ant-design/icons": "~6.0.2",
|
|
26
|
-
"listpage-components": "~0.0.
|
|
26
|
+
"listpage-components": "~0.0.296",
|
|
27
27
|
"lucide-react": "~0.575.0"
|
|
28
28
|
"mobx-react-lite": "~4.1.1"
|
|
29
29
|
},
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"artifacts": {
|
|
3
|
+
"frontend": [
|
|
4
|
+
{
|
|
5
|
+
"projectDir": "apps/__FRONTEND_NAME__",
|
|
6
|
+
"packageSubDir": "public",
|
|
7
|
+
"buildArtifactDirName": "dist",
|
|
8
|
+
"artifactAlias": "__APP_NAME__"
|
|
9
|
+
}
|
|
10
|
+
],
|
|
11
|
+
"backend": {
|
|
12
|
+
"projectDir": "servers/__BACKEND_NAME__",
|
|
13
|
+
"packageSubDir": ".",
|
|
14
|
+
"buildArtifactDirName": "dist",
|
|
15
|
+
"artifactAlias": "dist"
|
|
16
|
+
},
|
|
17
|
+
"copyFiles": [
|
|
18
|
+
{
|
|
19
|
+
"source": "servers/__BACKEND_NAME__/prisma",
|
|
20
|
+
"dest": "prisma"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"source": "servers/__BACKEND_NAME__/Dockerfile",
|
|
24
|
+
"dest": "Dockerfile"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"source": "servers/__BACKEND_NAME__/package.json",
|
|
28
|
+
"dest": "package.json"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
"docker": {
|
|
33
|
+
"imageName": "__APP_NAME__",
|
|
34
|
+
"registry": {
|
|
35
|
+
"url": "registry.cn-hangzhou.aliyuncs.com",
|
|
36
|
+
"namespace": "",
|
|
37
|
+
"username": "",
|
|
38
|
+
"password": ""
|
|
39
|
+
},
|
|
40
|
+
"build": {
|
|
41
|
+
"platform": "linux/amd64"
|
|
42
|
+
},
|
|
43
|
+
"releaseProfiles": {
|
|
44
|
+
"dev": {
|
|
45
|
+
"tag": "0.0.1",
|
|
46
|
+
"envFile": "env/.dev"
|
|
47
|
+
},
|
|
48
|
+
"test": {
|
|
49
|
+
"tag": "0.0.1-test",
|
|
50
|
+
"containerOverrides": {
|
|
51
|
+
"env": {
|
|
52
|
+
"NODE_ENV": "test"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"online": {
|
|
57
|
+
"tag": "0.0.1-prod",
|
|
58
|
+
"buildOverrides": {
|
|
59
|
+
"platform": "linux/amd64"
|
|
60
|
+
},
|
|
61
|
+
"containerOverrides": {
|
|
62
|
+
"env": {
|
|
63
|
+
"NODE_ENV": "production"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"remote": {
|
|
69
|
+
"socketPath": "/var/run/docker.sock",
|
|
70
|
+
"host": "localhost",
|
|
71
|
+
"port": 2376,
|
|
72
|
+
"protocol": "https",
|
|
73
|
+
"tls": {
|
|
74
|
+
"ca": "",
|
|
75
|
+
"cert": "",
|
|
76
|
+
"key": ""
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"container": {
|
|
80
|
+
"name": "__APP_NAME__",
|
|
81
|
+
"ports": ["3000:3000/tcp"],
|
|
82
|
+
"envFile": "env/.dev",
|
|
83
|
+
"env": {
|
|
84
|
+
"NODE_ENV": "development"
|
|
85
|
+
},
|
|
86
|
+
"volumes": []
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
package/bin/copy.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.copyRushTemplate = copyRushTemplate;
|
|
4
|
-
exports.updateRushJsonProjects = updateRushJsonProjects;
|
|
5
|
-
exports.copyFrontendTemplate = copyFrontendTemplate;
|
|
6
|
-
exports.copyBackendTemplate = copyBackendTemplate;
|
|
7
|
-
exports.copyDeployScriptTemplate = copyDeployScriptTemplate;
|
|
8
|
-
exports.ensureDir = ensureDir;
|
|
9
|
-
exports.isDirEmpty = isDirEmpty;
|
|
10
|
-
exports.copySkillDir = copySkillDir;
|
|
11
|
-
const node_fs_adapter_1 = require("./adapters/node-fs-adapter");
|
|
12
|
-
const filesystem_capability_service_1 = require("./services/filesystem-capability-service");
|
|
13
|
-
const fsAdapter = (0, node_fs_adapter_1.createNodeFsAdapter)();
|
|
14
|
-
const filesystemCapability = (0, filesystem_capability_service_1.createFilesystemCapabilityService)(fsAdapter, {
|
|
15
|
-
templateRootDir: fsAdapter.resolve(__dirname, "..", "templates"),
|
|
16
|
-
});
|
|
17
|
-
function copyRushTemplate(targetDir, vars) {
|
|
18
|
-
filesystemCapability.copyRushTemplate(targetDir, vars);
|
|
19
|
-
}
|
|
20
|
-
function updateRushJsonProjects(filepath, feAppName, beAppName) {
|
|
21
|
-
filesystemCapability.updateRushJsonProjects(filepath, feAppName, beAppName);
|
|
22
|
-
}
|
|
23
|
-
function copyFrontendTemplate(targetDir, vars) {
|
|
24
|
-
filesystemCapability.copyFrontendTemplate(targetDir, vars);
|
|
25
|
-
}
|
|
26
|
-
function copyBackendTemplate(targetDir, vars) {
|
|
27
|
-
filesystemCapability.copyBackendTemplate(targetDir, vars);
|
|
28
|
-
}
|
|
29
|
-
function copyDeployScriptTemplate(targetDir, vars) {
|
|
30
|
-
filesystemCapability.copyDeployScriptTemplate(targetDir, vars);
|
|
31
|
-
}
|
|
32
|
-
function ensureDir(dir) {
|
|
33
|
-
fsAdapter.ensureDir(dir);
|
|
34
|
-
}
|
|
35
|
-
function isDirEmpty(dir) {
|
|
36
|
-
return filesystemCapability.isDirEmpty(dir);
|
|
37
|
-
}
|
|
38
|
-
function copySkillDir(sourceDir, targetDir) {
|
|
39
|
-
filesystemCapability.copySkillDir(sourceDir, targetDir);
|
|
40
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# Dependencies
|
|
2
|
-
node_modules/
|
|
3
|
-
npm-debug.log*
|
|
4
|
-
yarn-debug.log*
|
|
5
|
-
yarn-error.log*
|
|
6
|
-
|
|
7
|
-
# Build outputs
|
|
8
|
-
dist/
|
|
9
|
-
build/
|
|
10
|
-
temp/
|
|
11
|
-
output/
|
|
12
|
-
|
|
13
|
-
# Package files
|
|
14
|
-
*.zip
|
|
15
|
-
*.tar.gz
|
|
16
|
-
|
|
17
|
-
# IDE
|
|
18
|
-
.vscode/
|
|
19
|
-
.idea/
|
|
20
|
-
*.swp
|
|
21
|
-
*.swo
|
|
22
|
-
|
|
23
|
-
# OS
|
|
24
|
-
.DS_Store
|
|
25
|
-
Thumbs.db
|
|
26
|
-
|
|
27
|
-
# Logs
|
|
28
|
-
*.log
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
## 内网部署方案
|
|
2
|
-
|
|
3
|
-
### 步骤一:源码构建
|
|
4
|
-
|
|
5
|
-
`npm run build`
|
|
6
|
-
|
|
7
|
-
此时会将前后端的代码打包在`output`目录下
|
|
8
|
-
|
|
9
|
-
### 步骤二:修改 prisma 连接 url
|
|
10
|
-
|
|
11
|
-
修改`output/prisma/schema.prisma`文件中的`datasource db`的`url`为内网的 url
|
|
12
|
-
|
|
13
|
-
### 步骤三:内网环境仿真
|
|
14
|
-
|
|
15
|
-
修改 dockerfile 中的基础镜像
|
|
16
|
-
|
|
17
|
-
### 步骤四:带依赖的源码导出
|
|
18
|
-
|
|
19
|
-
`npm run package`
|
|
20
|
-
|
|
21
|
-
此时会根据 dockerfile 中的基础镜像,将`output`目录下的代码和依赖导出到`output`目录下,比如 `docker-app-xxxxxx.tar.gz`
|
|
22
|
-
|
|
23
|
-
### 步骤五:内网部署
|
|
24
|
-
|
|
25
|
-
将导出的`docker-app-xxxxxx.tar.gz`文件上传到内网的服务器上,比如 `/opt/docker-app-xxxxxx.tar.gz`
|
|
26
|
-
|
|
27
|
-
然后解压源码:
|
|
28
|
-
|
|
29
|
-
`tar -zxvf docker-app-xxxxxx.tar.gz`
|
|
30
|
-
|
|
31
|
-
### 步骤六:启动服务
|
|
32
|
-
|
|
33
|
-
进入到 dist 目录下, node main.js
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "package-app",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "",
|
|
5
|
-
"main": "dist/build.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"build": "ts-node src/build.ts",
|
|
8
|
-
"package": "ts-node src/package.ts",
|
|
9
|
-
"publish": "ts-node src/publish.ts"
|
|
10
|
-
},
|
|
11
|
-
"dependencies": {
|
|
12
|
-
"listpage-next-deploy": "0.0.294"
|
|
13
|
-
},
|
|
14
|
-
"devDependencies": {
|
|
15
|
-
"@types/node": "^20.0.0",
|
|
16
|
-
"@types/archiver": "^6.0.0",
|
|
17
|
-
"typescript": "^5.0.0",
|
|
18
|
-
"ts-node": "^10.9.0"
|
|
19
|
-
},
|
|
20
|
-
"keywords": [
|
|
21
|
-
"packaging",
|
|
22
|
-
"build",
|
|
23
|
-
"typescript"
|
|
24
|
-
],
|
|
25
|
-
"author": "",
|
|
26
|
-
"license": "MIT"
|
|
27
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { Config } from "listpage-next-deploy";
|
|
2
|
-
import path from "path";
|
|
3
|
-
|
|
4
|
-
export const config = new Config({
|
|
5
|
-
root: path.join(__dirname, "../../../../"),
|
|
6
|
-
clean: true,
|
|
7
|
-
outputBaseDir: "common/scripts/package-app/output",
|
|
8
|
-
frontend: [
|
|
9
|
-
{
|
|
10
|
-
source: "apps/__FRONTEND_NAME__",
|
|
11
|
-
output: "public/",
|
|
12
|
-
outputName: "dist",
|
|
13
|
-
outputNewName: "__APP_NAME__",
|
|
14
|
-
},
|
|
15
|
-
],
|
|
16
|
-
backend: {
|
|
17
|
-
source: "servers/__BACKEND_NAME__",
|
|
18
|
-
output: ".",
|
|
19
|
-
outputName: "dist",
|
|
20
|
-
outputNewName: "dist",
|
|
21
|
-
},
|
|
22
|
-
copyFiles: [
|
|
23
|
-
{
|
|
24
|
-
source: "servers/__BACKEND_NAME__/prisma",
|
|
25
|
-
dest: "common/scripts/package-app/output/prisma",
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
source: "servers/__BACKEND_NAME__/Dockerfile",
|
|
29
|
-
dest: "common/scripts/package-app/output/Dockerfile",
|
|
30
|
-
},
|
|
31
|
-
],
|
|
32
|
-
docker: {
|
|
33
|
-
imageName: "__APP_NAME__",
|
|
34
|
-
imageTag: "0.0.1",
|
|
35
|
-
containerName: "__APP_NAME__",
|
|
36
|
-
// 需要和 dockerfile 中定义的 app 目录保持一致
|
|
37
|
-
appName: "__APP_NAME__",
|
|
38
|
-
registry: {
|
|
39
|
-
url: "registry.cn-hangzhou.aliyuncs.com",
|
|
40
|
-
namespace: "",
|
|
41
|
-
username: "",
|
|
42
|
-
password: "",
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
});
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2020",
|
|
4
|
-
"module": "commonjs",
|
|
5
|
-
"lib": ["ES2020"],
|
|
6
|
-
"types": ["node"],
|
|
7
|
-
"outDir": "./dist",
|
|
8
|
-
"rootDir": "./src",
|
|
9
|
-
"strict": true,
|
|
10
|
-
"esModuleInterop": true,
|
|
11
|
-
"skipLibCheck": true,
|
|
12
|
-
"forceConsistentCasingInFileNames": true,
|
|
13
|
-
"resolveJsonModule": true,
|
|
14
|
-
"declaration": true,
|
|
15
|
-
"declarationMap": true,
|
|
16
|
-
"sourceMap": true
|
|
17
|
-
},
|
|
18
|
-
"include": [
|
|
19
|
-
"src/**/*"
|
|
20
|
-
],
|
|
21
|
-
"exclude": [
|
|
22
|
-
"node_modules",
|
|
23
|
-
"dist"
|
|
24
|
-
]
|
|
25
|
-
}
|
|
File without changes
|