@ws-test-realm/admin-kit 0.1.7 → 0.1.8
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/ws-modules.js +29 -9
- package/lib/deploy-remotes.js +10 -99
- package/lib/purge-jar.js +50 -0
- package/lib/purge-remotes.js +120 -0
- package/lib/target-resolution.js +121 -0
- package/package.json +1 -1
- package/template/package.json +1 -0
package/bin/ws-modules.js
CHANGED
|
@@ -3,58 +3,76 @@
|
|
|
3
3
|
// workspace.
|
|
4
4
|
//
|
|
5
5
|
// Usage:
|
|
6
|
-
// ws-modules <names...|all> [--build] [--pack] [--deploy] [--with-deps]
|
|
6
|
+
// ws-modules <names...|all> [--build] [--pack] [--deploy] [--purge] [--with-deps]
|
|
7
7
|
//
|
|
8
8
|
// <names...> one or more project names from angular.json
|
|
9
9
|
// all expand to every project in angular.json
|
|
10
10
|
// --build ng build each lib (topo-ordered)
|
|
11
11
|
// --pack federation-pack each lib into dist/admin-remotes/<id>/
|
|
12
12
|
// --deploy push jar + types into <wpmRoot>/<modulesFolder>/<id>-*.jar
|
|
13
|
+
// --purge strip prior federation contribution from the jar (or ext
|
|
14
|
+
// dir) and host's .federation/<id>/ types dir. Resolves the
|
|
15
|
+
// target the same way --deploy does (wsconfig override >
|
|
16
|
+
// project package.json's wsmodules.target / pom).
|
|
13
17
|
// --with-deps expand selection to include each name's in-workspace deps
|
|
14
18
|
//
|
|
15
19
|
// Behaviour:
|
|
16
20
|
// - No args at all → print usage, exit 1
|
|
17
21
|
// - Positional + step flag(s) → run exactly those steps, non-interactive
|
|
18
22
|
// - Positional, no step flags → prompt y/n for each of build/pack/deploy
|
|
19
|
-
// (and --with-deps); run the selected set
|
|
23
|
+
// (and --with-deps); run the selected set.
|
|
24
|
+
// Purge is NOT prompted (destructive +
|
|
25
|
+
// not part of the normal wire cycle).
|
|
20
26
|
// - Step flag(s) but no positional → error (need to know what to operate on)
|
|
21
27
|
//
|
|
28
|
+
// Step ordering when multiple are passed: purge → build → pack → deploy.
|
|
29
|
+
//
|
|
22
30
|
// Examples:
|
|
23
31
|
// ws-modules all # interactive
|
|
24
32
|
// ws-modules db-login # interactive, just this project
|
|
25
33
|
// ws-modules all --build --pack --deploy # wire the whole stack
|
|
26
34
|
// ws-modules db-login --build --with-deps # build db-login + its deps
|
|
27
35
|
// ws-modules crm shop-common --pack # pack two specific projects
|
|
36
|
+
// ws-modules all --purge # strip stale contributions
|
|
37
|
+
// ws-modules all --purge --build --pack --deploy # nuke + rewire
|
|
28
38
|
|
|
29
39
|
const readline = require("readline");
|
|
30
40
|
const { buildLibs, packRemotes } = require("../lib/build-modules");
|
|
31
41
|
const { deployRemotes } = require("../lib/deploy-remotes");
|
|
42
|
+
const { purgeRemotes } = require("../lib/purge-remotes");
|
|
32
43
|
|
|
33
|
-
const STEP_FLAGS = ["build", "pack", "deploy"];
|
|
44
|
+
const STEP_FLAGS = ["purge", "build", "pack", "deploy"];
|
|
34
45
|
const PASSIVE_FLAGS = ["with-deps"];
|
|
35
46
|
const KNOWN_FLAGS = new Set([...STEP_FLAGS, ...PASSIVE_FLAGS]);
|
|
36
47
|
|
|
37
|
-
const USAGE = `ws-modules <names...|all> [--build] [--pack] [--deploy] [--with-deps]
|
|
48
|
+
const USAGE = `ws-modules <names...|all> [--build] [--pack] [--deploy] [--purge] [--with-deps]
|
|
38
49
|
|
|
39
|
-
Drive build / pack / deploy across an admin-modules workspace.
|
|
50
|
+
Drive build / pack / deploy / purge across an admin-modules workspace.
|
|
40
51
|
|
|
41
52
|
Positional:
|
|
42
53
|
<names...> one or more project names from angular.json
|
|
43
54
|
all expand to every project in angular.json
|
|
44
55
|
|
|
45
|
-
Step flags (run exactly the steps you list — if none, you'll be prompted
|
|
56
|
+
Step flags (run exactly the steps you list — if none, you'll be prompted for
|
|
57
|
+
build/pack/deploy; purge is never prompted):
|
|
46
58
|
--build ng build each lib (topo-ordered)
|
|
47
59
|
--pack federation-pack each lib into dist/admin-remotes/<id>/
|
|
48
60
|
--deploy push jar + types into <wpmRoot>/<modulesFolder>/<id>-*.jar
|
|
61
|
+
--purge strip prior federation contribution from the jar (or ext
|
|
62
|
+
dir) and host's .federation/<id>/ types dir
|
|
49
63
|
|
|
50
64
|
Other:
|
|
51
65
|
--with-deps expand selection to include each name's in-workspace deps
|
|
52
66
|
|
|
67
|
+
Order when multiple steps are passed: purge → build → pack → deploy.
|
|
68
|
+
|
|
53
69
|
Examples:
|
|
54
70
|
ws-modules all
|
|
55
71
|
ws-modules db-login --build
|
|
56
72
|
ws-modules all --build --pack --deploy
|
|
57
73
|
ws-modules crm shop-common --pack
|
|
74
|
+
ws-modules all --purge
|
|
75
|
+
ws-modules all --purge --build --pack --deploy
|
|
58
76
|
`;
|
|
59
77
|
|
|
60
78
|
function parseArgv(argv) {
|
|
@@ -143,6 +161,7 @@ async function main() {
|
|
|
143
161
|
let withDeps;
|
|
144
162
|
if (stepFlagsPresent) {
|
|
145
163
|
steps = {
|
|
164
|
+
purge: !!argv.flags.purge,
|
|
146
165
|
build: !!argv.flags.build,
|
|
147
166
|
pack: !!argv.flags.pack,
|
|
148
167
|
deploy: !!argv.flags.deploy,
|
|
@@ -150,11 +169,11 @@ async function main() {
|
|
|
150
169
|
withDeps = !!argv.flags["with-deps"];
|
|
151
170
|
} else {
|
|
152
171
|
const ans = await promptForSteps(!!argv.flags["with-deps"]);
|
|
153
|
-
steps = { build: ans.build, pack: ans.pack, deploy: ans.deploy };
|
|
172
|
+
steps = { purge: false, build: ans.build, pack: ans.pack, deploy: ans.deploy };
|
|
154
173
|
withDeps = ans.withDeps;
|
|
155
174
|
}
|
|
156
175
|
|
|
157
|
-
if (!steps.build && !steps.pack && !steps.deploy) {
|
|
176
|
+
if (!steps.purge && !steps.build && !steps.pack && !steps.deploy) {
|
|
158
177
|
console.log("No steps selected. Nothing to do.");
|
|
159
178
|
return;
|
|
160
179
|
}
|
|
@@ -164,10 +183,11 @@ async function main() {
|
|
|
164
183
|
|
|
165
184
|
console.log(
|
|
166
185
|
`\nws-modules: ${argv.positional.join(" ")} →` +
|
|
167
|
-
` build=${steps.build} pack=${steps.pack} deploy=${steps.deploy}` +
|
|
186
|
+
` purge=${steps.purge} build=${steps.build} pack=${steps.pack} deploy=${steps.deploy}` +
|
|
168
187
|
` with-deps=${withDeps}`
|
|
169
188
|
);
|
|
170
189
|
|
|
190
|
+
if (steps.purge) purgeRemotes(common);
|
|
171
191
|
if (steps.build) buildLibs(common);
|
|
172
192
|
if (steps.pack) packRemotes(common);
|
|
173
193
|
if (steps.deploy) deployRemotes(common);
|
package/lib/deploy-remotes.js
CHANGED
|
@@ -2,85 +2,8 @@ const fs = require("fs");
|
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const { packIntoJar } = require("./pack-into-jar");
|
|
4
4
|
const { loadOrder, partitionByKind } = require("./build-modules");
|
|
5
|
-
const {
|
|
6
|
-
const {
|
|
7
|
-
|
|
8
|
-
function readWsconfig(workspaceDir) {
|
|
9
|
-
const file = path.join(workspaceDir, "wsconfig.json");
|
|
10
|
-
if (!fs.existsSync(file)) {
|
|
11
|
-
throw new Error(
|
|
12
|
-
`No wsconfig.json in ${workspaceDir}. Run \`ws-wire-host <wpm-root>\` first.`
|
|
13
|
-
);
|
|
14
|
-
}
|
|
15
|
-
return JSON.parse(fs.readFileSync(file, "utf8"));
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function readModulesJson(wpmRoot) {
|
|
19
|
-
const file = path.join(wpmRoot, "modules.json");
|
|
20
|
-
if (!fs.existsSync(file)) {
|
|
21
|
-
throw new Error(`No modules.json at ${wpmRoot}.`);
|
|
22
|
-
}
|
|
23
|
-
return JSON.parse(fs.readFileSync(file, "utf8"));
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function readProjectPkg(workspaceDir, name) {
|
|
27
|
-
const pkgPath = path.join(workspaceDir, "projects", name, "package.json");
|
|
28
|
-
if (!fs.existsSync(pkgPath)) return {};
|
|
29
|
-
try {
|
|
30
|
-
return JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
31
|
-
} catch {
|
|
32
|
-
return {};
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Decide jar vs ext for a project, honouring wsconfig override > package.json.
|
|
37
|
-
// Returns { kind: "jar", jarPath } or { kind: "ext", extDir }.
|
|
38
|
-
function resolveTarget({ workspaceDir, projectName, wsconfig, wpmRoot, modulesFolder }) {
|
|
39
|
-
const modulesDir = path.resolve(wpmRoot, modulesFolder);
|
|
40
|
-
const extDir = path.join(
|
|
41
|
-
wpmRoot,
|
|
42
|
-
"scripts",
|
|
43
|
-
"ext-admin-remotes",
|
|
44
|
-
projectName
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
// 1. wsconfig override
|
|
48
|
-
const override =
|
|
49
|
-
wsconfig.deployOverrides && wsconfig.deployOverrides[projectName];
|
|
50
|
-
if (override) {
|
|
51
|
-
if (override.jar && override.ext) {
|
|
52
|
-
throw new Error(
|
|
53
|
-
`wsconfig.deployOverrides.${projectName}: set exactly one of 'jar' or 'ext', not both`
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
if (override.ext === true) {
|
|
57
|
-
return { kind: "ext", extDir };
|
|
58
|
-
}
|
|
59
|
-
if (override.jar) {
|
|
60
|
-
const jarPath = resolveOne(modulesDir, override.jar, projectName);
|
|
61
|
-
return { kind: "jar", jarPath };
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// 2. project package.json
|
|
66
|
-
const pkg = readProjectPkg(workspaceDir, projectName);
|
|
67
|
-
const target = (pkg.wsmodules && pkg.wsmodules.target) || "jar";
|
|
68
|
-
if (target === "ext") {
|
|
69
|
-
return { kind: "ext", extDir };
|
|
70
|
-
}
|
|
71
|
-
if (target !== "jar") {
|
|
72
|
-
throw new Error(
|
|
73
|
-
`Invalid wsmodules.target for ${projectName}: ${JSON.stringify(target)} (expected 'jar' or 'ext')`
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// 3. pom-derived artifactId
|
|
78
|
-
const pomField = pkg.wsmodules && pkg.wsmodules.pom;
|
|
79
|
-
const pomPath = resolveProjectPom(workspaceDir, projectName, pomField);
|
|
80
|
-
const artifactId = readArtifactId(pomPath);
|
|
81
|
-
const jarPath = resolveOne(modulesDir, `${artifactId}-*.jar`, projectName);
|
|
82
|
-
return { kind: "jar", jarPath, pomPath, artifactId };
|
|
83
|
-
}
|
|
5
|
+
const { findMatches } = require("./jar-glob");
|
|
6
|
+
const { loadDeployContext, resolveTarget } = require("./target-resolution");
|
|
84
7
|
|
|
85
8
|
function copyTypes(distLib, hostFederationDir) {
|
|
86
9
|
if (fs.existsSync(hostFederationDir)) {
|
|
@@ -94,7 +17,6 @@ function copyTypes(distLib, hostFederationDir) {
|
|
|
94
17
|
// dir (replace-existing semantics). Also warn if a same-id-named jar exists
|
|
95
18
|
// in the modules folder — possible name-collision abuse signal.
|
|
96
19
|
function deployExt({ workspaceDir, id, modulesDir, extDir }) {
|
|
97
|
-
// Collision check: same constrained-glob rules as everywhere else.
|
|
98
20
|
const collisions = findMatches(modulesDir, `${id}-*.jar`);
|
|
99
21
|
if (collisions.length) {
|
|
100
22
|
const list = collisions.map((c) => path.join(modulesDir, c)).join(", ");
|
|
@@ -113,7 +35,6 @@ function deployExt({ workspaceDir, id, modulesDir, extDir }) {
|
|
|
113
35
|
}
|
|
114
36
|
fs.mkdirSync(extDir, { recursive: true });
|
|
115
37
|
fs.cpSync(srcDir, extDir, { recursive: true });
|
|
116
|
-
// Count files for the report.
|
|
117
38
|
let fileCount = 0;
|
|
118
39
|
const walk = (d) => {
|
|
119
40
|
for (const e of fs.readdirSync(d, { withFileTypes: true })) {
|
|
@@ -131,7 +52,8 @@ function deployOne({
|
|
|
131
52
|
id,
|
|
132
53
|
wpmRoot,
|
|
133
54
|
modulesFolder,
|
|
134
|
-
|
|
55
|
+
adminDir,
|
|
56
|
+
modulesDir,
|
|
135
57
|
wsconfig,
|
|
136
58
|
}) {
|
|
137
59
|
const distRemoteDir = path.join(workspaceDir, "dist", "admin-remotes", id);
|
|
@@ -146,8 +68,6 @@ function deployOne({
|
|
|
146
68
|
throw new Error(`Lib dist missing: ${distLibDir}. Run \`build\` first.`);
|
|
147
69
|
}
|
|
148
70
|
|
|
149
|
-
const modulesDir = path.resolve(wpmRoot, modulesFolder);
|
|
150
|
-
const adminDir = path.resolve(wpmRoot, adminBuildFolder);
|
|
151
71
|
const hostFederationDir = path.join(adminDir, ".federation", id);
|
|
152
72
|
|
|
153
73
|
const target = resolveTarget({
|
|
@@ -158,7 +78,6 @@ function deployOne({
|
|
|
158
78
|
modulesFolder,
|
|
159
79
|
});
|
|
160
80
|
|
|
161
|
-
// Perform the artifact deploy first; only on success do we touch host types.
|
|
162
81
|
let artifactReport;
|
|
163
82
|
if (target.kind === "jar") {
|
|
164
83
|
const packResult = packIntoJar({
|
|
@@ -183,22 +102,13 @@ function deployOne({
|
|
|
183
102
|
artifactReport = { kind: "ext", ...extResult };
|
|
184
103
|
}
|
|
185
104
|
|
|
186
|
-
// Artifact deploy succeeded — now publish types.
|
|
187
105
|
copyTypes(distLibDir, hostFederationDir);
|
|
188
106
|
|
|
189
107
|
return { ...artifactReport, hostFederationDir };
|
|
190
108
|
}
|
|
191
109
|
|
|
192
110
|
function deployRemotes({ workspaceDir, restrictTo = [], withDeps = false }) {
|
|
193
|
-
const
|
|
194
|
-
if (!wsconfig.wpmRoot) {
|
|
195
|
-
throw new Error(
|
|
196
|
-
"wsconfig.json missing wpmRoot. Run `ws-wire-host <wpm-root>`."
|
|
197
|
-
);
|
|
198
|
-
}
|
|
199
|
-
const modulesJson = readModulesJson(wsconfig.wpmRoot);
|
|
200
|
-
const modulesFolder = modulesJson.modulesFolder || "./modules";
|
|
201
|
-
const adminBuildFolder = modulesJson.adminBuildFolder || "./admin";
|
|
111
|
+
const ctx = loadDeployContext(workspaceDir);
|
|
202
112
|
|
|
203
113
|
const { order } = loadOrder({ workspaceDir, restrictTo, withDeps });
|
|
204
114
|
const { remotes, libraries } = partitionByKind(workspaceDir, order);
|
|
@@ -217,10 +127,11 @@ function deployRemotes({ workspaceDir, restrictTo = [], withDeps = false }) {
|
|
|
217
127
|
const r = deployOne({
|
|
218
128
|
workspaceDir,
|
|
219
129
|
id,
|
|
220
|
-
wpmRoot:
|
|
221
|
-
modulesFolder,
|
|
222
|
-
|
|
223
|
-
|
|
130
|
+
wpmRoot: ctx.wpmRoot,
|
|
131
|
+
modulesFolder: ctx.modulesFolder,
|
|
132
|
+
adminDir: ctx.adminDir,
|
|
133
|
+
modulesDir: ctx.modulesDir,
|
|
134
|
+
wsconfig: ctx.wsconfig,
|
|
224
135
|
});
|
|
225
136
|
if (r.kind === "jar") {
|
|
226
137
|
console.log(` target: jar`);
|
package/lib/purge-jar.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const AdmZip = require("adm-zip");
|
|
4
|
+
|
|
5
|
+
// Strip a federated remote contribution from a jar by dropping every entry
|
|
6
|
+
// under META-INF/federation/<id>/. Inverse of packIntoJar. Returns
|
|
7
|
+
// { jarPath, droppedEntries, hadContribution }.
|
|
8
|
+
function purgeJar({ jarPath, id }) {
|
|
9
|
+
if (!fs.existsSync(jarPath)) {
|
|
10
|
+
throw new Error(`Jar not found: ${jarPath}`);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const contribRoot = `META-INF/federation/${id}/`;
|
|
14
|
+
const original = new AdmZip(jarPath);
|
|
15
|
+
const out = new AdmZip();
|
|
16
|
+
|
|
17
|
+
let dropped = 0;
|
|
18
|
+
for (const entry of original.getEntries()) {
|
|
19
|
+
if (entry.entryName.startsWith(contribRoot)) {
|
|
20
|
+
dropped++;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (entry.isDirectory) {
|
|
24
|
+
out.addFile(entry.entryName, Buffer.alloc(0), "", entry.attr);
|
|
25
|
+
} else {
|
|
26
|
+
out.addFile(
|
|
27
|
+
entry.entryName,
|
|
28
|
+
entry.getData(),
|
|
29
|
+
entry.comment,
|
|
30
|
+
entry.attr
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (dropped === 0) {
|
|
36
|
+
return { jarPath, droppedEntries: 0, hadContribution: false };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const dir = path.dirname(jarPath);
|
|
40
|
+
const tmp = path.join(
|
|
41
|
+
dir,
|
|
42
|
+
`.${path.basename(jarPath)}.repack.${process.pid}.tmp`
|
|
43
|
+
);
|
|
44
|
+
out.writeZip(tmp);
|
|
45
|
+
fs.renameSync(tmp, jarPath);
|
|
46
|
+
|
|
47
|
+
return { jarPath, droppedEntries: dropped, hadContribution: true };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = { purgeJar };
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { purgeJar } = require("./purge-jar");
|
|
4
|
+
const { loadOrder, partitionByKind } = require("./build-modules");
|
|
5
|
+
const { loadDeployContext, resolveTarget } = require("./target-resolution");
|
|
6
|
+
|
|
7
|
+
// Purge a single remote's deployed footprint:
|
|
8
|
+
// - jar target: drop META-INF/federation/<id>/ entries from the jar
|
|
9
|
+
// - ext target: remove <wpmRoot>/scripts/ext-admin-remotes/<id>/
|
|
10
|
+
// - always: remove host's <adminDir>/.federation/<id>/ types dir
|
|
11
|
+
//
|
|
12
|
+
// Uses the exact same target resolution as deploy — wsconfig override >
|
|
13
|
+
// project package.json (target=ext | pom-derived artifactId). No part of the
|
|
14
|
+
// jar location is implied from the project id; same abuse-resistance as deploy.
|
|
15
|
+
function purgeOne({
|
|
16
|
+
workspaceDir,
|
|
17
|
+
id,
|
|
18
|
+
wpmRoot,
|
|
19
|
+
modulesFolder,
|
|
20
|
+
adminDir,
|
|
21
|
+
wsconfig,
|
|
22
|
+
}) {
|
|
23
|
+
const hostFederationDir = path.join(adminDir, ".federation", id);
|
|
24
|
+
|
|
25
|
+
const target = resolveTarget({
|
|
26
|
+
workspaceDir,
|
|
27
|
+
projectName: id,
|
|
28
|
+
wsconfig,
|
|
29
|
+
wpmRoot,
|
|
30
|
+
modulesFolder,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
let artifactReport;
|
|
34
|
+
if (target.kind === "jar") {
|
|
35
|
+
const result = purgeJar({ jarPath: target.jarPath, id });
|
|
36
|
+
artifactReport = {
|
|
37
|
+
kind: "jar",
|
|
38
|
+
jarPath: target.jarPath,
|
|
39
|
+
pomPath: target.pomPath,
|
|
40
|
+
artifactId: target.artifactId,
|
|
41
|
+
...result,
|
|
42
|
+
};
|
|
43
|
+
} else {
|
|
44
|
+
let removed = false;
|
|
45
|
+
if (fs.existsSync(target.extDir)) {
|
|
46
|
+
fs.rmSync(target.extDir, { recursive: true, force: true });
|
|
47
|
+
removed = true;
|
|
48
|
+
}
|
|
49
|
+
artifactReport = { kind: "ext", extDir: target.extDir, removedExtDir: removed };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let typesRemoved = false;
|
|
53
|
+
if (fs.existsSync(hostFederationDir)) {
|
|
54
|
+
fs.rmSync(hostFederationDir, { recursive: true, force: true });
|
|
55
|
+
typesRemoved = true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return { ...artifactReport, hostFederationDir, typesRemoved };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function purgeRemotes({ workspaceDir, restrictTo = [], withDeps = false }) {
|
|
62
|
+
const ctx = loadDeployContext(workspaceDir);
|
|
63
|
+
|
|
64
|
+
const { order } = loadOrder({ workspaceDir, restrictTo, withDeps });
|
|
65
|
+
const { remotes, libraries } = partitionByKind(workspaceDir, order);
|
|
66
|
+
|
|
67
|
+
console.log(`\n=== Purge order ===`);
|
|
68
|
+
remotes.forEach((n, i) => console.log(` ${i + 1}. ${n}`));
|
|
69
|
+
if (libraries.length) {
|
|
70
|
+
console.log(
|
|
71
|
+
` (skipping libraries: ${libraries.join(", ")} — wsmodules.kind=library)`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const results = [];
|
|
76
|
+
for (const id of remotes) {
|
|
77
|
+
console.log(`\n=== purge ${id} ===`);
|
|
78
|
+
try {
|
|
79
|
+
const r = purgeOne({
|
|
80
|
+
workspaceDir,
|
|
81
|
+
id,
|
|
82
|
+
wpmRoot: ctx.wpmRoot,
|
|
83
|
+
modulesFolder: ctx.modulesFolder,
|
|
84
|
+
adminDir: ctx.adminDir,
|
|
85
|
+
wsconfig: ctx.wsconfig,
|
|
86
|
+
});
|
|
87
|
+
if (r.kind === "jar") {
|
|
88
|
+
console.log(` target: jar`);
|
|
89
|
+
console.log(` jar: ${r.jarPath}`);
|
|
90
|
+
if (r.artifactId) console.log(` artifactId: ${r.artifactId}`);
|
|
91
|
+
if (r.pomPath) console.log(` pom: ${r.pomPath}`);
|
|
92
|
+
if (r.hadContribution) {
|
|
93
|
+
console.log(` dropped: ${r.droppedEntries} entries`);
|
|
94
|
+
} else {
|
|
95
|
+
console.log(` dropped: (nothing to purge)`);
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
console.log(` target: ext`);
|
|
99
|
+
console.log(` ext dir: ${r.extDir}`);
|
|
100
|
+
console.log(` ext dir: ${r.removedExtDir ? "removed" : "(absent)"}`);
|
|
101
|
+
}
|
|
102
|
+
console.log(
|
|
103
|
+
` host types: ${r.typesRemoved ? "removed" : "(absent)"} (${r.hostFederationDir})`
|
|
104
|
+
);
|
|
105
|
+
results.push({ id, ok: true, ...r });
|
|
106
|
+
} catch (err) {
|
|
107
|
+
console.error(` \x1b[31mfailed:\x1b[0m ${err.message}`);
|
|
108
|
+
results.push({ id, ok: false, error: err.message });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const ok = results.filter((r) => r.ok).length;
|
|
113
|
+
const failed = results.length - ok;
|
|
114
|
+
console.log(
|
|
115
|
+
`\nPurged ${ok} module(s)${failed ? `, ${failed} failed` : ""}.`
|
|
116
|
+
);
|
|
117
|
+
return { results };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
module.exports = { purgeRemotes, purgeOne };
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { resolveProjectPom, readArtifactId } = require("./pom");
|
|
4
|
+
const { resolveOne } = require("./jar-glob");
|
|
5
|
+
|
|
6
|
+
function readWsconfig(workspaceDir) {
|
|
7
|
+
const file = path.join(workspaceDir, "wsconfig.json");
|
|
8
|
+
if (!fs.existsSync(file)) {
|
|
9
|
+
throw new Error(
|
|
10
|
+
`No wsconfig.json in ${workspaceDir}. Run \`ws-wire-host <wpm-root>\` first.`
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
return JSON.parse(fs.readFileSync(file, "utf8"));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function readModulesJson(wpmRoot) {
|
|
17
|
+
const file = path.join(wpmRoot, "modules.json");
|
|
18
|
+
if (!fs.existsSync(file)) {
|
|
19
|
+
throw new Error(`No modules.json at ${wpmRoot}.`);
|
|
20
|
+
}
|
|
21
|
+
return JSON.parse(fs.readFileSync(file, "utf8"));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function readProjectPkg(workspaceDir, name) {
|
|
25
|
+
const pkgPath = path.join(workspaceDir, "projects", name, "package.json");
|
|
26
|
+
if (!fs.existsSync(pkgPath)) return {};
|
|
27
|
+
try {
|
|
28
|
+
return JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
29
|
+
} catch {
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Load the deployment context once and reuse across step runners (deploy,
|
|
35
|
+
// purge, ...). Returns { wsconfig, wpmRoot, modulesFolder, modulesDir,
|
|
36
|
+
// adminBuildFolder, adminDir }.
|
|
37
|
+
function loadDeployContext(workspaceDir) {
|
|
38
|
+
const wsconfig = readWsconfig(workspaceDir);
|
|
39
|
+
if (!wsconfig.wpmRoot) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
"wsconfig.json missing wpmRoot. Run `ws-wire-host <wpm-root>`."
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
const modulesJson = readModulesJson(wsconfig.wpmRoot);
|
|
45
|
+
const modulesFolder = modulesJson.modulesFolder || "./modules";
|
|
46
|
+
const adminBuildFolder = modulesJson.adminBuildFolder || "./admin";
|
|
47
|
+
const modulesDir = path.resolve(wsconfig.wpmRoot, modulesFolder);
|
|
48
|
+
const adminDir = path.resolve(wsconfig.wpmRoot, adminBuildFolder);
|
|
49
|
+
return {
|
|
50
|
+
wsconfig,
|
|
51
|
+
wpmRoot: wsconfig.wpmRoot,
|
|
52
|
+
modulesFolder,
|
|
53
|
+
adminBuildFolder,
|
|
54
|
+
modulesDir,
|
|
55
|
+
adminDir,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Decide jar vs ext for a project, honouring wsconfig override > package.json.
|
|
60
|
+
// Returns { kind: "jar", jarPath, pomPath?, artifactId? } or
|
|
61
|
+
// { kind: "ext", extDir }.
|
|
62
|
+
function resolveTarget({
|
|
63
|
+
workspaceDir,
|
|
64
|
+
projectName,
|
|
65
|
+
wsconfig,
|
|
66
|
+
wpmRoot,
|
|
67
|
+
modulesFolder,
|
|
68
|
+
}) {
|
|
69
|
+
const modulesDir = path.resolve(wpmRoot, modulesFolder);
|
|
70
|
+
const extDir = path.join(
|
|
71
|
+
wpmRoot,
|
|
72
|
+
"scripts",
|
|
73
|
+
"ext-admin-remotes",
|
|
74
|
+
projectName
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// 1. wsconfig override
|
|
78
|
+
const override =
|
|
79
|
+
wsconfig.deployOverrides && wsconfig.deployOverrides[projectName];
|
|
80
|
+
if (override) {
|
|
81
|
+
if (override.jar && override.ext) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`wsconfig.deployOverrides.${projectName}: set exactly one of 'jar' or 'ext', not both`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
if (override.ext === true) {
|
|
87
|
+
return { kind: "ext", extDir };
|
|
88
|
+
}
|
|
89
|
+
if (override.jar) {
|
|
90
|
+
const jarPath = resolveOne(modulesDir, override.jar, projectName);
|
|
91
|
+
return { kind: "jar", jarPath };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 2. project package.json
|
|
96
|
+
const pkg = readProjectPkg(workspaceDir, projectName);
|
|
97
|
+
const target = (pkg.wsmodules && pkg.wsmodules.target) || "jar";
|
|
98
|
+
if (target === "ext") {
|
|
99
|
+
return { kind: "ext", extDir };
|
|
100
|
+
}
|
|
101
|
+
if (target !== "jar") {
|
|
102
|
+
throw new Error(
|
|
103
|
+
`Invalid wsmodules.target for ${projectName}: ${JSON.stringify(target)} (expected 'jar' or 'ext')`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 3. pom-derived artifactId
|
|
108
|
+
const pomField = pkg.wsmodules && pkg.wsmodules.pom;
|
|
109
|
+
const pomPath = resolveProjectPom(workspaceDir, projectName, pomField);
|
|
110
|
+
const artifactId = readArtifactId(pomPath);
|
|
111
|
+
const jarPath = resolveOne(modulesDir, `${artifactId}-*.jar`, projectName);
|
|
112
|
+
return { kind: "jar", jarPath, pomPath, artifactId };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
module.exports = {
|
|
116
|
+
readWsconfig,
|
|
117
|
+
readModulesJson,
|
|
118
|
+
readProjectPkg,
|
|
119
|
+
loadDeployContext,
|
|
120
|
+
resolveTarget,
|
|
121
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ws-test-realm/admin-kit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Workflow CLI + scaffolding for Wiresphere admin-modules workspaces. Ships `ws-init-workspace` (init/merge into a project, stamps @wiresphere/shared's `getOverrides()` into the workspace's npm overrides block), `ws-modules` (build/pack/deploy driver), `ws-generate-module`/`ws-drop-module`, `ws-wire-host`, `ws-wire-pom`, `ws-sync-paths`, and `ws-pack-remote`. Depends on @wiresphere/devkit (toolchain BOM, peerDeps); pairs with @wiresphere/shared (runtime BOM + MF share map + overrides manifest). Requires npm 9+ for overrides + peerDep resolution to coexist cleanly.",
|
|
5
5
|
"license": "Artistic-2.0",
|
|
6
6
|
"publishConfig": {
|
package/template/package.json
CHANGED