enablement-build-monorepo-version 6.0.0 → 8.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/index.mjs +37 -22
- package/src/lib.mjs +6 -5
- package/tests/index.test.mjs +49 -7
- package/tests/lib.test.mjs +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "enablement-build-monorepo-version",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.2.0",
|
|
4
4
|
"description": "This detects changes in the children packages of a monorepo.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./src/index.mjs",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
]
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"enablement-build-manifest": "1.
|
|
17
|
+
"enablement-build-manifest": "1.7.0"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"jest": "^30.4.2"
|
package/src/index.mjs
CHANGED
|
@@ -44,6 +44,35 @@ async function updateRootVersionIfNeeded(options, changeList) {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
|
|
47
|
+
|
|
48
|
+
async function collectPackageEntries(prefixPath, scanFolder, packageFolder, hashOptions, current, seenDirs = new Set()) {
|
|
49
|
+
const dirPath = path.join(prefixPath, scanFolder);
|
|
50
|
+
const dirKey = path.resolve(dirPath);
|
|
51
|
+
if (!existsSync(dirPath) || !lstatSync(dirPath).isDirectory()) return;
|
|
52
|
+
if (seenDirs.has(dirKey)) return;
|
|
53
|
+
seenDirs.add(dirKey);
|
|
54
|
+
|
|
55
|
+
const hash = await hashElement(dirPath, hashOptions);
|
|
56
|
+
const children = hash.children || [];
|
|
57
|
+
|
|
58
|
+
for (let i = 0; i < children.length; i++) {
|
|
59
|
+
const child = children[i];
|
|
60
|
+
const name = child.name;
|
|
61
|
+
if (name.substring(0, 1) === "_" || name === "version") continue;
|
|
62
|
+
|
|
63
|
+
const childPath = path.join(dirPath, name);
|
|
64
|
+
if (!existsSync(childPath) || lstatSync(childPath).isFile()) continue;
|
|
65
|
+
|
|
66
|
+
const versionInfo = getCurrentVersion(prefixPath, scanFolder, name);
|
|
67
|
+
if (versionInfo.fullName) {
|
|
68
|
+
current[name] = { hash: child.hash, ...versionInfo, packageFolder };
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
await collectPackageEntries(prefixPath, path.join(scanFolder, name), packageFolder, hashOptions, current, seenDirs);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
47
76
|
async function main(options) {
|
|
48
77
|
return new Promise((mainResolve, mainreject) => {
|
|
49
78
|
const hashOptions = { encoding: 'hex', folders: { exclude: options.hashExcludeFolders }, files: { exclude: options.hashExcludeFiles } };
|
|
@@ -101,7 +130,7 @@ async function main(options) {
|
|
|
101
130
|
}
|
|
102
131
|
}
|
|
103
132
|
|
|
104
|
-
// Load previous hashes, keyed by
|
|
133
|
+
// Load previous hashes, keyed by full package name.
|
|
105
134
|
previous = loadHashFile(changeConfig);
|
|
106
135
|
if (options.debug) console.log("PREVIOUS", JSON.stringify(previous));
|
|
107
136
|
|
|
@@ -131,16 +160,7 @@ async function main(options) {
|
|
|
131
160
|
const children = hash.children;
|
|
132
161
|
if (options.debug) console.log("HASH", JSON.stringify(children));
|
|
133
162
|
|
|
134
|
-
|
|
135
|
-
let name = children[i].name;
|
|
136
|
-
if (name.substring(0, 1) === "_" || name === "version") continue;
|
|
137
|
-
if (lstatSync(path.join(options.prefixPath, packageFolder, name)).isFile()) continue;
|
|
138
|
-
if (!existsSync(path.join(options.prefixPath, packageFolder, name))) continue;
|
|
139
|
-
|
|
140
|
-
delete children[i].children;
|
|
141
|
-
let v = getCurrentVersion(options.prefixPath, packageFolder, name);
|
|
142
|
-
current[name] = { hash: children[i].hash, ...v };
|
|
143
|
-
}
|
|
163
|
+
await collectPackageEntries(options.prefixPath, packageFolder, packageFolder, hashOptions, current, new Set());
|
|
144
164
|
|
|
145
165
|
if (options.changed || options.version || options.tag) {
|
|
146
166
|
let results = await compare(packageFolder, previous, current, dependencies, options);
|
|
@@ -194,16 +214,6 @@ async function main(options) {
|
|
|
194
214
|
}
|
|
195
215
|
}
|
|
196
216
|
|
|
197
|
-
// save current hashes
|
|
198
|
-
if (options.hash) {
|
|
199
|
-
let names = Object.keys(current);
|
|
200
|
-
for (let i = 0; i < names.length; i++) {
|
|
201
|
-
if (current[names[i]].packageFolder !== packageFolder) continue;
|
|
202
|
-
let v = getCurrentVersion(options.prefixPath, packageFolder, names[i]);
|
|
203
|
-
current[names[i]].version = v.version;
|
|
204
|
-
current[names[i]].fullName = v.fullName;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
217
|
resolve("OK");
|
|
208
218
|
})
|
|
209
219
|
.catch(error => {
|
|
@@ -233,7 +243,12 @@ async function main(options) {
|
|
|
233
243
|
if (options.try) {
|
|
234
244
|
console.log('\x1b[36m%s\x1b[0m', `[try] Would write updated hashes to ${changeConfig}`);
|
|
235
245
|
} else {
|
|
236
|
-
|
|
246
|
+
const hashesByFullName = Object.fromEntries(
|
|
247
|
+
Object.entries(current)
|
|
248
|
+
.filter(([, entry]) => entry && entry.fullName)
|
|
249
|
+
.map(([, entry]) => [entry.fullName, entry])
|
|
250
|
+
);
|
|
251
|
+
writeHashFile(changeConfig, hashesByFullName, { usesManifestHashFile });
|
|
237
252
|
console.log('folder hashes written successfully');
|
|
238
253
|
}
|
|
239
254
|
}
|
package/src/lib.mjs
CHANGED
|
@@ -319,8 +319,8 @@ export async function compare(
|
|
|
319
319
|
packages.forEach((name) => {
|
|
320
320
|
if (current[name].packageFolder !== packageFolder) return;
|
|
321
321
|
if (
|
|
322
|
-
previous[name] === undefined ||
|
|
323
|
-
current[name].hash !== previous[name].hash
|
|
322
|
+
previous[current[name].fullName] === undefined ||
|
|
323
|
+
current[name].hash !== previous[current[name].fullName].hash
|
|
324
324
|
)
|
|
325
325
|
changedNames.add(name);
|
|
326
326
|
});
|
|
@@ -342,8 +342,9 @@ export async function compare(
|
|
|
342
342
|
// Emit one result per package — no duplicates
|
|
343
343
|
packages.forEach((name) => {
|
|
344
344
|
if (current[name].packageFolder !== packageFolder) return;
|
|
345
|
-
const
|
|
346
|
-
const
|
|
345
|
+
const previousPackage = previous[current[name].fullName];
|
|
346
|
+
const isNew = previousPackage === undefined;
|
|
347
|
+
const isDirect = !isNew && current[name].hash !== previousPackage.hash;
|
|
347
348
|
const status = isNew
|
|
348
349
|
? "NEW"
|
|
349
350
|
: changedNames.has(name)
|
|
@@ -363,7 +364,7 @@ export async function compare(
|
|
|
363
364
|
current[name].version,
|
|
364
365
|
status,
|
|
365
366
|
options,
|
|
366
|
-
|
|
367
|
+
previousPackage?.hash,
|
|
367
368
|
current[name].hash,
|
|
368
369
|
parent,
|
|
369
370
|
current[name].fullName,
|
package/tests/index.test.mjs
CHANGED
|
@@ -94,8 +94,8 @@ describe("index CLI hash loading", () => {
|
|
|
94
94
|
|
|
95
95
|
const hashJson = JSON.parse(readFileSync(path.join(root, ".cicd", "hash.json"), "utf8"));
|
|
96
96
|
expect(hashJson.version).toBe(2);
|
|
97
|
-
expect(typeof hashJson.hash
|
|
98
|
-
expect(hashJson.hash
|
|
97
|
+
expect(typeof hashJson.hash["@scope/example"]).toBe("string");
|
|
98
|
+
expect(hashJson.hash["@scope/example"]).toBeTruthy();
|
|
99
99
|
} finally {
|
|
100
100
|
rmSync(root, { recursive: true, force: true });
|
|
101
101
|
}
|
|
@@ -112,8 +112,8 @@ describe("index CLI hash loading", () => {
|
|
|
112
112
|
|
|
113
113
|
const hashJson = JSON.parse(readFileSync(path.join(root, ".cicd", "hash.json"), "utf8"));
|
|
114
114
|
expect(hashJson.version).toBe(2);
|
|
115
|
-
expect(typeof hashJson.hash
|
|
116
|
-
expect(hashJson.hash
|
|
115
|
+
expect(typeof hashJson.hash["@scope/example"]).toBe("string");
|
|
116
|
+
expect(hashJson.hash["@scope/example"]).toBeTruthy();
|
|
117
117
|
} finally {
|
|
118
118
|
rmSync(root, { recursive: true, force: true });
|
|
119
119
|
}
|
|
@@ -164,8 +164,8 @@ describe("index CLI --exclude", () => {
|
|
|
164
164
|
expect(changed).not.toContain("skip-me");
|
|
165
165
|
|
|
166
166
|
const hashJson = JSON.parse(readFileSync(path.join(root, ".cicd", "hash.json"), "utf8"));
|
|
167
|
-
expect(hashJson.hash
|
|
168
|
-
expect(hashJson.hash["skip-me"]).toBeUndefined();
|
|
167
|
+
expect(hashJson.hash["@scope/example"]).toBeTruthy();
|
|
168
|
+
expect(hashJson.hash["@scope/skip-me"]).toBeUndefined();
|
|
169
169
|
} finally {
|
|
170
170
|
rmSync(root, { recursive: true, force: true });
|
|
171
171
|
}
|
|
@@ -198,7 +198,49 @@ describe("index CLI --children defaulting", () => {
|
|
|
198
198
|
expect(JSON.parse(changedMatch[1])).toContain("example");
|
|
199
199
|
|
|
200
200
|
const hashJson = JSON.parse(readFileSync(path.join(root, ".cicd", "hash.json"), "utf8"));
|
|
201
|
-
expect(hashJson.hash
|
|
201
|
+
expect(hashJson.hash["@scope/example"]).toBeTruthy();
|
|
202
|
+
} finally {
|
|
203
|
+
rmSync(root, { recursive: true, force: true });
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
describe("index CLI nested workspace roots", () => {
|
|
209
|
+
it("skips non-package folders and discovers nested package roots under a child directory", () => {
|
|
210
|
+
const root = mkdtempSync(path.join(os.tmpdir(), "monorepo-version-"));
|
|
211
|
+
try {
|
|
212
|
+
mkdirSync(path.join(root, "ux", "portal", "profile"), { recursive: true });
|
|
213
|
+
mkdirSync(path.join(root, ".cicd"), { recursive: true });
|
|
214
|
+
|
|
215
|
+
writeFileSync(
|
|
216
|
+
path.join(root, "package.json"),
|
|
217
|
+
JSON.stringify(
|
|
218
|
+
{ name: "tmp-monorepo", private: true, workspaces: ["ux/*"] },
|
|
219
|
+
null,
|
|
220
|
+
2,
|
|
221
|
+
) + "\n",
|
|
222
|
+
"utf8",
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
writeFileSync(
|
|
226
|
+
path.join(root, "ux", "portal", "profile", "package.json"),
|
|
227
|
+
JSON.stringify({ name: "@scope/profile", version: "1.0.0" }, null, 2) + "\n",
|
|
228
|
+
"utf8",
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
const stdout = execFileSync(
|
|
232
|
+
"node",
|
|
233
|
+
[cliPath, "--hash", "--changed", "--children", "ux", "--prefixPath", root],
|
|
234
|
+
{ cwd: repoRoot, encoding: "utf8" },
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
const changedMatch = stdout.match(/CHANGED - (\[[^\n]*\])/);
|
|
238
|
+
expect(changedMatch).not.toBeNull();
|
|
239
|
+
expect(JSON.parse(changedMatch[1])).toContain("profile");
|
|
240
|
+
|
|
241
|
+
const hashJson = JSON.parse(readFileSync(path.join(root, ".cicd", "hash.json"), "utf8"));
|
|
242
|
+
expect(hashJson.hash["@scope/profile"]).toBeTruthy();
|
|
243
|
+
expect(hashJson.hash.undefined).toBeUndefined();
|
|
202
244
|
} finally {
|
|
203
245
|
rmSync(root, { recursive: true, force: true });
|
|
204
246
|
}
|
package/tests/lib.test.mjs
CHANGED
|
@@ -83,7 +83,7 @@ describe("compare", () => {
|
|
|
83
83
|
[name]: { hash, version: "1.0.0", fullName, packageFolder: folder },
|
|
84
84
|
});
|
|
85
85
|
|
|
86
|
-
const prev = (name, hash) => ({ [
|
|
86
|
+
const prev = (name, hash, fullName = "@s/" + name) => ({ [fullName]: { hash } });
|
|
87
87
|
|
|
88
88
|
describe("status classification", () => {
|
|
89
89
|
it("marks all packages UNCHANGED when hashes match", async () => {
|