added `devEngines` support breaks updating dependencies
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 52/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 静か
- 技術スタック
- nodejs, typescript
- 領域
- tooling
調査の方向性
sources/specUtils.ts から始め、特に parsePackageJSON と、parseSpec を呼び出す loadSpec に注目してください。devEngines.packageManager.version "^10" を使用する package.json で、報告された corepack npm install コマンドを再現し、その後、提案された処理のどれが意図されたものかを判断してください。依存関係の更新で有効な semver 範囲が拒否されなくなり、厳密な完全バージョンチェックが引き続きドキュメントどおりに動作すれば完了です。
索引モデルが issue の本文から書いたものです。
説明
The recent devEngines support seems to cause errors with dependabot (all updates broken), this is an example but there are more packages like this:
Error running package manager command: corepack npm install vite@7.0.5 --force --dry-run false --ignore-scripts --package-lock-only
Error: Invalid package manager specification in package.json (npm@^10); expected a semver version
NPM : Invalid package manager specification in package.json (npm@^10); expected a semver version
Context:
Within our project we have this in the package.json:
"engines": {
"node": "^20.11.0 || ^22 || ^24"
},
"devEngines": {
"packageManager": {
"name": "npm",
"version": "^10",
"onFail": "error"
},
"runtime": {
"name": "node",
"version": "^22",
"onFail": "error"
}
}
(We support a wide range of engines - but for development devs should only use Node 22 and NPM 10 to have consistent compiled assets (and test results)).
I guess this is caused here: https://github.com/nodejs/corepack/pull/643/files#r2234021913
I see two ways to fix corepack:
- Only enforce strict version if a full version was passed, see patch:
diff --git a/sources/specUtils.ts b/sources/specUtils.ts
index edd5c7e..82c1435 100644
--- a/sources/specUtils.ts
+++ b/sources/specUtils.ts
@@ -77,47 +77,51 @@ function warnOrThrow(errorMessage: string, onFail?: DevEngineDependency[`onFail`
console.warn(`! Corepack validation warning: ${errorMessage}`);
}
}
-function parsePackageJSON(packageJSONContent: CorepackPackageJSON) {
- const {packageManager: pm} = packageJSONContent;
- if (packageJSONContent.devEngines?.packageManager != null) {
- const {packageManager} = packageJSONContent.devEngines;
-
- if (typeof packageManager !== `object`) {
- console.warn(`! Corepack only supports objects as valid value for devEngines.packageManager. The current value (${JSON.stringify(packageManager)}) will be ignored.`);
- return pm;
+function parsePackageJSON({devEngines, packageManager}: CorepackPackageJSON) {
+ const spec = {
+ packageManager,
+ enforceExactVersion: true,
+ };
+
+ if (devEngines?.packageManager != null) {
+ const {packageManager: pm} = devEngines;
+
+ if (typeof pm !== `object`) {
+ console.warn(`! Corepack only supports objects as valid value for devEngines.packageManager. The current value (${JSON.stringify(pm)}) will be ignored.`);
+ return spec;
}
- if (Array.isArray(packageManager)) {
+ if (Array.isArray(pm)) {
console.warn(`! Corepack does not currently support array values for devEngines.packageManager`);
- return pm;
+ return spec;
}
- const {name, version, onFail} = packageManager;
+ const {name, version, onFail} = pm;
if (typeof name !== `string` || name.includes(`@`)) {
warnOrThrow(`The value of devEngines.packageManager.name ${JSON.stringify(name)} is not a supported string value`, onFail);
- return pm;
+ return spec;
}
if (version != null && (typeof version !== `string` || !semverValidRange(version))) {
warnOrThrow(`The value of devEngines.packageManager.version ${JSON.stringify(version)} is not a valid semver range`, onFail);
- return pm;
+ return spec;
}
debugUtils.log(`devEngines.packageManager defines that ${name}@${version} is the local package manager`);
- if (pm) {
- if (!pm.startsWith?.(`${name}@`))
- warnOrThrow(`"packageManager" field is set to ${JSON.stringify(pm)} which does not match the "devEngines.packageManager" field set to ${JSON.stringify(name)}`, onFail);
-
- else if (version != null && !semverSatisfies(pm.slice(packageManager.name.length + 1), version))
- warnOrThrow(`"packageManager" field is set to ${JSON.stringify(pm)} which does not match the value defined in "devEngines.packageManager" for ${JSON.stringify(name)} of ${JSON.stringify(version)}`, onFail);
-
- return pm;
+ if (packageManager) {
+ if (!packageManager.startsWith?.(`${name}@`))
+ warnOrThrow(`"packageManager" field is set to ${JSON.stringify(packageManager)} which does not match the "devEngines.packageManager" field set to ${JSON.stringify(name)}`, onFail);
+ else if (version != null && !semverSatisfies(packageManager.slice(pm.name.length + 1), version))
+ warnOrThrow(`"packageManager" field is set to ${JSON.stringify(packageManager)} which does not match the value defined in "devEngines.packageManager" for ${JSON.stringify(name)} of ${JSON.stringify(version)}`, onFail);
+ return spec;
}
-
- return `${name}@${version ?? `*`}`;
+ return {
+ enforceExactVersion: semverValid(version),
+ packageManager: `${name}@${version ?? `*`}`,
+ };
}
- return pm;
+ return spec;
}
export async function setLocalPackageManager(cwd: string, info: PreparedPackageManagerInfo) {
@@ -233,11 +237,11 @@ export async function loadSpec(initialCwd: string): Promise<LoadSpecResult> {
process.env = selection.localEnv;
}
- const rawPmSpec = parsePackageJSON(selection.data);
- if (typeof rawPmSpec === `undefined`)
+ const {enforceExactVersion, packageManager} = parsePackageJSON(selection.data);
+ if (typeof packageManager === `undefined`)
return {type: `NoSpec`, target: selection.manifestPath};
- debugUtils.log(`${selection.manifestPath} defines ${rawPmSpec} as local package manager`);
+ debugUtils.log(`${selection.manifestPath} defines ${packageManager} as local package manager`);
return {
type: `Found`,
@@ -249,6 +253,6 @@ export async function loadSpec(initialCwd: string): Promise<LoadSpecResult> {
onFail: selection.data.devEngines.packageManager.onFail,
},
// Lazy-loading it so we do not throw errors on commands that do not need valid spec.
- getSpec: () => parseSpec(rawPmSpec, path.relative(initialCwd, selection.manifestPath)),
+ getSpec: () => parseSpec(packageManager, path.relative(initialCwd, selection.manifestPath), {enforceExactVersion}),
};
}
- Ignore
devEnginesif it is a version range, see patch:
diff --git a/sources/specUtils.ts b/sources/specUtils.ts
index edd5c7e..183a62e 100644
--- a/sources/specUtils.ts
+++ b/sources/specUtils.ts
@@ -113,8 +113,9 @@ function parsePackageJSON(packageJSONContent: CorepackPackageJSON) {
return pm;
}
-
- return `${name}@${version ?? `*`}`;
+ if (semverValid(version)) {
+ return `${name}@${version ?? `*`}`;
+ }
}
return pm;
- 主要言語
- TypeScript
- スター
- 3.8k
- フォーク
- 279
- 平均マージ
- 1時間 47分
- マージ済み PR(30日)
- 2
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
nodejs/corepack のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 64/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
-
難易度 4/5 3〜5日 初心者へのやさしさ 68/100
-
難易度 3/5 1〜2日 初心者へのやさしさ 52/100
-
難易度 3/5 1〜2日 初心者へのやさしさ 68/100
nodejs/corepack の issue をすべて見る
似ている issue
-
VerificationGate: ATTRIBUTION quote guard never matches a normal quotation (\b around the quote) オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
danielmiessler/LifeOS#2234 ·
-
T: Bug
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
-
難易度 1/5 1時間未満 初心者へのやさしさ 85/100
-
Mend: dependency security vulnerability untriaged
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100