enablement-build-monorepo-version 8.4.9 → 8.4.10
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 +1 -1
- package/package.json +2 -2
- package/src/index.mjs +20 -15
- package/src/lib.mjs +0 -1
- package/tests/index.test.mjs +59 -0
- package/tests/lib.test.mjs +4 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ npx enablement-build-monorepo-version@latest [flags]
|
|
|
14
14
|
|
|
15
15
|
1. **Hash** — Each subfolder under the configured `children` directories is hashed (source files only; `node_modules`, `dist`, etc. are excluded).
|
|
16
16
|
2. **Compare** — Hashes are diffed against state in `--hashFile`, which defaults to `{configDir}/hash.json`.
|
|
17
|
-
3. **Propagate** —
|
|
17
|
+
3. **Propagate** — After all workspace folders have been scanned, any package whose hash changed is marked `CHANGED`. All transitive dependents, including those in other workspace folders, are also marked `CHANGED` via a breadth-first traversal. The graph comes from `{configDir}/manifest.json` `dependents` (or inverted `dependencies` for manifests without `dependents`), or from the Nx graph supplied explicitly with `--dependencies`.
|
|
18
18
|
4. **Version** — The next semver is determined from the current version found in each package's version manifest (`package.json`, `version.json`, or `pyproject.toml`) using conventional-commit rules.
|
|
19
19
|
5. **Output** — Azure DevOps `##vso[task.setvariable]` lines are written to stdout for consumption by downstream pipeline steps.
|
|
20
20
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "enablement-build-monorepo-version",
|
|
3
|
-
"version": "8.4.
|
|
3
|
+
"version": "8.4.10",
|
|
4
4
|
"description": "This detects changes in the children packages of a monorepo.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./src/index.mjs",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"minimatch": "~10.1.1",
|
|
18
|
-
"enablement-build-manifest": "1.8.
|
|
18
|
+
"enablement-build-manifest": "1.8.10"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"jest": "^30.4.2"
|
package/src/index.mjs
CHANGED
|
@@ -9,7 +9,7 @@ const packageMetadata = JSON.parse(
|
|
|
9
9
|
);
|
|
10
10
|
const packageVersion = packageMetadata.version;
|
|
11
11
|
|
|
12
|
-
import { dependencyMap, compare, getCurrentVersion, updateVersion, retagToPackageNames, detectOldFormatTags, resolveWorkspaceChildren, excludeChildren, applyInitScripts, RELEASE_SCRIPTS, emitVariable, hashElement, resolveHashFilePath, ensureHashFileExists, loadHashFile, writeHashFile } from "./lib.mjs";
|
|
12
|
+
import { dependencyMap, parseDependencyMap, compare, getCurrentVersion, updateVersion, retagToPackageNames, detectOldFormatTags, resolveWorkspaceChildren, excludeChildren, applyInitScripts, RELEASE_SCRIPTS, emitVariable, hashElement, resolveHashFilePath, ensureHashFileExists, loadHashFile, writeHashFile } from "./lib.mjs";
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
function bumpPatchVersion(version, forcedSuffix) {
|
|
@@ -162,7 +162,11 @@ async function main(options) {
|
|
|
162
162
|
if (shouldPreferManifestDependencies) {
|
|
163
163
|
const manifestText = readFileSync(manifestDependencyPath, 'utf8');
|
|
164
164
|
const manifest = JSON.parse(manifestText || '{}');
|
|
165
|
-
dependencies = manifest.
|
|
165
|
+
dependencies = manifest.dependents ?? parseDependencyMap(
|
|
166
|
+
Object.fromEntries(Object.entries(manifest.dependencies || {}).map(
|
|
167
|
+
([name, targets]) => [name, targets.map(target => ({ target }))],
|
|
168
|
+
)),
|
|
169
|
+
);
|
|
166
170
|
if (options.debug) console.log(`Loaded dependencies from ${manifestDependencyPath}\n`, JSON.stringify(dependencies));
|
|
167
171
|
} else if (options.dependencies) {
|
|
168
172
|
if (existsSync(options.dependencies)) {
|
|
@@ -211,6 +215,14 @@ async function main(options) {
|
|
|
211
215
|
|
|
212
216
|
await collectPackageEntries(options.prefixPath, packageFolder, packageFolder, hashOptions, current, new Set());
|
|
213
217
|
|
|
218
|
+
resolve("OK");
|
|
219
|
+
}).catch(reject);
|
|
220
|
+
}));
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
Promise.all(scanlist).then(async () => {
|
|
224
|
+
const pendingOperations = [];
|
|
225
|
+
for (const packageFolder of children.split(',')) {
|
|
214
226
|
if (options.changed || options.version || options.tag) {
|
|
215
227
|
let results = await compare(packageFolder, previous, current, dependencies, options);
|
|
216
228
|
if (options.debug) console.log("COMPARE", JSON.stringify(results));
|
|
@@ -231,14 +243,14 @@ async function main(options) {
|
|
|
231
243
|
if (results[i].value.changed) {
|
|
232
244
|
emitVariable(safeName, results[i].value.version, options.platform);
|
|
233
245
|
if (options.saveVersion) {
|
|
234
|
-
|
|
246
|
+
pendingOperations.push(updateVersion(packageFolder, results[i].value.name, results[i].value.version, options));
|
|
235
247
|
}
|
|
236
248
|
} else {
|
|
237
249
|
emitVariable(safeName, results[i].value.previous, options.platform);
|
|
238
250
|
}
|
|
239
251
|
}
|
|
240
252
|
if (options.tag) {
|
|
241
|
-
|
|
253
|
+
pendingOperations.push(new Promise((resolve, reject) => {
|
|
242
254
|
let v = results[i].value.version;
|
|
243
255
|
if (!v) v = getCurrentVersion(options.prefixPath, packageFolder, results[i].value.name)?.version;
|
|
244
256
|
const shortName = (results[i].value.fullName || results[i].value.name).replace(/^@[^/]+\//, '');
|
|
@@ -257,22 +269,15 @@ async function main(options) {
|
|
|
257
269
|
});
|
|
258
270
|
return;
|
|
259
271
|
}
|
|
272
|
+
resolve(rev);
|
|
260
273
|
});
|
|
261
274
|
}));
|
|
262
275
|
}
|
|
263
276
|
}
|
|
264
277
|
}
|
|
265
278
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
.catch(error => {
|
|
269
|
-
console.error('hashing failed:', error);
|
|
270
|
-
resolve("OK");
|
|
271
|
-
});
|
|
272
|
-
}));
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
Promise.all(scanlist).then(async () => {
|
|
279
|
+
}
|
|
280
|
+
await Promise.all(pendingOperations);
|
|
276
281
|
await updateRootVersionIfNeeded(options, changeList);
|
|
277
282
|
|
|
278
283
|
if (options.changed) {
|
|
@@ -339,7 +344,7 @@ async function main(options) {
|
|
|
339
344
|
} else {
|
|
340
345
|
finish();
|
|
341
346
|
}
|
|
342
|
-
}
|
|
347
|
+
}).catch(mainreject);
|
|
343
348
|
});
|
|
344
349
|
}
|
|
345
350
|
|
package/src/lib.mjs
CHANGED
|
@@ -317,7 +317,6 @@ export async function compare(
|
|
|
317
317
|
// Collect directly-changed/new packages
|
|
318
318
|
const changedNames = new Set();
|
|
319
319
|
packages.forEach((name) => {
|
|
320
|
-
if (current[name].packageFolder !== packageFolder) return;
|
|
321
320
|
if (
|
|
322
321
|
previous[current[name].fullName] === undefined ||
|
|
323
322
|
current[name].hash !== previous[current[name].fullName].hash
|
package/tests/index.test.mjs
CHANGED
|
@@ -120,6 +120,65 @@ describe("index CLI hash loading", () => {
|
|
|
120
120
|
});
|
|
121
121
|
});
|
|
122
122
|
|
|
123
|
+
describe("index CLI cross-folder propagation", () => {
|
|
124
|
+
it.each(["dependents", "dependencies", "nx"])(
|
|
125
|
+
"includes unchanged consumers across folders using %s",
|
|
126
|
+
graphSource => {
|
|
127
|
+
const root = setupWorkspace();
|
|
128
|
+
try {
|
|
129
|
+
const packages = [
|
|
130
|
+
["ux/apps", "admin-ux", "@icg/x-saas-ux"],
|
|
131
|
+
["ux/packages", "saas-package", "@lit/lit-saas-package"],
|
|
132
|
+
["ux/saas", "manage-role", "@lit/lit-saas-manage-role"],
|
|
133
|
+
["ux/apps", "unrelated", "@scope/unrelated"],
|
|
134
|
+
];
|
|
135
|
+
for (const [folder, name, fullName] of packages) {
|
|
136
|
+
const directory = path.join(root, folder, name);
|
|
137
|
+
mkdirSync(directory, { recursive: true });
|
|
138
|
+
writeFileSync(path.join(directory, "package.json"), JSON.stringify({ name: fullName, version: "1.0.0" }));
|
|
139
|
+
writeFileSync(path.join(directory, "index.js"), "export default 1;\n");
|
|
140
|
+
}
|
|
141
|
+
const dependencies = {
|
|
142
|
+
"@icg/x-saas-ux": ["@lit/lit-saas-package"],
|
|
143
|
+
"@lit/lit-saas-package": ["@lit/lit-saas-manage-role"],
|
|
144
|
+
"@lit/lit-saas-manage-role": [],
|
|
145
|
+
};
|
|
146
|
+
const dependents = {
|
|
147
|
+
"@lit/lit-saas-manage-role": ["@lit/lit-saas-package"],
|
|
148
|
+
"@lit/lit-saas-package": ["@icg/x-saas-ux"],
|
|
149
|
+
};
|
|
150
|
+
writeFileSync(path.join(root, ".cicd/manifest.json"), JSON.stringify(
|
|
151
|
+
graphSource === "dependents" ? { dependencies, dependents } :
|
|
152
|
+
graphSource === "dependencies" ? { dependencies } : { dependencies: {} },
|
|
153
|
+
));
|
|
154
|
+
const graphPath = path.join(root, "dependencies.json");
|
|
155
|
+
writeFileSync(graphPath, JSON.stringify({ graph: {
|
|
156
|
+
dependencies: Object.fromEntries(Object.entries(dependencies).map(
|
|
157
|
+
([name, targets]) => [name, targets.map(target => ({ target }))],
|
|
158
|
+
)),
|
|
159
|
+
} }));
|
|
160
|
+
const run = (folders, saveHash = false) => execFileSync("node", [
|
|
161
|
+
cliPath, "--changed", "--children", folders, "--prefixPath", root,
|
|
162
|
+
...(saveHash ? ["--hash"] : []),
|
|
163
|
+
...(graphSource === "nx" ? ["--dependencies", graphPath] : []),
|
|
164
|
+
], { cwd: repoRoot, encoding: "utf8" });
|
|
165
|
+
run("ux/apps,ux/packages,ux/saas", true);
|
|
166
|
+
writeFileSync(path.join(root, "ux/saas/manage-role/index.js"), "export default 2;\n");
|
|
167
|
+
for (const folders of ["ux/apps,ux/packages,ux/saas", "ux/saas,ux/packages,ux/apps"]) {
|
|
168
|
+
const stdout = run(folders);
|
|
169
|
+
const changed = JSON.parse(stdout.match(/CHANGED - (\[[^\n]*\])/)[1]);
|
|
170
|
+
expect(changed.sort()).toEqual(["admin-ux", "manage-role", "saas-package"]);
|
|
171
|
+
expect(stdout).toContain("variable=ux_apps;");
|
|
172
|
+
expect(stdout).toContain("variable=ux_packages;");
|
|
173
|
+
expect(stdout).toContain("variable=ux_saas;");
|
|
174
|
+
}
|
|
175
|
+
} finally {
|
|
176
|
+
rmSync(root, { recursive: true, force: true });
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
);
|
|
180
|
+
});
|
|
181
|
+
|
|
123
182
|
describe("index CLI --exclude", () => {
|
|
124
183
|
function setupWorkspaceWithTwoRoots() {
|
|
125
184
|
const root = mkdtempSync(path.join(os.tmpdir(), "monorepo-version-"));
|
package/tests/lib.test.mjs
CHANGED
|
@@ -256,7 +256,7 @@ describe("compare", () => {
|
|
|
256
256
|
expect(results[0].value.name).toBe("comp-a");
|
|
257
257
|
});
|
|
258
258
|
|
|
259
|
-
it("
|
|
259
|
+
it("propagates cross-folder changes while emitting only the requested folder", async () => {
|
|
260
260
|
// leaf is in 'components', parent is in 'saas'
|
|
261
261
|
// when comparing 'components', only comp packages appear in output
|
|
262
262
|
const current = {
|
|
@@ -274,6 +274,9 @@ describe("compare", () => {
|
|
|
274
274
|
);
|
|
275
275
|
expect(results).toHaveLength(1);
|
|
276
276
|
expect(results[0].value.name).toBe("leaf");
|
|
277
|
+
const parentResults = await compare("saas", previous, current, deps, opts);
|
|
278
|
+
expect(parentResults).toHaveLength(1);
|
|
279
|
+
expect(parentResults[0].value).toMatchObject({ name: "parent", changed: true });
|
|
277
280
|
});
|
|
278
281
|
});
|
|
279
282
|
|