mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(ci): merge nested shrinkwrap override pins
This commit is contained in:
@@ -305,11 +305,60 @@ function mergeOverrideEntry(merged, name, spec) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (
|
||||
typeof current === "string" &&
|
||||
isPlainObject(spec) &&
|
||||
typeof spec["."] === "string" &&
|
||||
exactOverrideVersionsMatch(current, spec["."])
|
||||
) {
|
||||
merged[name] = { ".": preferredExactOverrideRootSpec(current, spec["."]) };
|
||||
for (const [nestedName, nestedSpec] of Object.entries(spec)) {
|
||||
if (nestedName === ".") {
|
||||
continue;
|
||||
}
|
||||
mergeOverrideEntry(merged[name], nestedName, nestedSpec);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (
|
||||
isPlainObject(current) &&
|
||||
typeof spec === "string" &&
|
||||
typeof current["."] === "string" &&
|
||||
exactOverrideVersionsMatch(current["."], spec)
|
||||
) {
|
||||
current["."] = preferredExactOverrideRootSpec(current["."], spec);
|
||||
return;
|
||||
}
|
||||
if (JSON.stringify(current) !== JSON.stringify(spec)) {
|
||||
throw new Error(`package.json overrides.${name} conflicts with pnpm lock policy for ${name}`);
|
||||
}
|
||||
}
|
||||
|
||||
function preferredExactOverrideRootSpec(current, incoming) {
|
||||
return incoming.startsWith("npm:") ? incoming : current;
|
||||
}
|
||||
|
||||
function exactOverrideVersionsMatch(left, right) {
|
||||
const leftVersion = exactVersionFromOverrideSpec(left);
|
||||
if (leftVersion === null || leftVersion !== exactVersionFromOverrideSpec(right)) {
|
||||
return false;
|
||||
}
|
||||
const leftAlias = parseNpmAliasOverrideSpec(left);
|
||||
const rightAlias = parseNpmAliasOverrideSpec(right);
|
||||
return !leftAlias || !rightAlias || leftAlias.name === rightAlias.name;
|
||||
}
|
||||
|
||||
function parseNpmAliasOverrideSpec(spec) {
|
||||
if (!spec.startsWith("npm:")) {
|
||||
return null;
|
||||
}
|
||||
const versionIndex = spec.lastIndexOf("@");
|
||||
if (versionIndex <= "npm:".length) {
|
||||
return null;
|
||||
}
|
||||
return { name: spec.slice("npm:".length, versionIndex) };
|
||||
}
|
||||
|
||||
function mergeOverrides(packageOverrides, workspaceOverrides, pnpmLockOverrides) {
|
||||
const merged = normalizeOverrides(packageOverrides);
|
||||
for (const [name, spec] of [
|
||||
@@ -1085,6 +1134,7 @@ export {
|
||||
disableShrinkwrappedOverrideConflictSources,
|
||||
exactOverrideRulesFromOverrides,
|
||||
exactVersionFromOverrideSpec,
|
||||
mergeOverrides,
|
||||
applyPackageExtensionPeerMetadata,
|
||||
normalizeNpmVersionDrift,
|
||||
packageJsonForShrinkwrap,
|
||||
|
||||
@@ -4,6 +4,7 @@ import { parse } from "yaml";
|
||||
import {
|
||||
collectCurrentShrinkwrapOverrides,
|
||||
collectPnpmLockViolations,
|
||||
mergeOverrides,
|
||||
parsePnpmPackageKey,
|
||||
readShrinkwrapOverrides,
|
||||
} from "../scripts/generate-npm-shrinkwrap.mjs";
|
||||
@@ -132,6 +133,82 @@ describe("package manager build policy", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("merges exact current shrinkwrap pins with nested lock-derived pins", () => {
|
||||
expect(
|
||||
mergeOverrides(
|
||||
{ "@mistralai/mistralai": "2.2.1" },
|
||||
{ "@mistralai/mistralai": { ".": "2.2.1", zod: "4.4.3" } },
|
||||
{},
|
||||
),
|
||||
).toEqual({
|
||||
"@mistralai/mistralai": { ".": "2.2.1", zod: "4.4.3" },
|
||||
});
|
||||
});
|
||||
|
||||
it("preserves npm alias pins when merging nested lock-derived pins", () => {
|
||||
expect(
|
||||
mergeOverrides(
|
||||
{ "node-domexception": "npm:@nolyfill/domexception@1.0.28" },
|
||||
{ "node-domexception": { ".": "1.0.28", child: "2.0.0" } },
|
||||
{},
|
||||
),
|
||||
).toEqual({
|
||||
"node-domexception": {
|
||||
".": "npm:@nolyfill/domexception@1.0.28",
|
||||
child: "2.0.0",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("preserves later npm alias pins when nested pins are already merged", () => {
|
||||
expect(
|
||||
mergeOverrides(
|
||||
{ "node-domexception": { ".": "1.0.28", child: "2.0.0" } },
|
||||
{ "node-domexception": "npm:@nolyfill/domexception@1.0.28" },
|
||||
{},
|
||||
),
|
||||
).toEqual({
|
||||
"node-domexception": {
|
||||
".": "npm:@nolyfill/domexception@1.0.28",
|
||||
child: "2.0.0",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("rejects non-exact root pins when merging nested pins", () => {
|
||||
expect(() =>
|
||||
mergeOverrides(
|
||||
{ "floating-package": "^1.0.0" },
|
||||
{ "floating-package": { ".": "~1.0.0", child: "2.0.0" } },
|
||||
{},
|
||||
),
|
||||
).toThrow(/conflicts with pnpm lock policy/u);
|
||||
expect(() =>
|
||||
mergeOverrides(
|
||||
{ "floating-package": { ".": "^1.0.0", child: "2.0.0" } },
|
||||
{ "floating-package": "~1.0.0" },
|
||||
{},
|
||||
),
|
||||
).toThrow(/conflicts with pnpm lock policy/u);
|
||||
});
|
||||
|
||||
it("rejects distinct npm alias targets with matching versions", () => {
|
||||
expect(() =>
|
||||
mergeOverrides(
|
||||
{ "aliased-package": "npm:@safe/foo@1.0.0" },
|
||||
{ "aliased-package": { ".": "npm:@other/foo@1.0.0", child: "2.0.0" } },
|
||||
{},
|
||||
),
|
||||
).toThrow(/conflicts with pnpm lock policy/u);
|
||||
expect(() =>
|
||||
mergeOverrides(
|
||||
{ "aliased-package": { ".": "npm:@safe/foo@1.0.0", child: "2.0.0" } },
|
||||
{ "aliased-package": "npm:@other/foo@1.0.0" },
|
||||
{},
|
||||
),
|
||||
).toThrow(/conflicts with pnpm lock policy/u);
|
||||
});
|
||||
|
||||
it("keeps npm shrinkwrap package versions inside the pnpm lock graph", () => {
|
||||
const pnpmLockPackages = collectPnpmLockPackages();
|
||||
const shrinkwrapPaths = [
|
||||
|
||||
Reference in New Issue
Block a user