@infly/libs 2.0.43 → 2.0.44
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 +92 -67
- package/adapters/vue2/build/webpack5/inline-runtime-plugin.js +35 -0
- package/adapters/vue2/build/webpack5/remove-legacy-assets-plugin.js +84 -0
- package/adapters/vue2/build/webpack5/webpack.base.js +437 -0
- package/adapters/vue2/module/Permission.js +204 -0
- package/adapters/vue2/postinstall.js +46 -0
- package/adapters/vue2/project-preview.js +148 -0
- package/adapters/vue2/script-config.js +26 -0
- package/adapters/vue2/store/index.js +1 -0
- package/adapters/vue2/store/modules/user.js +268 -0
- package/bin/cli.js +71 -71
- package/build/build-dist/index.js +863 -863
- package/build/build-dist/script-management.js +5 -5
- package/build/docker/compose-command.js +74 -74
- package/build/docker/compose-release.js +91 -91
- package/build/webpack5/inline-runtime-plugin.js +1 -35
- package/build/webpack5/remove-legacy-assets-plugin.js +1 -84
- package/build/webpack5/webpack.base.js +1 -435
- package/compat/init.js +9 -0
- package/index.js +8 -20
- package/module/Permission.js +1 -204
- package/module/REST.js +31 -19
- package/module/TokenService.js +9 -0
- package/module/Uts.js +460 -7252
- package/module/cjs/request-url-rules.cjs +6 -0
- package/module/cjs/rest-error-rules.cjs +33 -0
- package/package.json +121 -92
- package/script/build/deps.js +1 -1
- package/script/build/webhook.js +3 -2
- package/script/git-automation/git-clone.js +3 -4
- package/script/git-automation/index.js +2 -2
- package/script/index.js +1 -26
- package/script/webhook/webhook.js +7 -2
- package/store/index.js +1 -0
- package/store/modules/user.js +1 -268
- package/tools/auto-export.js +1 -2
- package/tools/file-export.js +6 -4
- package/tools/project-command.js +194 -194
- package/tools/project-preview.js +1 -148
- package/tools/select-option.js +60 -60
- package/.prettierrc +0 -5
- package/build/build-dist/script-management.test.js +0 -16
- package/build/docker/compose-command.test.js +0 -148
- package/build/docker/compose-release.test.js +0 -101
- package/build/docker/docker-build-push.test.js +0 -124
- package/build/webpack5/webpack.base.test.js +0 -59
- package/lib/index.js +0 -6
- package/lib/server/connect.js +0 -3011
- package/lib/server/serve-static.js +0 -4848
- package/script/pts/cloud-scenes.mjs +0 -65
- package/script/pts/cloud.js +0 -151
- package/script/pts/generate-cloud-params.mjs +0 -210
- package/script/pts/generate-cloud-params.test.mjs +0 -67
- package/tools/project-command.test.js +0 -267
- package/tools/select-option.test.js +0 -52
- package/webpack.config.js +0 -38
package/tools/select-option.js
CHANGED
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
const EXIT_SELECTION = "__exit__";
|
|
2
|
-
|
|
3
|
-
function isReadlineClosedError(error) {
|
|
4
|
-
return error?.code === "ERR_USE_AFTER_CLOSE";
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
function makePromptCancellationSafe(prompt) {
|
|
8
|
-
const unsafeStop = prompt.stop;
|
|
9
|
-
if (typeof unsafeStop !== "function") return;
|
|
10
|
-
|
|
11
|
-
prompt.removeListener("close", unsafeStop);
|
|
12
|
-
const safeStop = () => {
|
|
13
|
-
try {
|
|
14
|
-
unsafeStop();
|
|
15
|
-
} catch (error) {
|
|
16
|
-
if (!isReadlineClosedError(error)) throw error;
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
prompt.stop = safeStop;
|
|
20
|
-
prompt.once("close", safeStop);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async function selectOption(message, choices, dependencies = {}) {
|
|
24
|
-
const stdin = dependencies.stdin || process.stdin;
|
|
25
|
-
const stdout = dependencies.stdout || process.stdout;
|
|
26
|
-
if (!stdin.isTTY || !stdout.isTTY) {
|
|
27
|
-
throw new Error(`${message}: interactive selection requires a TTY; pass an explicit option.`);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const Select = dependencies.Select || require("enquirer").Select;
|
|
31
|
-
const prompt = new Select({
|
|
32
|
-
name: "selection",
|
|
33
|
-
message,
|
|
34
|
-
stdin,
|
|
35
|
-
stdout,
|
|
36
|
-
choices: [
|
|
37
|
-
...choices.map((choice) => ({
|
|
38
|
-
name: choice.value,
|
|
39
|
-
message: choice.label,
|
|
40
|
-
})),
|
|
41
|
-
{ name: EXIT_SELECTION, message: "退出" },
|
|
42
|
-
],
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
prompt.once("start", makePromptCancellationSafe);
|
|
46
|
-
try {
|
|
47
|
-
return await prompt.run();
|
|
48
|
-
} catch (error) {
|
|
49
|
-
if (!error || error.name === "CancelPromptError" || isReadlineClosedError(error)) {
|
|
50
|
-
return EXIT_SELECTION;
|
|
51
|
-
}
|
|
52
|
-
throw error;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
module.exports = {
|
|
57
|
-
EXIT_SELECTION,
|
|
58
|
-
makePromptCancellationSafe,
|
|
59
|
-
selectOption,
|
|
60
|
-
};
|
|
1
|
+
const EXIT_SELECTION = "__exit__";
|
|
2
|
+
|
|
3
|
+
function isReadlineClosedError(error) {
|
|
4
|
+
return error?.code === "ERR_USE_AFTER_CLOSE";
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function makePromptCancellationSafe(prompt) {
|
|
8
|
+
const unsafeStop = prompt.stop;
|
|
9
|
+
if (typeof unsafeStop !== "function") return;
|
|
10
|
+
|
|
11
|
+
prompt.removeListener("close", unsafeStop);
|
|
12
|
+
const safeStop = () => {
|
|
13
|
+
try {
|
|
14
|
+
unsafeStop();
|
|
15
|
+
} catch (error) {
|
|
16
|
+
if (!isReadlineClosedError(error)) throw error;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
prompt.stop = safeStop;
|
|
20
|
+
prompt.once("close", safeStop);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function selectOption(message, choices, dependencies = {}) {
|
|
24
|
+
const stdin = dependencies.stdin || process.stdin;
|
|
25
|
+
const stdout = dependencies.stdout || process.stdout;
|
|
26
|
+
if (!stdin.isTTY || !stdout.isTTY) {
|
|
27
|
+
throw new Error(`${message}: interactive selection requires a TTY; pass an explicit option.`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const Select = dependencies.Select || require("enquirer").Select;
|
|
31
|
+
const prompt = new Select({
|
|
32
|
+
name: "selection",
|
|
33
|
+
message,
|
|
34
|
+
stdin,
|
|
35
|
+
stdout,
|
|
36
|
+
choices: [
|
|
37
|
+
...choices.map((choice) => ({
|
|
38
|
+
name: choice.value,
|
|
39
|
+
message: choice.label,
|
|
40
|
+
})),
|
|
41
|
+
{ name: EXIT_SELECTION, message: "退出" },
|
|
42
|
+
],
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
prompt.once("start", makePromptCancellationSafe);
|
|
46
|
+
try {
|
|
47
|
+
return await prompt.run();
|
|
48
|
+
} catch (error) {
|
|
49
|
+
if (!error || error.name === "CancelPromptError" || isReadlineClosedError(error)) {
|
|
50
|
+
return EXIT_SELECTION;
|
|
51
|
+
}
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = {
|
|
57
|
+
EXIT_SELECTION,
|
|
58
|
+
makePromptCancellationSafe,
|
|
59
|
+
selectOption,
|
|
60
|
+
};
|
package/.prettierrc
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
const assert = require("node:assert/strict");
|
|
2
|
-
const test = require("node:test");
|
|
3
|
-
|
|
4
|
-
const { shouldManageBuildScripts } = require("./script-management");
|
|
5
|
-
|
|
6
|
-
test("shouldManageBuildScripts defaults to existing automatic script management", () => {
|
|
7
|
-
assert.equal(shouldManageBuildScripts(), true);
|
|
8
|
-
assert.equal(shouldManageBuildScripts({ buildConfigs: {} }), true);
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
test("shouldManageBuildScripts allows a project to own its build scripts", () => {
|
|
12
|
-
assert.equal(
|
|
13
|
-
shouldManageBuildScripts({ buildConfigs: { manageScripts: false } }),
|
|
14
|
-
false,
|
|
15
|
-
);
|
|
16
|
-
});
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
const assert = require("node:assert/strict");
|
|
2
|
-
const fs = require("node:fs");
|
|
3
|
-
const os = require("node:os");
|
|
4
|
-
const path = require("node:path");
|
|
5
|
-
const test = require("node:test");
|
|
6
|
-
|
|
7
|
-
const { runComposeCommand } = require("./compose-command");
|
|
8
|
-
const { EXIT_SELECTION } = require("../../tools/select-option");
|
|
9
|
-
|
|
10
|
-
test("runComposeCommand resolves a configured target relative to its config file", async () => {
|
|
11
|
-
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "compose-command-"));
|
|
12
|
-
const configPath = path.join(dir, "docker.targets.js");
|
|
13
|
-
fs.writeFileSync(
|
|
14
|
-
configPath,
|
|
15
|
-
`module.exports = { targets: { qdxy: { label: "青岛信跃", file: "docker-compose.qdxy.yaml" } } };`,
|
|
16
|
-
);
|
|
17
|
-
const calls = [];
|
|
18
|
-
|
|
19
|
-
try {
|
|
20
|
-
await runComposeCommand(
|
|
21
|
-
{ config: configPath, target: "qdxy", push: true, dryRun: true },
|
|
22
|
-
{ composeRelease: (options) => calls.push(options) },
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
assert.deepEqual(calls, [{
|
|
26
|
-
projectDir: dir,
|
|
27
|
-
file: "docker-compose.qdxy.yaml",
|
|
28
|
-
bump: "patch",
|
|
29
|
-
push: true,
|
|
30
|
-
dryRun: true,
|
|
31
|
-
}]);
|
|
32
|
-
} finally {
|
|
33
|
-
fs.rmSync(dir, { recursive: true, force: true });
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
test("runComposeCommand discovers targets from package.json in the working directory", async () => {
|
|
38
|
-
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "compose-package-config-"));
|
|
39
|
-
fs.writeFileSync(
|
|
40
|
-
path.join(dir, "package.json"),
|
|
41
|
-
JSON.stringify({
|
|
42
|
-
infly: {
|
|
43
|
-
docker: {
|
|
44
|
-
targets: {
|
|
45
|
-
qdxy: { label: "青岛信跃", file: "docker-compose.qdxy.yaml" },
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
}),
|
|
50
|
-
);
|
|
51
|
-
const calls = [];
|
|
52
|
-
|
|
53
|
-
try {
|
|
54
|
-
await runComposeCommand(
|
|
55
|
-
{ cwd: dir, target: "qdxy", push: true, dryRun: true },
|
|
56
|
-
{ composeRelease: (options) => calls.push(options) },
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
assert.deepEqual(calls, [{
|
|
60
|
-
projectDir: dir,
|
|
61
|
-
file: "docker-compose.qdxy.yaml",
|
|
62
|
-
bump: "patch",
|
|
63
|
-
push: true,
|
|
64
|
-
dryRun: true,
|
|
65
|
-
}]);
|
|
66
|
-
} finally {
|
|
67
|
-
fs.rmSync(dir, { recursive: true, force: true });
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
test("runComposeCommand prompts for a target when omitted", async () => {
|
|
72
|
-
const calls = [];
|
|
73
|
-
|
|
74
|
-
await runComposeCommand(
|
|
75
|
-
{
|
|
76
|
-
configObject: {
|
|
77
|
-
targets: {
|
|
78
|
-
yhqy: { label: "邮惠权益", file: "docker-compose.yaml" },
|
|
79
|
-
qdxy: { label: "青岛信跃", file: "docker-compose.qdxy.yaml" },
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
configDir: "C:/dist",
|
|
83
|
-
dryRun: true,
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
selectOption: async (message, choices) => {
|
|
87
|
-
assert.equal(message, "请选择 Docker 发布目标");
|
|
88
|
-
assert.deepEqual(choices.map(({ value }) => value), ["yhqy", "qdxy"]);
|
|
89
|
-
return "qdxy";
|
|
90
|
-
},
|
|
91
|
-
composeRelease: (options) => calls.push(options),
|
|
92
|
-
},
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
assert.equal(calls[0].file, "docker-compose.qdxy.yaml");
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
test("runComposeCommand exits without publishing when the user chooses exit", async () => {
|
|
99
|
-
const logs = [];
|
|
100
|
-
const result = await runComposeCommand(
|
|
101
|
-
{
|
|
102
|
-
configObject: {
|
|
103
|
-
targets: {
|
|
104
|
-
qdxy: { label: "青岛信跃", file: "docker-compose.qdxy.yaml" },
|
|
105
|
-
},
|
|
106
|
-
},
|
|
107
|
-
configDir: "C:/dist",
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
selectOption: async () => EXIT_SELECTION,
|
|
111
|
-
log: (message) => logs.push(message),
|
|
112
|
-
composeRelease: () => assert.fail("release should not run after exit"),
|
|
113
|
-
},
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
assert.deepEqual(result, { cancelled: true });
|
|
117
|
-
assert.deepEqual(logs, ["已退出,未执行任何操作。"]);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
test("runComposeCommand preserves direct project-dir and file usage", async () => {
|
|
121
|
-
const calls = [];
|
|
122
|
-
|
|
123
|
-
await runComposeCommand(
|
|
124
|
-
{ projectDir: "apps/dist", file: "docker-compose.yaml", dryRun: true },
|
|
125
|
-
{ composeRelease: (options) => calls.push(options) },
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
assert.deepEqual(calls, [{
|
|
129
|
-
projectDir: "apps/dist",
|
|
130
|
-
file: "docker-compose.yaml",
|
|
131
|
-
dryRun: true,
|
|
132
|
-
}]);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
test("postal dist package owns its Docker target mapping", () => {
|
|
136
|
-
const projectDir = path.resolve(__dirname, "../../../../apps/postal-benefits-platform-dist");
|
|
137
|
-
const packageJson = require(path.join(projectDir, "package.json"));
|
|
138
|
-
|
|
139
|
-
assert.equal(packageJson.scripts["docker:release"], "infly-libs docker:compose --push");
|
|
140
|
-
assert.deepEqual(packageJson.infly.docker.targets, {
|
|
141
|
-
yhqy: { label: "邮惠权益默认前端", file: "docker-compose.frontend.yaml" },
|
|
142
|
-
sq223: { label: "宿迁贰贰叁", file: "docker-compose.frontend.sq223.yaml" },
|
|
143
|
-
qdxy: { label: "青岛信跃", file: "docker-compose.frontend.qdxy.yaml" },
|
|
144
|
-
xzya: { label: "徐州沂埃", file: "docker-compose.frontend.xzya.yaml" },
|
|
145
|
-
next: { label: "邮惠权益 Next", file: "docker-compose.frontend.next.yaml" },
|
|
146
|
-
});
|
|
147
|
-
assert.equal(fs.existsSync(path.join(projectDir, "docker.targets.js")), false);
|
|
148
|
-
});
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
const assert = require("node:assert/strict");
|
|
2
|
-
const fs = require("node:fs");
|
|
3
|
-
const os = require("node:os");
|
|
4
|
-
const path = require("node:path");
|
|
5
|
-
const test = require("node:test");
|
|
6
|
-
|
|
7
|
-
const {
|
|
8
|
-
bumpComposeImageVersion,
|
|
9
|
-
composeRelease,
|
|
10
|
-
} = require("./compose-release");
|
|
11
|
-
|
|
12
|
-
const composeSource = `services:\n frontend:\n image: registry.example.com/team/app:1.2.9\n`;
|
|
13
|
-
|
|
14
|
-
test("bumpComposeImageVersion bumps exactly one image patch version", () => {
|
|
15
|
-
const result = bumpComposeImageVersion(composeSource, "patch");
|
|
16
|
-
|
|
17
|
-
assert.equal(
|
|
18
|
-
result.content,
|
|
19
|
-
`services:\n frontend:\n image: registry.example.com/team/app:1.2.10\n`,
|
|
20
|
-
);
|
|
21
|
-
assert.equal(result.from, "registry.example.com/team/app:1.2.9");
|
|
22
|
-
assert.equal(result.to, "registry.example.com/team/app:1.2.10");
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test("bumpComposeImageVersion rejects zero or multiple versioned images", () => {
|
|
26
|
-
assert.throws(() => bumpComposeImageVersion("services: {}\n", "patch"), /exactly one versioned image/);
|
|
27
|
-
assert.throws(
|
|
28
|
-
() => bumpComposeImageVersion(`${composeSource} worker:\n image: team/worker:2.0.0\n`, "patch"),
|
|
29
|
-
/exactly one versioned image/,
|
|
30
|
-
);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test("composeRelease dry-run does not write or invoke Docker", () => {
|
|
34
|
-
const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), "compose-release-"));
|
|
35
|
-
const composeFile = "docker-compose.yaml";
|
|
36
|
-
const composePath = path.join(projectDir, composeFile);
|
|
37
|
-
fs.writeFileSync(composePath, composeSource);
|
|
38
|
-
const calls = [];
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
const result = composeRelease(
|
|
42
|
-
{ projectDir, file: composeFile, dryRun: true, push: true },
|
|
43
|
-
{ runDocker: (args) => calls.push(args) },
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
assert.equal(fs.readFileSync(composePath, "utf8"), composeSource);
|
|
47
|
-
assert.deepEqual(calls, []);
|
|
48
|
-
assert.equal(result.to, "registry.example.com/team/app:1.2.10");
|
|
49
|
-
} finally {
|
|
50
|
-
fs.rmSync(projectDir, { recursive: true, force: true });
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test("composeRelease builds without pushing unless push is explicit", () => {
|
|
55
|
-
const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), "compose-release-"));
|
|
56
|
-
const composeFile = "docker-compose.yaml";
|
|
57
|
-
const composePath = path.join(projectDir, composeFile);
|
|
58
|
-
fs.writeFileSync(composePath, composeSource);
|
|
59
|
-
const calls = [];
|
|
60
|
-
|
|
61
|
-
try {
|
|
62
|
-
composeRelease(
|
|
63
|
-
{ projectDir, file: composeFile },
|
|
64
|
-
{ runDocker: (args) => calls.push(args) },
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
assert.deepEqual(calls, [
|
|
68
|
-
["compose", "-f", composePath, "config"],
|
|
69
|
-
["compose", "-f", composePath, "build"],
|
|
70
|
-
]);
|
|
71
|
-
} finally {
|
|
72
|
-
fs.rmSync(projectDir, { recursive: true, force: true });
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
test("composeRelease restores the compose file when Docker fails", () => {
|
|
77
|
-
const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), "compose-release-"));
|
|
78
|
-
const composeFile = "docker-compose.yaml";
|
|
79
|
-
const composePath = path.join(projectDir, composeFile);
|
|
80
|
-
fs.writeFileSync(composePath, composeSource);
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
assert.throws(
|
|
84
|
-
() => composeRelease(
|
|
85
|
-
{ projectDir, file: composeFile, push: true },
|
|
86
|
-
{ runDocker: () => { throw new Error("docker failed"); } },
|
|
87
|
-
),
|
|
88
|
-
/docker failed/,
|
|
89
|
-
);
|
|
90
|
-
assert.equal(fs.readFileSync(composePath, "utf8"), composeSource);
|
|
91
|
-
} finally {
|
|
92
|
-
fs.rmSync(projectDir, { recursive: true, force: true });
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
test("composeRelease rejects files outside projectDir", () => {
|
|
97
|
-
assert.throws(
|
|
98
|
-
() => composeRelease({ projectDir: ".", file: "../docker-compose.yaml", dryRun: true }),
|
|
99
|
-
/inside project-dir/,
|
|
100
|
-
);
|
|
101
|
-
});
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
const assert = require("node:assert/strict");
|
|
2
|
-
const path = require("node:path");
|
|
3
|
-
const { spawnSync } = require("node:child_process");
|
|
4
|
-
const test = require("node:test");
|
|
5
|
-
|
|
6
|
-
const cliPath = path.resolve(__dirname, "../../bin/cli.js");
|
|
7
|
-
|
|
8
|
-
function parseArgsInChildProcess(argv) {
|
|
9
|
-
const source = `
|
|
10
|
-
const { parseArgs } = require(${JSON.stringify(cliPath)});
|
|
11
|
-
process.stdout.write(JSON.stringify(parseArgs(${JSON.stringify(argv)})));
|
|
12
|
-
`;
|
|
13
|
-
return spawnSync(process.execPath, ["-e", source], {
|
|
14
|
-
encoding: "utf-8",
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
test("parseArgs keeps existing defaults and options", () => {
|
|
19
|
-
const result = parseArgsInChildProcess(["--local", "--env", "dev", "--dry-run"]);
|
|
20
|
-
|
|
21
|
-
assert.equal(result.status, 0, result.stderr);
|
|
22
|
-
assert.deepEqual(JSON.parse(result.stdout), {
|
|
23
|
-
env: "dev",
|
|
24
|
-
local: true,
|
|
25
|
-
dryRun: true,
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
test("parseArgs accepts spaced and equals cicd URL forms", () => {
|
|
30
|
-
const url = "https://cicd.sutpay.com/view/积分商城/";
|
|
31
|
-
const spaced = parseArgsInChildProcess(["--cicd-url", url]);
|
|
32
|
-
const equals = parseArgsInChildProcess([`--cicd-url=${url}`]);
|
|
33
|
-
|
|
34
|
-
assert.equal(spaced.status, 0, spaced.stderr);
|
|
35
|
-
assert.equal(equals.status, 0, equals.stderr);
|
|
36
|
-
assert.equal(JSON.parse(spaced.stdout).cicdUrl, url);
|
|
37
|
-
assert.equal(JSON.parse(equals.stdout).cicdUrl, url);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
test("parseArgs accepts Docker Compose release options", () => {
|
|
41
|
-
const result = parseArgsInChildProcess([
|
|
42
|
-
"--project-dir",
|
|
43
|
-
"apps/deploy",
|
|
44
|
-
"--file=docker-compose.yaml",
|
|
45
|
-
"--bump",
|
|
46
|
-
"patch",
|
|
47
|
-
"--push",
|
|
48
|
-
"--config",
|
|
49
|
-
"docker.targets.js",
|
|
50
|
-
"--target=qdxy",
|
|
51
|
-
"--dry-run",
|
|
52
|
-
]);
|
|
53
|
-
|
|
54
|
-
assert.equal(result.status, 0, result.stderr);
|
|
55
|
-
assert.deepEqual(JSON.parse(result.stdout), {
|
|
56
|
-
env: "prod",
|
|
57
|
-
local: false,
|
|
58
|
-
dryRun: true,
|
|
59
|
-
projectDir: "apps/deploy",
|
|
60
|
-
file: "docker-compose.yaml",
|
|
61
|
-
bump: "patch",
|
|
62
|
-
push: true,
|
|
63
|
-
config: "docker.targets.js",
|
|
64
|
-
target: "qdxy",
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
test("parseProjectArgs leaves environment unset for interactive selection", () => {
|
|
68
|
-
const source = `
|
|
69
|
-
const { parseProjectArgs } = require(${JSON.stringify(cliPath)});
|
|
70
|
-
process.stdout.write(JSON.stringify({
|
|
71
|
-
interactive: parseProjectArgs([]),
|
|
72
|
-
explicit: parseProjectArgs(["--env", "stage", "--target", "qdxy"]),
|
|
73
|
-
}));
|
|
74
|
-
`;
|
|
75
|
-
const result = spawnSync(process.execPath, ["-e", source], { encoding: "utf-8" });
|
|
76
|
-
|
|
77
|
-
assert.equal(result.status, 0, result.stderr);
|
|
78
|
-
assert.deepEqual(JSON.parse(result.stdout), {
|
|
79
|
-
interactive: { dryRun: false },
|
|
80
|
-
explicit: { dryRun: false, env: "stage", target: "qdxy" },
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
test("parseArgs rejects cicd URL without a value", () => {
|
|
84
|
-
const result = parseArgsInChildProcess(["--cicd-url"]);
|
|
85
|
-
|
|
86
|
-
assert.notEqual(result.status, 0);
|
|
87
|
-
assert.match(result.stderr, /--cicd-url/);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
test("CLI keeps the existing unknown command output", () => {
|
|
91
|
-
const result = spawnSync(process.execPath, [cliPath, "unknown-command"], {
|
|
92
|
-
encoding: "utf-8",
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
assert.equal(result.status, 1);
|
|
96
|
-
assert.match(result.stderr, /未知命令: unknown-command/);
|
|
97
|
-
assert.match(result.stdout, /可用命令:/);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
test("formatCicdLink returns no output when option is absent", () => {
|
|
101
|
-
const { formatCicdLink } = require("./docker-build-push");
|
|
102
|
-
|
|
103
|
-
assert.equal(formatCicdLink(), "");
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
test("formatCicdLink normalizes encoded Chinese URL and colors it blue", () => {
|
|
107
|
-
const { formatCicdLink } = require("./docker-build-push");
|
|
108
|
-
const result = formatCicdLink(
|
|
109
|
-
"https://cicd.sutpay.com/view/%E7%A7%AF%E5%88%86%E5%95%86%E5%9F%8E/"
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
assert.equal(
|
|
113
|
-
result,
|
|
114
|
-
"发布系统:\x1b[34mhttps://cicd.sutpay.com/view/积分商城/\x1b[0m"
|
|
115
|
-
);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
test("formatCicdLink rejects unsafe URL values", () => {
|
|
119
|
-
const { formatCicdLink } = require("./docker-build-push");
|
|
120
|
-
|
|
121
|
-
assert.throws(() => formatCicdLink("ftp://cicd.sutpay.com/build"), /HTTP\/HTTPS/);
|
|
122
|
-
assert.throws(() => formatCicdLink("https://user:secret@cicd.sutpay.com/"), /凭据/);
|
|
123
|
-
assert.throws(() => formatCicdLink("https://cicd.sutpay.com/\nnext"), /控制字符/);
|
|
124
|
-
});
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const assert = require("node:assert/strict");
|
|
4
|
-
const test = require("node:test");
|
|
5
|
-
const { chainWebpack } = require("./webpack.base");
|
|
6
|
-
|
|
7
|
-
function createChainConfig() {
|
|
8
|
-
let htmlPluginOptions;
|
|
9
|
-
const chain = new Proxy(
|
|
10
|
-
function () {},
|
|
11
|
-
{
|
|
12
|
-
get(_target, property) {
|
|
13
|
-
if (property === "plugin") {
|
|
14
|
-
return (name) => ({
|
|
15
|
-
tap(callback) {
|
|
16
|
-
if (name === "html") {
|
|
17
|
-
[htmlPluginOptions] = callback([htmlPluginOptions || {}]);
|
|
18
|
-
}
|
|
19
|
-
return this;
|
|
20
|
-
},
|
|
21
|
-
use() {
|
|
22
|
-
return this;
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return chain;
|
|
28
|
-
},
|
|
29
|
-
apply() {
|
|
30
|
-
return chain;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
return {
|
|
36
|
-
config: chain,
|
|
37
|
-
getHtmlPluginOptions: () => htmlPluginOptions
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
test("chainWebpack 默认不增加 HTML 插件参数", () => {
|
|
42
|
-
const { config, getHtmlPluginOptions } = createChainConfig();
|
|
43
|
-
|
|
44
|
-
chainWebpack(config);
|
|
45
|
-
|
|
46
|
-
assert.equal(getHtmlPluginOptions()?.faviconPath, undefined);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test("chainWebpack 合并调用方传入的 HTML 插件参数", () => {
|
|
50
|
-
const { config, getHtmlPluginOptions } = createChainConfig();
|
|
51
|
-
|
|
52
|
-
chainWebpack(config, {
|
|
53
|
-
htmlPluginOptions: {
|
|
54
|
-
faviconPath: "favicon_xzya.ico"
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
assert.equal(getHtmlPluginOptions()?.faviconPath, "favicon_xzya.ico");
|
|
59
|
-
});
|