mirror of https://github.com/nodejs/corepack.git
Compare commits
57 Commits
Author | SHA1 | Date |
---|---|---|
|
15498ddb9a | |
|
9a1794a59f | |
|
783a42fbe3 | |
|
98fd966176 | |
|
5fc3691354 | |
|
b45b3a3244 | |
|
77fff3c1f3 | |
|
273237a110 | |
|
2b43f26135 | |
|
aefde28a63 | |
|
0b94797f96 | |
|
679bcefda5 | |
|
633764f7c4 | |
|
19e3c6861a | |
|
b83bb5ec15 | |
|
7deb39ead0 | |
|
9b95b46f05 | |
|
b456268851 | |
|
53b1fe75c4 | |
|
4be72f6941 | |
|
bb16184b7b | |
|
b0608d1a60 | |
|
351d86c202 | |
|
48ce89827c | |
|
da96687e69 | |
|
f8de7214e5 | |
|
7f7336b9bd | |
|
d26a552daa | |
|
7b193d8498 | |
|
91ea527475 | |
|
c388c64805 | |
|
12e77e5069 | |
|
b0c46078f1 | |
|
bae0839794 | |
|
d5e938795b | |
|
9317593dda | |
|
8163608e49 | |
|
721eeec8c3 | |
|
a7cb9f603c | |
|
c11891152c | |
|
ab38255f24 | |
|
34abfcaee8 | |
|
72a588c237 | |
|
8c90caab7f | |
|
9dfbe18003 | |
|
2a04e7c8da | |
|
8bebc0c0a5 | |
|
c7a9bde16d | |
|
0ae3c3c1f5 | |
|
afd939011f | |
|
256cf8aaa4 | |
|
1bb0fb5d67 | |
|
a286c8f553 | |
|
cba690575b | |
|
72ed05b775 | |
|
98d0e43cbc | |
|
d732259faf |
|
@ -39,22 +39,28 @@ jobs:
|
|||
run: corepack yarn typecheck
|
||||
|
||||
- name: "Check for linting errors"
|
||||
run: corepack yarn lint
|
||||
run: corepack yarn lint --max-warnings=0
|
||||
|
||||
build-and-test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node:
|
||||
- 18
|
||||
- 20
|
||||
- 21
|
||||
- 22
|
||||
- 24
|
||||
platform:
|
||||
- ubuntu-latest
|
||||
- macos-latest
|
||||
- windows-latest
|
||||
|
||||
# Temporarily skipping Node.js 24 under Windows due to issue
|
||||
# https://github.com/nodejs/corepack/issues/715
|
||||
# vitest fails "handle integrity checks" on Windows with Node.js 24.x
|
||||
exclude:
|
||||
- node: 24
|
||||
platform: windows-latest
|
||||
|
||||
name: "${{matrix.platform}} w/ Node.js ${{matrix.node}}.x"
|
||||
runs-on: ${{matrix.platform}}
|
||||
|
||||
|
|
|
@ -8,17 +8,19 @@ env:
|
|||
YARN_ENABLE_GLOBAL_CACHE: false
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
release-please:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
outputs:
|
||||
release_created: ${{ steps.release.outputs.release_created }}
|
||||
release_tag: ${{ steps.release.outputs.tag_name }}
|
||||
steps:
|
||||
- uses: google-github-actions/release-please-action@v3
|
||||
- uses: googleapis/release-please-action@v3
|
||||
id: release
|
||||
with:
|
||||
release-type: node
|
||||
|
@ -29,6 +31,9 @@ jobs:
|
|||
needs: release-please
|
||||
if: ${{ needs.release-please.outputs.release_created }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
|
@ -48,10 +53,10 @@ jobs:
|
|||
restore-keys: |
|
||||
${{runner.os}}-yarn-
|
||||
|
||||
- run: corepack yarn install --immutable
|
||||
|
||||
- name: Publish to the npm registry
|
||||
run: |
|
||||
corepack yarn install --immutable
|
||||
corepack yarn npm publish
|
||||
run: corepack yarn npm publish --provenance
|
||||
env:
|
||||
YARN_NPM_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ jobs:
|
|||
fetch-latest-versions:
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"**/.yarn": true,
|
||||
"**/.pnp.*": true
|
||||
},
|
||||
"eslint.experimental.useFlatConfig": true,
|
||||
"eslint.useFlatConfig": true,
|
||||
"eslint.nodePath": ".yarn/sdks",
|
||||
"typescript.enablePromptUseWorkspaceTsdk": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
|
|
|
@ -1,20 +1,32 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire} = require(`module`);
|
||||
const {createRequire, register} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
const {pathToFileURL} = require(`url`);
|
||||
|
||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
|
||||
const absRequire = createRequire(absPnpApiPath);
|
||||
|
||||
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
|
||||
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require eslint/bin/eslint.js
|
||||
require(absPnpApiPath).setup();
|
||||
if (isPnpLoaderEnabled && register) {
|
||||
register(pathToFileURL(absPnpLoaderPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
|
||||
? exports => absRequire(absUserWrapperPath)(exports)
|
||||
: exports => exports;
|
||||
|
||||
// Defer to the real eslint/bin/eslint.js your application uses
|
||||
module.exports = absRequire(`eslint/bin/eslint.js`);
|
||||
module.exports = wrapWithUserWrapper(absRequire(`eslint/bin/eslint.js`));
|
||||
|
|
|
@ -1,20 +1,32 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire} = require(`module`);
|
||||
const {createRequire, register} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
const {pathToFileURL} = require(`url`);
|
||||
|
||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
|
||||
const absRequire = createRequire(absPnpApiPath);
|
||||
|
||||
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
|
||||
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require eslint
|
||||
require(absPnpApiPath).setup();
|
||||
if (isPnpLoaderEnabled && register) {
|
||||
register(pathToFileURL(absPnpLoaderPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
|
||||
? exports => absRequire(absUserWrapperPath)(exports)
|
||||
: exports => exports;
|
||||
|
||||
// Defer to the real eslint your application uses
|
||||
module.exports = absRequire(`eslint`);
|
||||
module.exports = wrapWithUserWrapper(absRequire(`eslint`));
|
||||
|
|
|
@ -1,20 +1,32 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire} = require(`module`);
|
||||
const {createRequire, register} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
const {pathToFileURL} = require(`url`);
|
||||
|
||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
|
||||
const absRequire = createRequire(absPnpApiPath);
|
||||
|
||||
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
|
||||
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require eslint/use-at-your-own-risk
|
||||
require(absPnpApiPath).setup();
|
||||
if (isPnpLoaderEnabled && register) {
|
||||
register(pathToFileURL(absPnpLoaderPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
|
||||
? exports => absRequire(absUserWrapperPath)(exports)
|
||||
: exports => exports;
|
||||
|
||||
// Defer to the real eslint/use-at-your-own-risk your application uses
|
||||
module.exports = absRequire(`eslint/use-at-your-own-risk`);
|
||||
module.exports = wrapWithUserWrapper(absRequire(`eslint/use-at-your-own-risk`));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "eslint",
|
||||
"version": "8.56.0-sdk",
|
||||
"version": "8.57.0-sdk",
|
||||
"main": "./lib/api.js",
|
||||
"type": "commonjs",
|
||||
"bin": {
|
||||
|
|
|
@ -1,20 +1,32 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire} = require(`module`);
|
||||
const {createRequire, register} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
const {pathToFileURL} = require(`url`);
|
||||
|
||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
|
||||
const absRequire = createRequire(absPnpApiPath);
|
||||
|
||||
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
|
||||
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require typescript/bin/tsc
|
||||
require(absPnpApiPath).setup();
|
||||
if (isPnpLoaderEnabled && register) {
|
||||
register(pathToFileURL(absPnpLoaderPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
|
||||
? exports => absRequire(absUserWrapperPath)(exports)
|
||||
: exports => exports;
|
||||
|
||||
// Defer to the real typescript/bin/tsc your application uses
|
||||
module.exports = absRequire(`typescript/bin/tsc`);
|
||||
module.exports = wrapWithUserWrapper(absRequire(`typescript/bin/tsc`));
|
||||
|
|
|
@ -1,20 +1,32 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire} = require(`module`);
|
||||
const {createRequire, register} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
const {pathToFileURL} = require(`url`);
|
||||
|
||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
|
||||
const absRequire = createRequire(absPnpApiPath);
|
||||
|
||||
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
|
||||
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require typescript/bin/tsserver
|
||||
require(absPnpApiPath).setup();
|
||||
if (isPnpLoaderEnabled && register) {
|
||||
register(pathToFileURL(absPnpLoaderPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
|
||||
? exports => absRequire(absUserWrapperPath)(exports)
|
||||
: exports => exports;
|
||||
|
||||
// Defer to the real typescript/bin/tsserver your application uses
|
||||
module.exports = absRequire(`typescript/bin/tsserver`);
|
||||
module.exports = wrapWithUserWrapper(absRequire(`typescript/bin/tsserver`));
|
||||
|
|
|
@ -1,20 +1,32 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire} = require(`module`);
|
||||
const {createRequire, register} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
const {pathToFileURL} = require(`url`);
|
||||
|
||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
|
||||
const absRequire = createRequire(absPnpApiPath);
|
||||
|
||||
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
|
||||
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require typescript/lib/tsc.js
|
||||
require(absPnpApiPath).setup();
|
||||
if (isPnpLoaderEnabled && register) {
|
||||
register(pathToFileURL(absPnpLoaderPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
|
||||
? exports => absRequire(absUserWrapperPath)(exports)
|
||||
: exports => exports;
|
||||
|
||||
// Defer to the real typescript/lib/tsc.js your application uses
|
||||
module.exports = absRequire(`typescript/lib/tsc.js`);
|
||||
module.exports = wrapWithUserWrapper(absRequire(`typescript/lib/tsc.js`));
|
||||
|
|
|
@ -1,15 +1,38 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire} = require(`module`);
|
||||
const {createRequire, register} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
const {pathToFileURL} = require(`url`);
|
||||
|
||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
|
||||
const absRequire = createRequire(absPnpApiPath);
|
||||
|
||||
const moduleWrapper = tsserver => {
|
||||
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
|
||||
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require typescript/lib/tsserver.js
|
||||
require(absPnpApiPath).setup();
|
||||
if (isPnpLoaderEnabled && register) {
|
||||
register(pathToFileURL(absPnpLoaderPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
|
||||
? exports => absRequire(absUserWrapperPath)(exports)
|
||||
: exports => exports;
|
||||
|
||||
const moduleWrapper = exports => {
|
||||
return wrapWithUserWrapper(moduleWrapperFn(exports));
|
||||
};
|
||||
|
||||
const moduleWrapperFn = tsserver => {
|
||||
if (!process.versions.pnp) {
|
||||
return tsserver;
|
||||
}
|
||||
|
@ -214,11 +237,11 @@ const moduleWrapper = tsserver => {
|
|||
return tsserver;
|
||||
};
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require typescript/lib/tsserver.js
|
||||
require(absPnpApiPath).setup();
|
||||
}
|
||||
const [major, minor] = absRequire(`typescript/package.json`).version.split(`.`, 2).map(value => parseInt(value, 10));
|
||||
// In TypeScript@>=5.5 the tsserver uses the public TypeScript API so that needs to be patched as well.
|
||||
// Ref https://github.com/microsoft/TypeScript/pull/55326
|
||||
if (major > 5 || (major === 5 && minor >= 5)) {
|
||||
moduleWrapper(absRequire(`typescript`));
|
||||
}
|
||||
|
||||
// Defer to the real typescript/lib/tsserver.js your application uses
|
||||
|
|
|
@ -1,15 +1,38 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire} = require(`module`);
|
||||
const {createRequire, register} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
const {pathToFileURL} = require(`url`);
|
||||
|
||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
|
||||
const absRequire = createRequire(absPnpApiPath);
|
||||
|
||||
const moduleWrapper = tsserver => {
|
||||
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
|
||||
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require typescript/lib/tsserverlibrary.js
|
||||
require(absPnpApiPath).setup();
|
||||
if (isPnpLoaderEnabled && register) {
|
||||
register(pathToFileURL(absPnpLoaderPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
|
||||
? exports => absRequire(absUserWrapperPath)(exports)
|
||||
: exports => exports;
|
||||
|
||||
const moduleWrapper = exports => {
|
||||
return wrapWithUserWrapper(moduleWrapperFn(exports));
|
||||
};
|
||||
|
||||
const moduleWrapperFn = tsserver => {
|
||||
if (!process.versions.pnp) {
|
||||
return tsserver;
|
||||
}
|
||||
|
@ -214,11 +237,11 @@ const moduleWrapper = tsserver => {
|
|||
return tsserver;
|
||||
};
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require typescript/lib/tsserverlibrary.js
|
||||
require(absPnpApiPath).setup();
|
||||
}
|
||||
const [major, minor] = absRequire(`typescript/package.json`).version.split(`.`, 2).map(value => parseInt(value, 10));
|
||||
// In TypeScript@>=5.5 the tsserver uses the public TypeScript API so that needs to be patched as well.
|
||||
// Ref https://github.com/microsoft/TypeScript/pull/55326
|
||||
if (major > 5 || (major === 5 && minor >= 5)) {
|
||||
moduleWrapper(absRequire(`typescript`));
|
||||
}
|
||||
|
||||
// Defer to the real typescript/lib/tsserverlibrary.js your application uses
|
||||
|
|
|
@ -1,20 +1,32 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire} = require(`module`);
|
||||
const {createRequire, register} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
const {pathToFileURL} = require(`url`);
|
||||
|
||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`);
|
||||
const absRequire = createRequire(absPnpApiPath);
|
||||
|
||||
const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`);
|
||||
const isPnpLoaderEnabled = existsSync(absPnpLoaderPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require typescript
|
||||
require(absPnpApiPath).setup();
|
||||
if (isPnpLoaderEnabled && register) {
|
||||
register(pathToFileURL(absPnpLoaderPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const wrapWithUserWrapper = existsSync(absUserWrapperPath)
|
||||
? exports => absRequire(absUserWrapperPath)(exports)
|
||||
: exports => exports;
|
||||
|
||||
// Defer to the real typescript your application uses
|
||||
module.exports = absRequire(`typescript`);
|
||||
module.exports = wrapWithUserWrapper(absRequire(`typescript`));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "typescript",
|
||||
"version": "5.3.3-sdk",
|
||||
"version": "5.7.3-sdk",
|
||||
"main": "./lib/typescript.js",
|
||||
"type": "commonjs",
|
||||
"bin": {
|
||||
|
|
65
CHANGELOG.md
65
CHANGELOG.md
|
@ -1,5 +1,70 @@
|
|||
# Changelog
|
||||
|
||||
## [0.33.0](https://github.com/nodejs/corepack/compare/v0.32.0...v0.33.0) (2025-06-02)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Adds guard to avoid stepping on Yarn's feet ([#714](https://github.com/nodejs/corepack/issues/714)) ([5fc3691](https://github.com/nodejs/corepack/commit/5fc3691354eb5bdeca17a9495b234584353f0151))
|
||||
* update package manager versions ([#671](https://github.com/nodejs/corepack/issues/671)) ([b45b3a3](https://github.com/nodejs/corepack/commit/b45b3a3244bacfbaf65188ae8c04209a1e98307d))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* debug text typo ([#698](https://github.com/nodejs/corepack/issues/698)) ([0b94797](https://github.com/nodejs/corepack/commit/0b94797f96e30e46e466873fe7d437d0471cd92c))
|
||||
|
||||
## [0.32.0](https://github.com/nodejs/corepack/compare/v0.31.0...v0.32.0) (2025-02-28)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add limited support for `devEngines` ([#643](https://github.com/nodejs/corepack/issues/643)) ([b456268](https://github.com/nodejs/corepack/commit/b4562688513f23e37e37b0d69a0daff33ca84c8d))
|
||||
* add more informative error when fetching latest stable fails ([#644](https://github.com/nodejs/corepack/issues/644)) ([53b1fe7](https://github.com/nodejs/corepack/commit/53b1fe75c47c06bd72a8b8f8bb699a47c9ca32fb))
|
||||
* add support for `.corepack.env` ([#642](https://github.com/nodejs/corepack/issues/642)) ([9b95b46](https://github.com/nodejs/corepack/commit/9b95b46f05e50fe1c60f05309c210ba8fe4e23c5))
|
||||
* update package manager versions ([#617](https://github.com/nodejs/corepack/issues/617)) ([b83bb5e](https://github.com/nodejs/corepack/commit/b83bb5ec150980c998b9c7053dff307d912cb508))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* do not resolve fallback descriptor when `packageManager` is defined ([#632](https://github.com/nodejs/corepack/issues/632)) ([12e77e5](https://github.com/nodejs/corepack/commit/12e77e506946d42a0de9ce8e68d75af8454d6776))
|
||||
* **doc:** fix link to proxy library ([#636](https://github.com/nodejs/corepack/issues/636)) ([bae0839](https://github.com/nodejs/corepack/commit/bae08397943d4b99437389b4286546361091f4b3))
|
||||
* replace explicit with specify as verb ([#665](https://github.com/nodejs/corepack/issues/665)) ([351d86c](https://github.com/nodejs/corepack/commit/351d86c20226a8c18bfe212be27401f2908b1595))
|
||||
* **use:** do not throw on invalid `packageManager` ([#663](https://github.com/nodejs/corepack/issues/663)) ([4be72f6](https://github.com/nodejs/corepack/commit/4be72f6941afa0c9b2b7d26635016bb7b560df8a))
|
||||
|
||||
## [0.31.0](https://github.com/nodejs/corepack/compare/v0.30.0...v0.31.0) (2025-01-27)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* drop support for Node.js 21.x ([#594](https://github.com/nodejs/corepack/issues/594))
|
||||
|
||||
### Features
|
||||
|
||||
* update package manager versions ([#595](https://github.com/nodejs/corepack/issues/595)) ([c7a9bde](https://github.com/nodejs/corepack/commit/c7a9bde16dcbbb7e6ef03fef740656cde7ade360))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* only print message for `UsageError`s ([#602](https://github.com/nodejs/corepack/issues/602)) ([72a588c](https://github.com/nodejs/corepack/commit/72a588c2370c17e415b24fe389efdafb3c84e90b))
|
||||
* update npm registry keys ([#614](https://github.com/nodejs/corepack/issues/614)) ([8c90caa](https://github.com/nodejs/corepack/commit/8c90caab7f1c5c9b89f1de113bc1dfc441bf25d2))
|
||||
|
||||
|
||||
### Miscellaneous Chores
|
||||
|
||||
* drop support for Node.js 21.x ([#594](https://github.com/nodejs/corepack/issues/594)) ([8bebc0c](https://github.com/nodejs/corepack/commit/8bebc0c0a5cbcdeec41673dcbaf581e6e1c1be11))
|
||||
|
||||
## [0.30.0](https://github.com/nodejs/corepack/compare/v0.29.4...v0.30.0) (2024-11-23)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* update package manager versions ([#578](https://github.com/nodejs/corepack/issues/578)) ([a286c8f](https://github.com/nodejs/corepack/commit/a286c8f5537ea9ecf9b6ff53c7bc3e8da4e3c8bb))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* prefer `module.enableCompileCache` over `v8-compile-cache` ([#574](https://github.com/nodejs/corepack/issues/574)) ([cba6905](https://github.com/nodejs/corepack/commit/cba690575bd606faeee54bd512ccb8797d49055f))
|
||||
|
||||
## [0.29.4](https://github.com/nodejs/corepack/compare/v0.29.3...v0.29.4) (2024-09-07)
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
If you want to build Corepack yourself, you can build the project like this:
|
||||
|
||||
1. Clone this repository.
|
||||
1. Clone this repository. Some restrictions on the cloning location apply to Windows users, read [Contributing on Windows](#contributing-on-windows) for more information.
|
||||
2. Run `yarn install` (or `corepack yarn install` if the global version of
|
||||
`yarn` is not provided by Corepack).
|
||||
3. Run `yarn build` (or `corepack yarn build`).
|
||||
|
@ -11,6 +11,12 @@ The `dist/` directory now contains the corepack build and the shims.
|
|||
Call `node ./dist/corepack --help` and behold.
|
||||
You can also run the tests with `yarn test`.
|
||||
|
||||
## Contributing on Windows
|
||||
|
||||
If you are cloning the repo to a directory on a Microsoft Windows operating system, it is recommended to use the same drive as your Windows `HOMEDRIVE` to avoid build and other issues related to a current restriction with Yarn Plug'n'Play caching.
|
||||
|
||||
If you are unable to use your `HOMEDRIVE`, you may be able to work around the issue by setting the environment variable `YARN_ENABLE_GLOBAL_CACHE` to `false` before running `yarn install` (or `corepack yarn install`).
|
||||
|
||||
# Adding a new package manager
|
||||
|
||||
New package managers can be added by editing the following files:
|
||||
|
@ -18,7 +24,7 @@ New package managers can be added by editing the following files:
|
|||
- [`config.json`](./config.json),
|
||||
- [`.github/workflows/sync.yml`](./.github/workflows/sync.yml) that keeps pinned
|
||||
versions up-to-date,
|
||||
- [`package.json`](./package.json) to add to add the added shims to the list of
|
||||
- [`package.json`](./package.json) to add the new shims to the list of
|
||||
`"publishConfig/bin"` and `"executableFiles"`,
|
||||
- [`sources/types.ts`](./sources/types.ts) to add the package manager to the
|
||||
`SupportedPackageManagers` enum,
|
||||
|
|
68
README.md
68
README.md
|
@ -11,7 +11,7 @@ and pnpm without having to install them**.
|
|||
|
||||
### Default Installs
|
||||
|
||||
Corepack is [distributed by default with all recent Node.js versions](https://nodejs.org/api/corepack.html).
|
||||
Corepack is distributed with Node.js from version 14.19.0 up to (but not including) 25.0.0.
|
||||
Run `corepack enable` to install the required Yarn and pnpm binaries on your path.
|
||||
|
||||
### Manual Installs
|
||||
|
@ -41,6 +41,25 @@ is distributed along with Node.js itself.
|
|||
|
||||
</details>
|
||||
|
||||
<details><summary>Update Corepack using npm</summary>
|
||||
|
||||
To install the latest version of Corepack, use:
|
||||
|
||||
```shell
|
||||
npm install -g corepack@latest
|
||||
```
|
||||
|
||||
If Corepack was installed on your system using a Node.js Windows Installer
|
||||
`.msi` package then you might need to remove it before attempting to install a
|
||||
different version of Corepack using npm. You can select the Modify option of the
|
||||
Node.js app settings to access the Windows Installer feature selection, and on
|
||||
the "corepack manager" feature of the Node.js `.msi` package by selecting
|
||||
"Entire feature will be unavailable". See
|
||||
[Repair apps and programs in Windows](https://support.microsoft.com/en-us/windows/repair-apps-and-programs-in-windows-e90eefe4-d0a2-7c1b-dd59-949a9030f317)
|
||||
for instructions on accessing the Windows apps page to modify settings.
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary>Install Corepack from source</summary>
|
||||
|
||||
See [`CONTRIBUTING.md`](./CONTRIBUTING.md).
|
||||
|
@ -94,6 +113,35 @@ use in the archive).
|
|||
}
|
||||
```
|
||||
|
||||
#### `devEngines.packageManager`
|
||||
|
||||
When a `devEngines.packageManager` field is defined, and is an object containing
|
||||
a `"name"` field (can also optionally contain `version` and `onFail` fields),
|
||||
Corepack will use it to validate you're using a compatible package manager.
|
||||
|
||||
Depending on the value of `devEngines.packageManager.onFail`:
|
||||
|
||||
- if set to `ignore`, Corepack won't print any warning or error.
|
||||
- if unset or set to `error`, Corepack will throw an error in case of a mismatch.
|
||||
- if set to `warn` or some other value, Corepack will print a warning in case
|
||||
of mismatch.
|
||||
|
||||
If the top-level `packageManager` field is missing, Corepack will use the
|
||||
package manager defined in `devEngines.packageManager` – in which case you must
|
||||
provide a specific version in `devEngines.packageManager.version`, ideally with
|
||||
a hash, as explained in the previous section:
|
||||
|
||||
```json
|
||||
{
|
||||
"devEngines":{
|
||||
"packageManager": {
|
||||
"name": "yarn",
|
||||
"version": "3.2.3+sha224.953c8233f7a92884eee2de69a1b92d1f2ec1655e66d08071ba9a02fa"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Known Good Releases
|
||||
|
||||
When running Corepack within projects that don't list a supported package
|
||||
|
@ -227,6 +275,7 @@ it.
|
|||
|
||||
Unlike `corepack use` this command doesn't take a package manager name nor a
|
||||
version range, as it will always select the latest available version from the
|
||||
range specified in `devEngines.packageManager.version`, or fallback to the
|
||||
same major line. Should you need to upgrade to a new major, use an explicit
|
||||
`corepack use {name}@latest` call (or simply `corepack use {name}`).
|
||||
|
||||
|
@ -237,8 +286,8 @@ same major line. Should you need to upgrade to a new major, use an explicit
|
|||
package manager, and to not update the Last Known Good version when it
|
||||
downloads a new version of the same major line.
|
||||
|
||||
- `COREPACK_ENABLE_AUTO_PIN` can be set to `0` to prevent Corepack from
|
||||
updating the `packageManager` field when it detects that the local package
|
||||
- `COREPACK_ENABLE_AUTO_PIN` can be set to `1` to instruct Corepack to
|
||||
update the `packageManager` field when it detects that the local package
|
||||
doesn't list it. In general we recommend to always list a `packageManager`
|
||||
field (which you can easily set through `corepack use [name]@[version]`), as
|
||||
it ensures that your project installs are always deterministic.
|
||||
|
@ -248,6 +297,7 @@ same major line. Should you need to upgrade to a new major, use an explicit
|
|||
set to `1` to have the URL shown. By default, when Corepack is called
|
||||
explicitly (e.g. `corepack pnpm …`), it is set to `0`; when Corepack is called
|
||||
implicitly (e.g. `pnpm …`), it is set to `1`.
|
||||
The default value cannot be overridden in a `.corepack.env` file.
|
||||
When standard input is a TTY and no CI environment is detected, Corepack will
|
||||
ask for user input before starting the download.
|
||||
|
||||
|
@ -273,6 +323,14 @@ same major line. Should you need to upgrade to a new major, use an explicit
|
|||
project. This means that it will always use the system-wide package manager
|
||||
regardless of what is being specified in the project's `packageManager` field.
|
||||
|
||||
- `COREPACK_ENV_FILE` can be set to `0` to request Corepack to not attempt to
|
||||
load `.corepack.env`; it can be set to a path to specify a different env file.
|
||||
Only keys that start with `COREPACK_` and are not in the exception list
|
||||
(`COREPACK_ENABLE_DOWNLOAD_PROMPT` and `COREPACK_ENV_FILE` are ignored)
|
||||
will be taken into account.
|
||||
For Node.js 18.x users, this setting has no effect as that version doesn't
|
||||
support parsing of `.env` files.
|
||||
|
||||
- `COREPACK_HOME` can be set in order to define where Corepack should install
|
||||
the package managers. By default it is set to `%LOCALAPPDATA%\node\corepack`
|
||||
on Windows, and to `$HOME/.cache/node/corepack` everywhere else.
|
||||
|
@ -294,7 +352,7 @@ same major line. Should you need to upgrade to a new major, use an explicit
|
|||
empty password, explicitly set `COREPACK_NPM_PASSWORD` to an empty string.
|
||||
|
||||
- `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` are supported through
|
||||
[`node-proxy-agent`](https://github.com/TooTallNate/node-proxy-agent).
|
||||
[`proxy-from-env`](https://github.com/Rob--W/proxy-from-env).
|
||||
|
||||
- `COREPACK_INTEGRITY_KEYS` can be set to an empty string or `0` to
|
||||
instruct Corepack to skip integrity checks, or to a JSON string containing
|
||||
|
@ -302,6 +360,8 @@ same major line. Should you need to upgrade to a new major, use an explicit
|
|||
|
||||
## Troubleshooting
|
||||
|
||||
The environment variable `DEBUG` can be set to `corepack` to enable additional debug logging.
|
||||
|
||||
### Networking
|
||||
|
||||
There are a wide variety of networking issues that can occur while running
|
||||
|
|
15
config.json
15
config.json
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"definitions": {
|
||||
"npm": {
|
||||
"default": "10.8.3+sha1.e6085b2864fcfd9b1aad7b602601b5a2fc116699",
|
||||
"default": "11.4.1+sha1.80350af543069991de20657ebcd07d9624cfad06",
|
||||
"fetchLatestFrom": {
|
||||
"type": "npm",
|
||||
"package": "npm"
|
||||
|
@ -38,7 +38,7 @@
|
|||
}
|
||||
},
|
||||
"pnpm": {
|
||||
"default": "9.9.0+sha1.3edbe440f4e570aa8f049adbd06b9483d55cc2d2",
|
||||
"default": "10.11.0+sha1.4048eeefd564ff1ab248fac3e2854d38245fe2f1",
|
||||
"fetchLatestFrom": {
|
||||
"type": "npm",
|
||||
"package": "pnpm"
|
||||
|
@ -102,7 +102,7 @@
|
|||
"package": "yarn"
|
||||
},
|
||||
"transparent": {
|
||||
"default": "4.4.1+sha224.fd21d9eb5fba020083811af1d4953acc21eeb9f6ff97efd1b3f9d4de",
|
||||
"default": "4.9.1+sha224.4285002185abb91fe2b781f27fd1e078086c37a7b095f6ea4ee25971",
|
||||
"commands": [
|
||||
[
|
||||
"yarn",
|
||||
|
@ -165,11 +165,18 @@
|
|||
"keys": {
|
||||
"npm": [
|
||||
{
|
||||
"expires": null,
|
||||
"expires": "2025-01-29T00:00:00.000Z",
|
||||
"keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA",
|
||||
"keytype": "ecdsa-sha2-nistp256",
|
||||
"scheme": "ecdsa-sha2-nistp256",
|
||||
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg=="
|
||||
},
|
||||
{
|
||||
"expires": null,
|
||||
"keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U",
|
||||
"keytype": "ecdsa-sha2-nistp256",
|
||||
"scheme": "ecdsa-sha2-nistp256",
|
||||
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEY6Ya7W++7aUPzvMTrezH6Ycx3c+HOKYCcNGybJZSCJq/fd7Qa8uuAKtdIkUQtQiEKERhAmE5lMMJhP8OkDOa2g=="
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -13,11 +13,13 @@ export default [
|
|||
...yarnpkg,
|
||||
{
|
||||
rules: {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
'no-restricted-globals': [`error`, {
|
||||
name: `fetch`,
|
||||
message: `Use fetch from sources/httpUtils.ts`,
|
||||
}],
|
||||
'@typescript-eslint/no-unused-vars': [`error`, {
|
||||
caughtErrors: `none`,
|
||||
}],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
|
@ -22,6 +22,7 @@ async function main() {
|
|||
fs.writeFileSync(corepackPath, [
|
||||
`#!/usr/bin/env node`,
|
||||
`process.env.COREPACK_ENABLE_DOWNLOAD_PROMPT??='0';`,
|
||||
`require('module').enableCompileCache?.();`,
|
||||
`require('./lib/corepack.cjs').runMain(process.argv.slice(2));`,
|
||||
].join(`\n`));
|
||||
fs.chmodSync(corepackPath, 0o755);
|
||||
|
@ -34,6 +35,7 @@ async function main() {
|
|||
const entryScript = [
|
||||
`#!/usr/bin/env node`,
|
||||
`process.env.COREPACK_ENABLE_DOWNLOAD_PROMPT??='1'`,
|
||||
`require('module').enableCompileCache?.();`,
|
||||
`require('./lib/corepack.cjs').runMain(['${binaryName}', ...process.argv.slice(2)]);`,
|
||||
].join(`\n`);
|
||||
|
||||
|
|
22
package.json
22
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "corepack",
|
||||
"version": "0.29.4",
|
||||
"version": "0.33.0",
|
||||
"homepage": "https://github.com/nodejs/corepack#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nodejs/corepack/issues"
|
||||
|
@ -10,37 +10,37 @@
|
|||
"url": "https://github.com/nodejs/corepack.git"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.17.1 || >=20.10.0"
|
||||
"node": "^20.10.0 || ^22.11.0 || >=24.0.0"
|
||||
},
|
||||
"exports": {
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"license": "MIT",
|
||||
"packageManager": "yarn@4.3.1+sha224.934d21773e22af4b69a7032a2d3b4cb38c1f7c019624777cc9916b23",
|
||||
"packageManager": "yarn@4.9.0+sha224.dce6c5df199861784bd9b0eecb2a228df97e3f18a02b1bb75ff98383",
|
||||
"devDependencies": {
|
||||
"@types/debug": "^4.1.5",
|
||||
"@types/node": "^20.4.6",
|
||||
"@types/proxy-from-env": "^1",
|
||||
"@types/semver": "^7.1.0",
|
||||
"@types/which": "^3.0.0",
|
||||
"@yarnpkg/eslint-config": "^2.0.0",
|
||||
"@yarnpkg/eslint-config": "^3.0.0",
|
||||
"@yarnpkg/fslib": "^3.0.0-rc.48",
|
||||
"@zkochan/cmd-shim": "^6.0.0",
|
||||
"better-sqlite3": "^10.0.0",
|
||||
"better-sqlite3": "^11.7.2",
|
||||
"clipanion": "patch:clipanion@npm%3A3.2.1#~/.yarn/patches/clipanion-npm-3.2.1-fc9187f56c.patch",
|
||||
"debug": "^4.1.1",
|
||||
"esbuild": "^0.21.0",
|
||||
"eslint": "^8.57.0",
|
||||
"esbuild": "^0.25.0",
|
||||
"eslint": "^9.22.0",
|
||||
"proxy-from-env": "^1.1.0",
|
||||
"semver": "^7.6.3",
|
||||
"supports-color": "^9.0.0",
|
||||
"supports-color": "^10.0.0",
|
||||
"tar": "^7.4.0",
|
||||
"tsx": "^4.16.2",
|
||||
"typescript": "^5.3.3",
|
||||
"typescript": "^5.7.3",
|
||||
"undici": "^6.19.2",
|
||||
"v8-compile-cache": "^2.3.0",
|
||||
"vitest": "^2.0.3",
|
||||
"which": "^4.0.0"
|
||||
"vitest": "^3.0.5",
|
||||
"which": "^5.0.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"undici-types": "6.x"
|
||||
|
|
|
@ -14,9 +14,9 @@ import * as folderUtils from './folderUtil
|
|||
import type {NodeError} from './nodeUtils';
|
||||
import * as semverUtils from './semverUtils';
|
||||
import * as specUtils from './specUtils';
|
||||
import {Config, Descriptor, Locator, PackageManagerSpec} from './types';
|
||||
import {Config, Descriptor, LazyLocator, Locator} from './types';
|
||||
import {SupportedPackageManagers, SupportedPackageManagerSet} from './types';
|
||||
import {isSupportedPackageManager} from './types';
|
||||
import {isSupportedPackageManager, PackageManagerSpec} from './types';
|
||||
|
||||
export type PreparedPackageManagerInfo = Awaited<ReturnType<Engine[`ensurePackageManager`]>>;
|
||||
|
||||
|
@ -237,19 +237,23 @@ export class Engine {
|
|||
*
|
||||
* If the project doesn't include a specification file, we just assume that
|
||||
* whatever the user uses is exactly what they want to use. Since the version
|
||||
* isn't explicited, we fallback on known good versions.
|
||||
* isn't specified, we fallback on known good versions.
|
||||
*
|
||||
* Finally, if the project doesn't exist at all, we ask the user whether they
|
||||
* want to create one in the current project. If they do, we initialize a new
|
||||
* project using the default package managers, and configure it so that we
|
||||
* don't need to ask again in the future.
|
||||
*/
|
||||
async findProjectSpec(initialCwd: string, locator: Locator, {transparent = false}: {transparent?: boolean} = {}): Promise<Descriptor> {
|
||||
async findProjectSpec(initialCwd: string, locator: Locator | LazyLocator, {transparent = false}: {transparent?: boolean} = {}): Promise<Descriptor> {
|
||||
// A locator is a valid descriptor (but not the other way around)
|
||||
const fallbackDescriptor = {name: locator.name, range: `${locator.reference}`};
|
||||
|
||||
if (process.env.COREPACK_ENABLE_PROJECT_SPEC === `0`)
|
||||
if (process.env.COREPACK_ENABLE_PROJECT_SPEC === `0`) {
|
||||
if (typeof locator.reference === `function`)
|
||||
fallbackDescriptor.range = await locator.reference();
|
||||
|
||||
return fallbackDescriptor;
|
||||
}
|
||||
|
||||
if (process.env.COREPACK_ENABLE_STRICT === `0`)
|
||||
transparent = true;
|
||||
|
@ -258,12 +262,19 @@ export class Engine {
|
|||
const result = await specUtils.loadSpec(initialCwd);
|
||||
|
||||
switch (result.type) {
|
||||
case `NoProject`:
|
||||
case `NoProject`: {
|
||||
if (typeof locator.reference === `function`)
|
||||
fallbackDescriptor.range = await locator.reference();
|
||||
|
||||
debugUtils.log(`Falling back to ${fallbackDescriptor.name}@${fallbackDescriptor.range} as no project manifest were found`);
|
||||
return fallbackDescriptor;
|
||||
}
|
||||
|
||||
case `NoSpec`: {
|
||||
if (process.env.COREPACK_ENABLE_AUTO_PIN !== `0`) {
|
||||
if (typeof locator.reference === `function`)
|
||||
fallbackDescriptor.range = await locator.reference();
|
||||
|
||||
if (process.env.COREPACK_ENABLE_AUTO_PIN === `1`) {
|
||||
const resolved = await this.resolveDescriptor(fallbackDescriptor, {allowTags: true});
|
||||
if (resolved === null)
|
||||
throw new UsageError(`Failed to successfully resolve '${fallbackDescriptor.range}' to a valid ${fallbackDescriptor.name} release`);
|
||||
|
@ -277,21 +288,25 @@ export class Engine {
|
|||
await specUtils.setLocalPackageManager(path.dirname(result.target), installSpec);
|
||||
}
|
||||
|
||||
debugUtils.log(`Falling back to ${fallbackDescriptor.name}@${fallbackDescriptor.range} in the absence of "packageManage" field in ${result.target}`);
|
||||
debugUtils.log(`Falling back to ${fallbackDescriptor.name}@${fallbackDescriptor.range} in the absence of "packageManager" field in ${result.target}`);
|
||||
return fallbackDescriptor;
|
||||
}
|
||||
|
||||
case `Found`: {
|
||||
if (result.spec.name !== locator.name) {
|
||||
const spec = result.getSpec();
|
||||
if (spec.name !== locator.name) {
|
||||
if (transparent) {
|
||||
debugUtils.log(`Falling back to ${fallbackDescriptor.name}@${fallbackDescriptor.range} in a ${result.spec.name}@${result.spec.range} project`);
|
||||
if (typeof locator.reference === `function`)
|
||||
fallbackDescriptor.range = await locator.reference();
|
||||
|
||||
debugUtils.log(`Falling back to ${fallbackDescriptor.name}@${fallbackDescriptor.range} in a ${spec.name}@${spec.range} project`);
|
||||
return fallbackDescriptor;
|
||||
} else {
|
||||
throw new UsageError(`This project is configured to use ${result.spec.name} because ${result.target} has a "packageManager" field`);
|
||||
throw new UsageError(`This project is configured to use ${spec.name} because ${result.target} has a "packageManager" field`);
|
||||
}
|
||||
} else {
|
||||
debugUtils.log(`Using ${result.spec.name}@${result.spec.range} as defined in project manifest ${result.target}`);
|
||||
return result.spec;
|
||||
debugUtils.log(`Using ${spec.name}@${spec.range} as defined in project manifest ${result.target}`);
|
||||
return spec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -299,14 +314,14 @@ export class Engine {
|
|||
}
|
||||
|
||||
async executePackageManagerRequest({packageManager, binaryName, binaryVersion}: PackageManagerRequest, {cwd, args}: {cwd: string, args: Array<string>}): Promise<void> {
|
||||
let fallbackLocator: Locator = {
|
||||
let fallbackLocator: Locator | LazyLocator = {
|
||||
name: binaryName as SupportedPackageManagers,
|
||||
reference: undefined as any,
|
||||
};
|
||||
|
||||
let isTransparentCommand = false;
|
||||
if (packageManager != null) {
|
||||
const defaultVersion = binaryVersion || await this.getDefaultVersion(packageManager);
|
||||
const defaultVersion = binaryVersion || (() => this.getDefaultVersion(packageManager));
|
||||
const definition = this.config.definitions[packageManager]!;
|
||||
|
||||
// If all leading segments match one of the patterns defined in the `transparent`
|
||||
|
@ -325,7 +340,7 @@ export class Engine {
|
|||
|
||||
fallbackLocator = {
|
||||
name: packageManager,
|
||||
reference: fallbackReference,
|
||||
reference: fallbackReference as string,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -13,13 +13,13 @@ export abstract class BaseCommand extends Command<Context> {
|
|||
const lookup = await specUtils.loadSpec(this.context.cwd);
|
||||
switch (lookup.type) {
|
||||
case `NoProject`:
|
||||
throw new UsageError(`Couldn't find a project in the local directory - please explicit the package manager to pack, or run this command from a valid project`);
|
||||
throw new UsageError(`Couldn't find a project in the local directory - please specify the package manager to pack, or run this command from a valid project`);
|
||||
|
||||
case `NoSpec`:
|
||||
throw new UsageError(`The local project doesn't feature a 'packageManager' field - please explicit the package manager to pack, or update the manifest to reference it`);
|
||||
throw new UsageError(`The local project doesn't feature a 'packageManager' field nor a 'devEngines.packageManager' field - please specify the package manager to pack, or update the manifest to reference it`);
|
||||
|
||||
default: {
|
||||
return [lookup.spec];
|
||||
return [lookup.range ?? lookup.getSpec()];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import fs from 'f
|
|||
import path from 'path';
|
||||
import which from 'which';
|
||||
|
||||
import * as corepackUtils from '../corepackUtils';
|
||||
import {Context} from '../main';
|
||||
import type {NodeError} from '../nodeUtils';
|
||||
import {isSupportedPackageManager, SupportedPackageManagerSetWithoutNpm} from '../types';
|
||||
|
@ -70,6 +71,11 @@ export class DisableCommand extends Command<Context> {
|
|||
async removePosixLink(installDirectory: string, binName: string) {
|
||||
const file = path.join(installDirectory, binName);
|
||||
try {
|
||||
if (binName.includes(`yarn`) && corepackUtils.isYarnSwitchPath(await fs.promises.realpath(file))) {
|
||||
console.warn(`${binName} is already installed in ${file} and points to a Yarn Switch install - skipping`);
|
||||
return;
|
||||
}
|
||||
|
||||
await fs.promises.unlink(file);
|
||||
} catch (err) {
|
||||
if ((err as NodeError).code !== `ENOENT`) {
|
||||
|
|
|
@ -4,6 +4,7 @@ import fs from 'f
|
|||
import path from 'path';
|
||||
import which from 'which';
|
||||
|
||||
import * as corepackUtils from '../corepackUtils';
|
||||
import {Context} from '../main';
|
||||
import {isSupportedPackageManager, SupportedPackageManagerSetWithoutNpm} from '../types';
|
||||
|
||||
|
@ -13,7 +14,7 @@ export class EnableCommand extends Command<Context> {
|
|||
];
|
||||
|
||||
static usage = Command.Usage({
|
||||
description: `Add the Corepack shims to the install directories`,
|
||||
description: `Add the Corepack shims to the install directory`,
|
||||
details: `
|
||||
When run, this command will check whether the shims for the specified package managers can be found with the correct values inside the install directory. If not, or if they don't exist, they will be created.
|
||||
|
||||
|
@ -83,6 +84,12 @@ export class EnableCommand extends Command<Context> {
|
|||
|
||||
if (fs.existsSync(file)) {
|
||||
const currentSymlink = await fs.promises.readlink(file);
|
||||
|
||||
if (binName.includes(`yarn`) && corepackUtils.isYarnSwitchPath(await fs.promises.realpath(file))) {
|
||||
console.warn(`${binName} is already installed in ${file} and points to a Yarn Switch install - skipping`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentSymlink !== symlink) {
|
||||
await fs.promises.unlink(file);
|
||||
} else {
|
||||
|
|
|
@ -36,13 +36,13 @@ export class PrepareCommand extends Command<Context> {
|
|||
const lookup = await specUtils.loadSpec(this.context.cwd);
|
||||
switch (lookup.type) {
|
||||
case `NoProject`:
|
||||
throw new UsageError(`Couldn't find a project in the local directory - please explicit the package manager to pack, or run this command from a valid project`);
|
||||
throw new UsageError(`Couldn't find a project in the local directory - please specify the package manager to pack, or run this command from a valid project`);
|
||||
|
||||
case `NoSpec`:
|
||||
throw new UsageError(`The local project doesn't feature a 'packageManager' field - please explicit the package manager to pack, or update the manifest to reference it`);
|
||||
throw new UsageError(`The local project doesn't feature a 'packageManager' field - please specify the package manager to pack, or update the manifest to reference it`);
|
||||
|
||||
default: {
|
||||
specs.push(lookup.spec);
|
||||
specs.push(lookup.getSpec());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,12 @@ import * as npmRegistryUtils from './npmRegist
|
|||
import {RegistrySpec, Descriptor, Locator, PackageManagerSpec} from './types';
|
||||
import {BinList, BinSpec, InstallSpec, DownloadSpec} from './types';
|
||||
|
||||
const YARN_SWITCH_REGEX = /[/\\]switch[/\\]bin[/\\]/;
|
||||
|
||||
export function isYarnSwitchPath(p: string) {
|
||||
return YARN_SWITCH_REGEX.test(p);
|
||||
}
|
||||
|
||||
export function getRegistryFromPackageManagerSpec(spec: PackageManagerSpec) {
|
||||
return process.env.COREPACK_NPM_REGISTRY
|
||||
? spec.npmRegistry ?? spec.registry
|
||||
|
@ -400,12 +406,16 @@ export async function runVersion(locator: Locator, installSpec: InstallSpec & {s
|
|||
if (!binPath)
|
||||
throw new Error(`Assertion failed: Unable to locate path for bin '${binName}'`);
|
||||
|
||||
// Node.js segfaults when using npm@>=9.7.0 and v8-compile-cache
|
||||
// $ docker run -it node:20.3.0-slim corepack npm@9.7.1 --version
|
||||
// [SIGSEGV]
|
||||
if (locator.name !== `npm` || semverLt(locator.reference, `9.7.0`))
|
||||
// @ts-expect-error - No types
|
||||
await import(`v8-compile-cache`);
|
||||
// @ts-expect-error - Missing types
|
||||
if (!Module.enableCompileCache) {
|
||||
// Node.js segfaults when using npm@>=9.7.0 and v8-compile-cache
|
||||
// $ docker run -it node:20.3.0-slim corepack npm@9.7.1 --version
|
||||
// [SIGSEGV]
|
||||
if (locator.name !== `npm` || semverLt(locator.reference, `9.7.0`)) {
|
||||
// @ts-expect-error - No types
|
||||
await import(`v8-compile-cache`);
|
||||
}
|
||||
}
|
||||
|
||||
// We load the binary into the current process,
|
||||
// while making it think it was spawned.
|
||||
|
@ -429,6 +439,12 @@ export async function runVersion(locator: Locator, installSpec: InstallSpec & {s
|
|||
// Use nextTick to unwind the stack, and consequently remove Corepack from
|
||||
// the stack trace of the package manager.
|
||||
process.nextTick(Module.runMain, binPath);
|
||||
|
||||
// @ts-expect-error - No types
|
||||
if (Module.flushCompileCache) {
|
||||
// @ts-expect-error - No types
|
||||
setImmediate(Module.flushCompileCache);
|
||||
}
|
||||
}
|
||||
|
||||
export function shouldSkipIntegrityCheck() {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import {BaseContext, Builtins, Cli} from 'clipanion';
|
||||
import type {UsageError} from 'clipanion';
|
||||
|
||||
import {version as corepackVersion} from '../package.json';
|
||||
|
||||
|
@ -37,6 +38,10 @@ function getPackageManagerRequestFromCli(parameter: string | undefined, engine:
|
|||
};
|
||||
}
|
||||
|
||||
function isUsageError(error: any): error is UsageError {
|
||||
return error?.name === `UsageError`;
|
||||
}
|
||||
|
||||
export async function runMain(argv: Array<string>) {
|
||||
const engine = new Engine();
|
||||
|
||||
|
@ -79,9 +84,17 @@ export async function runMain(argv: Array<string>) {
|
|||
process.exitCode ??= code;
|
||||
}
|
||||
} else {
|
||||
await engine.executePackageManagerRequest(request, {
|
||||
cwd: process.cwd(),
|
||||
args: restArgs,
|
||||
});
|
||||
try {
|
||||
await engine.executePackageManagerRequest(request, {
|
||||
cwd: process.cwd(),
|
||||
args: restArgs,
|
||||
});
|
||||
} catch (error) {
|
||||
if (isUsageError(error)) {
|
||||
console.error(error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,19 +38,27 @@ export function verifySignature({signatures, integrity, packageName, version}: {
|
|||
packageName: string;
|
||||
version: string;
|
||||
}) {
|
||||
const {npm: keys} = process.env.COREPACK_INTEGRITY_KEYS ?
|
||||
if (!Array.isArray(signatures) || !signatures.length) throw new Error(`No compatible signature found in package metadata`);
|
||||
|
||||
const {npm: trustedKeys} = process.env.COREPACK_INTEGRITY_KEYS ?
|
||||
JSON.parse(process.env.COREPACK_INTEGRITY_KEYS) as typeof defaultConfig.keys :
|
||||
defaultConfig.keys;
|
||||
|
||||
const key = keys.find(({keyid}) => signatures.some(s => s.keyid === keyid));
|
||||
const signature = signatures.find(({keyid}) => keyid === key?.keyid);
|
||||
|
||||
if (key == null || signature == null) throw new Error(`Cannot find matching keyid: ${JSON.stringify({signatures, keys})}`);
|
||||
let signature: typeof signatures[0] | undefined;
|
||||
let key!: string;
|
||||
for (const k of trustedKeys) {
|
||||
signature = signatures.find(({keyid}) => keyid === k.keyid);
|
||||
if (signature != null) {
|
||||
key = k.key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (signature?.sig == null) throw new UsageError(`The package was not signed by any trusted keys: ${JSON.stringify({signatures, trustedKeys}, undefined, 2)}`);
|
||||
|
||||
const verifier = createVerify(`SHA256`);
|
||||
verifier.end(`${packageName}@${version}:${integrity}`);
|
||||
const valid = verifier.verify(
|
||||
`-----BEGIN PUBLIC KEY-----\n${key.key}\n-----END PUBLIC KEY-----`,
|
||||
`-----BEGIN PUBLIC KEY-----\n${key}\n-----END PUBLIC KEY-----`,
|
||||
signature.sig,
|
||||
`base64`,
|
||||
);
|
||||
|
@ -65,10 +73,15 @@ export async function fetchLatestStableVersion(packageName: string) {
|
|||
const {version, dist: {integrity, signatures, shasum}} = metadata;
|
||||
|
||||
if (!shouldSkipIntegrityCheck()) {
|
||||
verifySignature({
|
||||
packageName, version,
|
||||
integrity, signatures,
|
||||
});
|
||||
try {
|
||||
verifySignature({
|
||||
packageName, version,
|
||||
integrity, signatures,
|
||||
});
|
||||
} catch (cause) {
|
||||
// TODO: consider switching to `UsageError` when https://github.com/arcanis/clipanion/issues/157 is fixed
|
||||
throw new Error(`Corepack cannot download the latest stable version of ${packageName}; you can disable signature verification by setting COREPACK_INTEGRITY_CHECK to 0 in your env, or instruct Corepack to use the latest stable release known by this version of Corepack by setting COREPACK_USE_LATEST to 0`, {cause});
|
||||
}
|
||||
}
|
||||
|
||||
return `${version}+${
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
import {UsageError} from 'clipanion';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import semverSatisfies from 'semver/functions/satisfies';
|
||||
import semverValid from 'semver/functions/valid';
|
||||
import semverValidRange from 'semver/ranges/valid';
|
||||
import {parseEnv} from 'util';
|
||||
|
||||
import {PreparedPackageManagerInfo} from './Engine';
|
||||
import * as debugUtils from './debugUtils';
|
||||
import {NodeError} from './nodeUtils';
|
||||
import * as nodeUtils from './nodeUtils';
|
||||
import {Descriptor, isSupportedPackageManager} from './types';
|
||||
import type {LocalEnvFile} from './types';
|
||||
|
||||
const nodeModulesRegExp = /[\\/]node_modules[\\/](@[^\\/]*[\\/])?([^@\\/][^\\/]*)$/;
|
||||
|
||||
|
@ -52,16 +56,87 @@ export function parseSpec(raw: unknown, source: string, {enforceExactVersion = t
|
|||
};
|
||||
}
|
||||
|
||||
type CorepackPackageJSON = {
|
||||
packageManager?: string;
|
||||
devEngines?: {packageManager?: DevEngineDependency};
|
||||
};
|
||||
|
||||
interface DevEngineDependency {
|
||||
name: string;
|
||||
version: string;
|
||||
onFail?: `ignore` | `warn` | `error`;
|
||||
}
|
||||
function warnOrThrow(errorMessage: string, onFail?: DevEngineDependency[`onFail`]) {
|
||||
switch (onFail) {
|
||||
case `ignore`:
|
||||
break;
|
||||
case `error`:
|
||||
case undefined:
|
||||
throw new UsageError(errorMessage);
|
||||
default:
|
||||
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;
|
||||
}
|
||||
if (Array.isArray(packageManager)) {
|
||||
console.warn(`! Corepack does not currently support array values for devEngines.packageManager`);
|
||||
return pm;
|
||||
}
|
||||
|
||||
const {name, version, onFail} = packageManager;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
return `${name}@${version ?? `*`}`;
|
||||
}
|
||||
|
||||
return pm;
|
||||
}
|
||||
|
||||
export async function setLocalPackageManager(cwd: string, info: PreparedPackageManagerInfo) {
|
||||
const lookup = await loadSpec(cwd);
|
||||
|
||||
const range = `range` in lookup && lookup.range;
|
||||
if (range) {
|
||||
if (info.locator.name !== range.name || !semverSatisfies(info.locator.reference, range.range)) {
|
||||
warnOrThrow(`The requested version of ${info.locator.name}@${info.locator.reference} does not match the devEngines specification (${range.name}@${range.range})`, range.onFail);
|
||||
}
|
||||
}
|
||||
|
||||
const content = lookup.type !== `NoProject`
|
||||
? await fs.promises.readFile(lookup.target, `utf8`)
|
||||
: ``;
|
||||
|
||||
const {data, indent} = nodeUtils.readPackageJson(content);
|
||||
|
||||
const previousPackageManager = data.packageManager ?? `unknown`;
|
||||
const previousPackageManager = data.packageManager ?? (range ? `${range.name}@${range.range}` : `unknown`);
|
||||
data.packageManager = `${info.locator.name}@${info.locator.reference}`;
|
||||
|
||||
const newContent = nodeUtils.normalizeLineEndings(content, `${JSON.stringify(data, null, indent)}\n`);
|
||||
|
@ -72,10 +147,17 @@ export async function setLocalPackageManager(cwd: string, info: PreparedPackageM
|
|||
};
|
||||
}
|
||||
|
||||
interface FoundSpecResult {
|
||||
type: `Found`;
|
||||
target: string;
|
||||
getSpec: () => Descriptor;
|
||||
range?: Descriptor & {onFail?: DevEngineDependency[`onFail`]};
|
||||
envFilePath?: string;
|
||||
}
|
||||
export type LoadSpecResult =
|
||||
| {type: `NoProject`, target: string}
|
||||
| {type: `NoSpec`, target: string}
|
||||
| {type: `Found`, target: string, spec: Descriptor};
|
||||
| FoundSpecResult;
|
||||
|
||||
export async function loadSpec(initialCwd: string): Promise<LoadSpecResult> {
|
||||
let nextCwd = initialCwd;
|
||||
|
@ -84,6 +166,8 @@ export async function loadSpec(initialCwd: string): Promise<LoadSpecResult> {
|
|||
let selection: {
|
||||
data: any;
|
||||
manifestPath: string;
|
||||
envFilePath?: string;
|
||||
localEnv: LocalEnvFile;
|
||||
} | null = null;
|
||||
|
||||
while (nextCwd !== currCwd && (!selection || !selection.data.packageManager)) {
|
||||
|
@ -111,19 +195,60 @@ export async function loadSpec(initialCwd: string): Promise<LoadSpecResult> {
|
|||
if (typeof data !== `object` || data === null)
|
||||
throw new UsageError(`Invalid package.json in ${path.relative(initialCwd, manifestPath)}`);
|
||||
|
||||
selection = {data, manifestPath};
|
||||
let localEnv: LocalEnvFile;
|
||||
const envFilePath = path.resolve(currCwd, process.env.COREPACK_ENV_FILE ?? `.corepack.env`);
|
||||
if (process.env.COREPACK_ENV_FILE == `0`) {
|
||||
debugUtils.log(`Skipping env file as configured with COREPACK_ENV_FILE`);
|
||||
localEnv = process.env;
|
||||
} else if (typeof parseEnv !== `function`) {
|
||||
// TODO: remove this block when support for Node.js 18.x is dropped.
|
||||
debugUtils.log(`Skipping env file as it is not supported by the current version of Node.js`);
|
||||
localEnv = process.env;
|
||||
} else {
|
||||
debugUtils.log(`Checking ${envFilePath}`);
|
||||
try {
|
||||
localEnv = {
|
||||
...Object.fromEntries(Object.entries(parseEnv(await fs.promises.readFile(envFilePath, `utf8`))).filter(e => e[0].startsWith(`COREPACK_`))),
|
||||
...process.env,
|
||||
};
|
||||
debugUtils.log(`Successfully loaded env file found at ${envFilePath}`);
|
||||
} catch (err) {
|
||||
if ((err as NodeError)?.code !== `ENOENT`)
|
||||
throw err;
|
||||
|
||||
debugUtils.log(`No env file found at ${envFilePath}`);
|
||||
localEnv = process.env;
|
||||
}
|
||||
}
|
||||
|
||||
selection = {data, manifestPath, localEnv, envFilePath};
|
||||
}
|
||||
|
||||
if (selection === null)
|
||||
return {type: `NoProject`, target: path.join(initialCwd, `package.json`)};
|
||||
|
||||
const rawPmSpec = selection.data.packageManager;
|
||||
let envFilePath: string | undefined;
|
||||
if (selection.localEnv !== process.env) {
|
||||
envFilePath = selection.envFilePath;
|
||||
process.env = selection.localEnv;
|
||||
}
|
||||
|
||||
const rawPmSpec = parsePackageJSON(selection.data);
|
||||
if (typeof rawPmSpec === `undefined`)
|
||||
return {type: `NoSpec`, target: selection.manifestPath};
|
||||
|
||||
debugUtils.log(`${selection.manifestPath} defines ${rawPmSpec} as local package manager`);
|
||||
|
||||
return {
|
||||
type: `Found`,
|
||||
target: selection.manifestPath,
|
||||
spec: parseSpec(rawPmSpec, path.relative(initialCwd, selection.manifestPath)),
|
||||
envFilePath,
|
||||
range: selection.data.devEngines?.packageManager?.version && {
|
||||
name: selection.data.devEngines.packageManager.name,
|
||||
range: selection.data.devEngines.packageManager.version,
|
||||
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)),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ export interface DownloadSpec {
|
|||
*/
|
||||
export interface Config {
|
||||
definitions: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
|
||||
[name in SupportedPackageManagers]?: {
|
||||
/**
|
||||
* Defines the version that needs to be used when running commands within
|
||||
|
@ -145,3 +145,20 @@ export interface Locator {
|
|||
*/
|
||||
reference: string;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export interface LazyLocator {
|
||||
/**
|
||||
* The name of the package manager required.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* The exact version required.
|
||||
*/
|
||||
reference: () => Promise<string>;
|
||||
}
|
||||
|
||||
export type LocalEnvFile = Record<string, string | undefined>;
|
||||
|
|
|
@ -97,4 +97,23 @@ describe(`DisableCommand`, () => {
|
|||
await expect(sortedEntries).resolves.toEqual([...binNames].sort());
|
||||
});
|
||||
});
|
||||
|
||||
it(`shouldn't remove Yarn binaries if they are in a /switch/ folder`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.mkdirPromise(ppath.join(cwd, `switch/bin`), {recursive: true});
|
||||
await xfs.writeFilePromise(ppath.join(cwd, `switch/bin/yarn`), `hello`);
|
||||
|
||||
await xfs.linkPromise(
|
||||
ppath.join(cwd, `switch/bin/yarn`),
|
||||
ppath.join(cwd, `yarn`),
|
||||
);
|
||||
|
||||
await expect(runCli(cwd, [`disable`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
});
|
||||
|
||||
const file = await xfs.readFilePromise(ppath.join(cwd, `yarn`), `utf8`);
|
||||
expect(file).toBe(`hello`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import {Filename, ppath, xfs, npath} from '@yarnpkg/fslib';
|
||||
import {delimiter} from 'node:path';
|
||||
import process from 'node:process';
|
||||
import {describe, beforeEach, it, expect} from 'vitest';
|
||||
import {describe, beforeEach, it, expect, test} from 'vitest';
|
||||
|
||||
import {Engine} from '../sources/Engine';
|
||||
import {SupportedPackageManagers, SupportedPackageManagerSetWithoutNpm} from '../sources/types';
|
||||
|
@ -87,4 +87,42 @@ describe(`EnableCommand`, () => {
|
|||
await expect(sortedEntries).resolves.toEqual(expectedEntries.sort());
|
||||
});
|
||||
});
|
||||
|
||||
test.skipIf(process.platform === `win32`)(`should overwrite existing files`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeFilePromise(ppath.join(cwd, `yarn`), `hello`);
|
||||
|
||||
process.env.PATH = `${npath.fromPortablePath(cwd)}${delimiter}${process.env.PATH}`;
|
||||
await expect(runCli(cwd, [`enable`])).resolves.toMatchObject({
|
||||
stdout: ``,
|
||||
stderr: ``,
|
||||
exitCode: 0,
|
||||
});
|
||||
|
||||
const file = await xfs.readFilePromise(ppath.join(cwd, `yarn`), `utf8`);
|
||||
expect(file).toBe(`hello`);
|
||||
});
|
||||
});
|
||||
|
||||
test.skipIf(process.platform === `win32`)(`shouldn't overwrite Yarn files if they are in a /switch/ folder`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.mkdirPromise(ppath.join(cwd, `switch/bin`), {recursive: true});
|
||||
await xfs.writeFilePromise(ppath.join(cwd, `switch/bin/yarn`), `hello`);
|
||||
|
||||
await xfs.linkPromise(
|
||||
ppath.join(cwd, `switch/bin/yarn`),
|
||||
ppath.join(cwd, `yarn`),
|
||||
);
|
||||
|
||||
process.env.PATH = `${npath.fromPortablePath(cwd)}${delimiter}${process.env.PATH}`;
|
||||
await expect(runCli(cwd, [`enable`])).resolves.toMatchObject({
|
||||
stdout: ``,
|
||||
stderr: ``,
|
||||
exitCode: 0,
|
||||
});
|
||||
|
||||
const file = await xfs.readFilePromise(ppath.join(cwd, `yarn`), `utf8`);
|
||||
expect(file).toBe(`hello`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
133
tests/Up.test.ts
133
tests/Up.test.ts
|
@ -5,30 +5,131 @@ import {describe, beforeEach, it, expect} from 'vitest';
|
|||
import {runCli} from './_runCli';
|
||||
|
||||
beforeEach(async () => {
|
||||
const home = await xfs.mktempPromise();
|
||||
|
||||
// `process.env` is reset after each tests in setupTests.js.
|
||||
process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise());
|
||||
process.env.COREPACK_HOME = npath.fromPortablePath(home);
|
||||
process.env.COREPACK_DEFAULT_TO_LATEST = `0`;
|
||||
|
||||
return async () => {
|
||||
await xfs.removePromise(home, {recursive: true});
|
||||
};
|
||||
});
|
||||
|
||||
describe(`UpCommand`, () => {
|
||||
it(`should upgrade the package manager from the current project`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
packageManager: `yarn@2.1.0`,
|
||||
});
|
||||
describe(`should update the "packageManager" field from the current project`, () => {
|
||||
it(`to the same major if no devEngines range`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
packageManager: `yarn@2.1.0`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`up`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
});
|
||||
await expect(runCli(cwd, [`up`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: expect.stringMatching(/^Installing yarn@2\.4\.3 in the project\.\.\.\n\n/),
|
||||
});
|
||||
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toMatchObject({
|
||||
packageManager: `yarn@2.4.3+sha512.8dd9fedc5451829619e526c56f42609ad88ae4776d9d3f9456d578ac085115c0c2f0fb02bb7d57fd2e1b6e1ac96efba35e80a20a056668f61c96934f67694fd0`,
|
||||
});
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toMatchObject({
|
||||
packageManager: `yarn@2.4.3+sha512.8dd9fedc5451829619e526c56f42609ad88ae4776d9d3f9456d578ac085115c0c2f0fb02bb7d57fd2e1b6e1ac96efba35e80a20a056668f61c96934f67694fd0`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `2.4.3\n`,
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `2.4.3\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it(`to whichever range devEngines defines`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
packageManager: `yarn@1.1.0`,
|
||||
devEngines: {
|
||||
packageManager: {
|
||||
name: `yarn`,
|
||||
version: `1.x || 2.x`,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`up`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: expect.stringMatching(/^Installing yarn@2\.4\.3 in the project\.\.\.\n\n/),
|
||||
});
|
||||
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toMatchObject({
|
||||
packageManager: `yarn@2.4.3+sha512.8dd9fedc5451829619e526c56f42609ad88ae4776d9d3f9456d578ac085115c0c2f0fb02bb7d57fd2e1b6e1ac96efba35e80a20a056668f61c96934f67694fd0`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `2.4.3\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it(`to whichever range devEngines defines even if onFail is set to ignore`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
packageManager: `pnpm@10.1.0`,
|
||||
devEngines: {
|
||||
packageManager: {
|
||||
name: `yarn`,
|
||||
version: `1.x || 2.x`,
|
||||
onFail: `ignore`,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`up`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: expect.stringMatching(/^Installing yarn@2\.4\.3 in the project\.\.\.\n\n/),
|
||||
});
|
||||
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toMatchObject({
|
||||
packageManager: `yarn@2.4.3+sha512.8dd9fedc5451829619e526c56f42609ad88ae4776d9d3f9456d578ac085115c0c2f0fb02bb7d57fd2e1b6e1ac96efba35e80a20a056668f61c96934f67694fd0`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `2.4.3\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it(`should succeed even if no 'packageManager' field`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
process.env.NO_COLOR = `1`;
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
devEngines: {
|
||||
packageManager: {
|
||||
name: `yarn`,
|
||||
version: `1.x || 2.x`,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`up`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: expect.stringMatching(/^Installing yarn@2\.4\.3 in the project\.\.\.\n\n/),
|
||||
});
|
||||
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toMatchObject({
|
||||
packageManager: `yarn@2.4.3+sha512.8dd9fedc5451829619e526c56f42609ad88ae4776d9d3f9456d578ac085115c0c2f0fb02bb7d57fd2e1b6e1ac96efba35e80a20a056668f61c96934f67694fd0`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `2.4.3\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,29 +5,112 @@ import {describe, beforeEach, it, expect} from 'vitest';
|
|||
import {runCli} from './_runCli';
|
||||
|
||||
beforeEach(async () => {
|
||||
const home = await xfs.mktempPromise();
|
||||
|
||||
// `process.env` is reset after each tests in setupTests.js.
|
||||
process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise());
|
||||
process.env.COREPACK_HOME = npath.fromPortablePath(home);
|
||||
process.env.COREPACK_DEFAULT_TO_LATEST = `0`;
|
||||
|
||||
return async () => {
|
||||
await xfs.removePromise(home, {recursive: true});
|
||||
};
|
||||
});
|
||||
|
||||
describe(`UseCommand`, () => {
|
||||
it(`should set the package manager in the current project`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
packageManager: `yarn@1.0.0`,
|
||||
});
|
||||
describe(`should set the package manager in the current project`, () => {
|
||||
it(`With an existing 'packageManager' field`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
packageManager: `yarn@1.0.0`,
|
||||
license: `MIT`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`use`, `yarn@1.22.4`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
});
|
||||
await expect(runCli(cwd, [`use`, `yarn@1.22.4`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: expect.stringMatching(/^Installing yarn@1\.22\.4 in the project\.\.\.\n\n/),
|
||||
stderr: ``,
|
||||
});
|
||||
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toMatchObject({
|
||||
packageManager: `yarn@1.22.4+sha512.a1833b862fe52169bd6c2a033045a07df5bc6a23595c259e675fed1b2d035ab37abe6ce309720abb6636d68f03615054b6292dc0a70da31c8697fda228b50d18`,
|
||||
});
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toMatchObject({
|
||||
packageManager: `yarn@1.22.4+sha512.a1833b862fe52169bd6c2a033045a07df5bc6a23595c259e675fed1b2d035ab37abe6ce309720abb6636d68f03615054b6292dc0a70da31c8697fda228b50d18`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `1.22.4\n`,
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `1.22.4\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
it(`with 'devEngines.packageManager' field`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
process.env.NO_COLOR = `1`;
|
||||
const devEngines = {packageManager: {name: `yarn`, version: `2.x`}};
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
devEngines,
|
||||
});
|
||||
|
||||
// Should refuse to install an incompatible version:
|
||||
await expect(runCli(cwd, [`use`, `yarn@1.22.4`])).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: ``,
|
||||
stdout: `Installing yarn@1.22.4 in the project...\nUsage Error: The requested version of yarn@1.22.4+sha512.a1833b862fe52169bd6c2a033045a07df5bc6a23595c259e675fed1b2d035ab37abe6ce309720abb6636d68f03615054b6292dc0a70da31c8697fda228b50d18 does not match the devEngines specification (yarn@2.x)\n\n$ corepack use <pattern>\n`,
|
||||
});
|
||||
|
||||
// Should accept setting to a compatible version:
|
||||
await expect(runCli(cwd, [`use`, `yarn@2.4.3`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: expect.stringMatching(/^Installing yarn@2\.4\.3 in the project\.\.\.\n\n/),
|
||||
});
|
||||
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toMatchObject({
|
||||
devEngines,
|
||||
packageManager: `yarn@2.4.3+sha512.8dd9fedc5451829619e526c56f42609ad88ae4776d9d3f9456d578ac085115c0c2f0fb02bb7d57fd2e1b6e1ac96efba35e80a20a056668f61c96934f67694fd0`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `2.4.3\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it(`with 'devEngines.packageManager' and 'packageManager' fields`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
process.env.NO_COLOR = `1`;
|
||||
const devEngines = {packageManager: {name: `yarn`, version: `1.x || 2.x`}};
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
devEngines,
|
||||
packageManager: `yarn@1.1.0`,
|
||||
license: `MIT`,
|
||||
});
|
||||
|
||||
// Should refuse to install an incompatible version:
|
||||
await expect(runCli(cwd, [`use`, `yarn@1.22.4`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: expect.stringMatching(/^Installing yarn@1\.22\.4 in the project\.\.\.\n\n/),
|
||||
});
|
||||
|
||||
// Should accept setting to a compatible version:
|
||||
await expect(runCli(cwd, [`use`, `yarn@2.4.3`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: expect.stringMatching(/^Installing yarn@2\.4\.3 in the project\.\.\.\n\n/),
|
||||
});
|
||||
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toMatchObject({
|
||||
devEngines,
|
||||
packageManager: `yarn@2.4.3+sha512.8dd9fedc5451829619e526c56f42609ad88ae4776d9d3f9456d578ac085115c0c2f0fb02bb7d57fd2e1b6e1ac96efba35e80a20a056668f61c96934f67694fd0`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `2.4.3\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -64,4 +147,50 @@ describe(`UseCommand`, () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe(`should not care if packageManager is set to an invalid value`, () => {
|
||||
for (const {description, packageManager} of [
|
||||
{
|
||||
description: `when a version range is given`,
|
||||
packageManager: `yarn@1.x`,
|
||||
},
|
||||
{
|
||||
description: `when only the pm name is given`,
|
||||
packageManager: `yarn`,
|
||||
},
|
||||
{
|
||||
description: `when the version is missing`,
|
||||
packageManager: `yarn@`,
|
||||
},
|
||||
{
|
||||
description: `when the field is not a string`,
|
||||
packageManager: [],
|
||||
},
|
||||
]) {
|
||||
it(description, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
packageManager,
|
||||
license: `MIT`, // To avoid warning
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`use`, `yarn@1.22.4`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: expect.stringMatching(/^Installing yarn@1\.22\.4 in the project\.\.\.\n\n/),
|
||||
});
|
||||
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toMatchObject({
|
||||
packageManager: `yarn@1.22.4+sha512.a1833b862fe52169bd6c2a033045a07df5bc6a23595c259e675fed1b2d035ab37abe6ce309720abb6636d68f03615054b6292dc0a70da31c8697fda228b50d18`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `1.22.4\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -79,7 +79,7 @@ const registry = {
|
|||
__proto__: null,
|
||||
yarn: [`1.9998.9999`],
|
||||
pnpm: [`1.9998.9999`],
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
|
||||
'@yarnpkg/cli-dist': [`5.9999.9999`],
|
||||
customPkgManager: [`1.0.0`],
|
||||
};
|
||||
|
@ -111,6 +111,8 @@ function generateVersionMetadata(packageName, version) {
|
|||
const TOKEN_MOCK = `SOME_DUMMY_VALUE`;
|
||||
|
||||
const server = createServer((req, res) => {
|
||||
res.setHeader(`connection`, `close`);
|
||||
|
||||
const auth = req.headers.authorization;
|
||||
|
||||
if (
|
||||
|
@ -129,7 +131,6 @@ const server = createServer((req, res) => {
|
|||
const packageName = req.url.slice(1, slashPosition === -1 ? undefined : slashPosition);
|
||||
if (packageName in registry) {
|
||||
if (req.url === `/${packageName}`) {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
res.end(JSON.stringify({"dist-tags": {
|
||||
latest: registry[packageName].at(-1),
|
||||
}, versions: Object.fromEntries(registry[packageName].map(version =>
|
||||
|
|
|
@ -9,6 +9,6 @@ describe(`key store should be up-to-date`, () => {
|
|||
it(`should contain up-to-date npm keys`, async () => {
|
||||
const r = await globalThis.fetch(new URL(`/-/npm/v1/keys`, DEFAULT_NPM_REGISTRY_URL));
|
||||
expect(r.ok).toBe(true);
|
||||
expect(r.json()).resolves.toMatchObject({keys: defaultConfig.keys.npm});
|
||||
await expect(r.json()).resolves.toMatchObject({keys: defaultConfig.keys.npm});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,31 +1,54 @@
|
|||
import {Filename, ppath, xfs, npath, PortablePath} from '@yarnpkg/fslib';
|
||||
import os from 'node:os';
|
||||
import process from 'node:process';
|
||||
import {beforeEach, describe, expect, it} from 'vitest';
|
||||
import {Filename, ppath, xfs, npath, PortablePath} from '@yarnpkg/fslib';
|
||||
import os from 'node:os';
|
||||
import process from 'node:process';
|
||||
import {afterEach, beforeEach, describe, expect, it} from 'vitest';
|
||||
|
||||
import config from '../config.json';
|
||||
import * as folderUtils from '../sources/folderUtils';
|
||||
import {SupportedPackageManagerSet} from '../sources/types';
|
||||
import config from '../config.json';
|
||||
import * as folderUtils from '../sources/folderUtils';
|
||||
import {SupportedPackageManagerSet} from '../sources/types';
|
||||
|
||||
import {runCli} from './_runCli';
|
||||
import {runCli} from './_runCli';
|
||||
|
||||
|
||||
beforeEach(async () => {
|
||||
const home = await xfs.mktempPromise();
|
||||
|
||||
// `process.env` is reset after each tests in setupTests.js.
|
||||
process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise());
|
||||
process.env.COREPACK_HOME = npath.fromPortablePath(home);
|
||||
process.env.COREPACK_DEFAULT_TO_LATEST = `0`;
|
||||
|
||||
return async () => {
|
||||
await xfs.removePromise(home, {recursive: true});
|
||||
};
|
||||
});
|
||||
|
||||
it(`should refuse to download a package manager if the hash doesn't match`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {
|
||||
packageManager: `yarn@1.22.4+sha1.deadbeef`,
|
||||
});
|
||||
describe(`should refuse to download a package manager if the hash doesn't match`, () => {
|
||||
it(`the one defined in "devEngines.packageManager" field`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {
|
||||
devEngines: {
|
||||
packageManager: {name: `yarn`, version: `1.22.4+sha1.deadbeef`},
|
||||
},
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: /Mismatch hashes/,
|
||||
stdout: ``,
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: expect.stringContaining(`Mismatch hashes`),
|
||||
stdout: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
it(`the one defined in "packageManager" field`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {
|
||||
packageManager: `yarn@1.22.4+sha1.deadbeef`,
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: expect.stringContaining(`Mismatch hashes`),
|
||||
stdout: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -35,7 +58,7 @@ it(`should refuse to download a known package manager from a URL`, async () => {
|
|||
// Package managers known by Corepack cannot be loaded from a URL.
|
||||
await expect(runCli(cwd, [`yarn@https://registry.npmjs.com/yarn/-/yarn-1.22.21.tgz`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: /Illegal use of URL for known package manager/,
|
||||
stderr: expect.stringContaining(`Illegal use of URL for known package manager`),
|
||||
stdout: ``,
|
||||
});
|
||||
|
||||
|
@ -57,7 +80,7 @@ it.fails(`should refuse to download a known package manager from a URL in packag
|
|||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: /Illegal use of URL for known package manager/,
|
||||
stderr: expect.stringContaining(`Illegal use of URL for known package manager`),
|
||||
stdout: ``,
|
||||
});
|
||||
|
||||
|
@ -82,7 +105,7 @@ it(`should require a version to be specified`, async () => {
|
|||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: /expected a semver version/,
|
||||
stderr: `No version specified for yarn in "packageManager" of package.json\n`,
|
||||
stdout: ``,
|
||||
});
|
||||
|
||||
|
@ -92,7 +115,7 @@ it(`should require a version to be specified`, async () => {
|
|||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: /expected a semver version/,
|
||||
stderr: expect.stringContaining(`expected a semver version`),
|
||||
stdout: ``,
|
||||
});
|
||||
|
||||
|
@ -102,7 +125,7 @@ it(`should require a version to be specified`, async () => {
|
|||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: /expected a semver version/,
|
||||
stderr: expect.stringContaining(`expected a semver version`),
|
||||
stdout: ``,
|
||||
});
|
||||
});
|
||||
|
@ -150,6 +173,20 @@ for (const [name, version, expectedVersion = version.split(`+`, 1)[0]] of tested
|
|||
stderr: ``,
|
||||
stdout: `${expectedVersion}\n`,
|
||||
});
|
||||
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {
|
||||
devEngines: {packageManager: {name, version}},
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [name, `--version`])).resolves.toMatchObject(URL.canParse(version) ? {
|
||||
exitCode: 1,
|
||||
stderr: expect.stringMatching(/^The value of devEngines\.packageManager\.version ".+" is not a valid semver range\n$/),
|
||||
stdout: ``,
|
||||
} : {
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: `${expectedVersion}\n`,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -231,6 +268,298 @@ it(`should ignore the packageManager field when found within a node_modules vend
|
|||
});
|
||||
});
|
||||
|
||||
describe(`should handle invalid devEngines values`, () => {
|
||||
it(`throw on missing version`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), {
|
||||
devEngines: {
|
||||
packageManager: {
|
||||
name: `yarn`,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: `Invalid package manager specification in package.json (yarn@*); expected a semver version\n`,
|
||||
stdout: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
it(`throw on invalid version`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), {
|
||||
devEngines: {
|
||||
packageManager: {
|
||||
name: `yarn`,
|
||||
version: `yarn@1.x`,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: `The value of devEngines.packageManager.version "yarn@1.x" is not a valid semver range\n`,
|
||||
stdout: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
it(`warn on array values`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), {
|
||||
packageManager: `yarn@1.22.4+sha1.01c1197ca5b27f21edc8bc472cd4c8ce0e5a470e`,
|
||||
devEngines: {
|
||||
packageManager: [{
|
||||
name: `pnpm`,
|
||||
version: `10.x`,
|
||||
},
|
||||
]},
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: `! Corepack does not currently support array values for devEngines.packageManager\n`,
|
||||
stdout: `1.22.4\n`,
|
||||
});
|
||||
});
|
||||
});
|
||||
it(`warn on string values`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), {
|
||||
packageManager: `yarn@1.22.4+sha1.01c1197ca5b27f21edc8bc472cd4c8ce0e5a470e`,
|
||||
devEngines: {
|
||||
packageManager: `pnpm@10.x`,
|
||||
},
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: `! Corepack only supports objects as valid value for devEngines.packageManager. The current value ("pnpm@10.x") will be ignored.\n`,
|
||||
stdout: `1.22.4\n`,
|
||||
});
|
||||
});
|
||||
});
|
||||
it(`warn on number values`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), {
|
||||
packageManager: `yarn@1.22.4+sha1.01c1197ca5b27f21edc8bc472cd4c8ce0e5a470e`,
|
||||
devEngines: {
|
||||
packageManager: 10,
|
||||
},
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: `! Corepack only supports objects as valid value for devEngines.packageManager. The current value (10) will be ignored.\n`,
|
||||
stdout: `1.22.4\n`,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it(`should use hash from "packageManager" even when "devEngines" defines a different one`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), {
|
||||
packageManager: `yarn@3.0.0-rc.2+sha1.11111`,
|
||||
devEngines: {
|
||||
packageManager: {
|
||||
name: `yarn`,
|
||||
version: `3.0.0-rc.2+sha1.22222`,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: expect.stringContaining(`Mismatch hashes. Expected 11111, got`),
|
||||
stdout: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe(`should accept range in devEngines only if a specific version is provided`, () => {
|
||||
it(`either in package.json#packageManager field`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), {
|
||||
devEngines: {
|
||||
packageManager: {
|
||||
name: `pnpm`,
|
||||
version: `6.x`,
|
||||
},
|
||||
},
|
||||
});
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: `Invalid package manager specification in package.json (pnpm@6.x); expected a semver version\n`,
|
||||
stdout: ``,
|
||||
});
|
||||
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), {
|
||||
devEngines: {
|
||||
packageManager: {
|
||||
name: `pnpm`,
|
||||
version: `6.x`,
|
||||
},
|
||||
},
|
||||
packageManager: `pnpm@6.6.2+sha224.eb5c0acad3b0f40ecdaa2db9aa5a73134ad256e17e22d1419a2ab073`,
|
||||
});
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: `6.6.2\n`,
|
||||
});
|
||||
|
||||
// No version should also work
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), {
|
||||
devEngines: {
|
||||
packageManager: {
|
||||
name: `pnpm`,
|
||||
},
|
||||
},
|
||||
packageManager: `pnpm@6.6.2+sha224.eb5c0acad3b0f40ecdaa2db9aa5a73134ad256e17e22d1419a2ab073`,
|
||||
});
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: `6.6.2\n`,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe(`when devEngines.packageManager.name does not match packageManager`, () => {
|
||||
it(`should ignore if devEngines.packageManager.onFail is set to "ignore"`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), {
|
||||
devEngines: {
|
||||
packageManager: {
|
||||
name: `yarn`,
|
||||
onFail: `ignore`,
|
||||
},
|
||||
},
|
||||
packageManager: `pnpm@6.6.2+sha1.7b4d6b176c1b93b5670ed94c24babb7d80c13854`,
|
||||
});
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: `6.6.2\n`,
|
||||
});
|
||||
});
|
||||
});
|
||||
it(`should warn if devEngines.packageManager.onFail is set to "warn"`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), {
|
||||
devEngines: {
|
||||
packageManager: {
|
||||
name: `yarn`,
|
||||
onFail: `warn`,
|
||||
},
|
||||
},
|
||||
packageManager: `pnpm@6.6.2+sha1.7b4d6b176c1b93b5670ed94c24babb7d80c13854`,
|
||||
});
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: `! Corepack validation warning: "packageManager" field is set to "pnpm@6.6.2+sha1.7b4d6b176c1b93b5670ed94c24babb7d80c13854" which does not match the "devEngines.packageManager" field set to "yarn"\n`,
|
||||
stdout: `6.6.2\n`,
|
||||
});
|
||||
});
|
||||
});
|
||||
it(`should throw if devEngines.packageManager.onFail is set to "error"`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), {
|
||||
devEngines: {
|
||||
packageManager: {
|
||||
name: `yarn`,
|
||||
onFail: `error`,
|
||||
},
|
||||
},
|
||||
packageManager: `pnpm@6.6.2+sha1.7b4d6b176c1b93b5670ed94c24babb7d80c13854`,
|
||||
});
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: `"packageManager" field is set to "pnpm@6.6.2+sha1.7b4d6b176c1b93b5670ed94c24babb7d80c13854" which does not match the "devEngines.packageManager" field set to "yarn"\n`,
|
||||
stdout: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
it(`should throw by default`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), {
|
||||
devEngines: {
|
||||
packageManager: {
|
||||
name: `yarn`,
|
||||
},
|
||||
},
|
||||
packageManager: `pnpm@6.6.2+sha1.7b4d6b176c1b93b5670ed94c24babb7d80c13854`,
|
||||
});
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: `"packageManager" field is set to "pnpm@6.6.2+sha1.7b4d6b176c1b93b5670ed94c24babb7d80c13854" which does not match the "devEngines.packageManager" field set to "yarn"\n`,
|
||||
stdout: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe(`should reject if range in devEngines does not match version provided`, () => {
|
||||
it(`unless onFail is set to "ignore"`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), {
|
||||
devEngines: {
|
||||
packageManager: {
|
||||
name: `pnpm`,
|
||||
version: `10.x`,
|
||||
onFail: `ignore`,
|
||||
},
|
||||
},
|
||||
packageManager: `pnpm@6.6.2+sha1.7b4d6b176c1b93b5670ed94c24babb7d80c13854`,
|
||||
});
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: `6.6.2\n`,
|
||||
});
|
||||
});
|
||||
});
|
||||
it(`unless onFail is set to "warn"`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), {
|
||||
devEngines: {
|
||||
packageManager: {
|
||||
name: `pnpm`,
|
||||
version: `10.x`,
|
||||
onFail: `warn`,
|
||||
},
|
||||
},
|
||||
packageManager: `pnpm@6.6.2+sha1.7b4d6b176c1b93b5670ed94c24babb7d80c13854`,
|
||||
});
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: `! Corepack validation warning: "packageManager" field is set to "pnpm@6.6.2+sha1.7b4d6b176c1b93b5670ed94c24babb7d80c13854" which does not match the value defined in "devEngines.packageManager" for "pnpm" of "10.x"\n`,
|
||||
stdout: `6.6.2\n`,
|
||||
});
|
||||
});
|
||||
});
|
||||
it(`in package.json#packageManager field`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), {
|
||||
devEngines: {
|
||||
packageManager: {
|
||||
name: `pnpm`,
|
||||
version: `10.x`,
|
||||
},
|
||||
},
|
||||
packageManager: `pnpm@6.6.2+sha1.7b4d6b176c1b93b5670ed94c24babb7d80c13854`,
|
||||
});
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: `"packageManager" field is set to "pnpm@6.6.2+sha1.7b4d6b176c1b93b5670ed94c24babb7d80c13854" which does not match the value defined in "devEngines.packageManager" for "pnpm" of "10.x"\n`,
|
||||
stdout: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it(`should use the closest matching packageManager field`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.mkdirPromise(ppath.join(cwd, `foo` as PortablePath), {recursive: true});
|
||||
|
@ -272,7 +601,7 @@ it(`shouldn't allow using regular Yarn commands on npm-configured projects`, asy
|
|||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: /This project is configured to use npm/,
|
||||
stderr: expect.stringContaining(`This project is configured to use npm`),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -318,18 +647,73 @@ for (const name of SupportedPackageManagerSet) {
|
|||
});
|
||||
}
|
||||
|
||||
it(`should configure the project when calling a package manager on it for the first time`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {
|
||||
describe(`when called on a project without any defined packageManager`, () => {
|
||||
it(`should not modify package.json by default`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {
|
||||
// empty package.json file
|
||||
});
|
||||
|
||||
await runCli(cwd, [`yarn`]);
|
||||
|
||||
const data = await xfs.readJsonPromise(ppath.join(cwd, `package.json` as Filename));
|
||||
|
||||
expect(Object.hasOwn(data, `packageManager`)).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
await runCli(cwd, [`yarn`]);
|
||||
it(`should modify package.json if enabled by env`, async () => {
|
||||
process.env.COREPACK_ENABLE_AUTO_PIN = `1`;
|
||||
|
||||
const data = await xfs.readJsonPromise(ppath.join(cwd, `package.json` as Filename));
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {
|
||||
// empty package.json file
|
||||
});
|
||||
|
||||
expect(data).toMatchObject({
|
||||
packageManager: `yarn@${config.definitions.yarn.default}`,
|
||||
await runCli(cwd, [`yarn`]);
|
||||
|
||||
const data = await xfs.readJsonPromise(ppath.join(cwd, `package.json` as Filename));
|
||||
|
||||
expect(data).toMatchObject({
|
||||
packageManager: expect.stringMatching(/^yarn@/),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it(`should modify package.json if enabled by .corepack.env`, async t => {
|
||||
// Skip that test on Node.js 18.x as it lacks support for .env files.
|
||||
if (process.version.startsWith(`v18.`)) t.skip();
|
||||
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {
|
||||
// empty package.json file
|
||||
});
|
||||
await xfs.writeFilePromise(ppath.join(cwd, `.corepack.env` as Filename), `COREPACK_ENABLE_AUTO_PIN=1\n`);
|
||||
|
||||
await runCli(cwd, [`yarn`]);
|
||||
|
||||
const data = await xfs.readJsonPromise(ppath.join(cwd, `package.json` as Filename));
|
||||
|
||||
expect(data).toMatchObject({
|
||||
packageManager: expect.stringMatching(/^yarn@/),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it(`should not modify package.json if .corepack.env is disabled`, async () => {
|
||||
process.env.COREPACK_ENV_FILE = `0`;
|
||||
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {
|
||||
// empty package.json file
|
||||
});
|
||||
await xfs.writeFilePromise(ppath.join(cwd, `.corepack.env` as Filename), `COREPACK_ENABLE_AUTO_PIN=1\n`);
|
||||
|
||||
await runCli(cwd, [`yarn`]);
|
||||
|
||||
const data = await xfs.readJsonPromise(ppath.join(cwd, `package.json` as Filename));
|
||||
|
||||
expect(Object.hasOwn(data, `packageManager`)).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -473,13 +857,19 @@ it(`should support disabling the network accesses from the environment`, async (
|
|||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
stdout: ``,
|
||||
stderr: /Network access disabled by the environment/,
|
||||
stderr: expect.stringContaining(`Network access disabled by the environment`),
|
||||
exitCode: 1,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe(`read-only and offline environment`, () => {
|
||||
afterEach(async () => {
|
||||
const home = npath.toPortablePath(process.env.COREPACK_HOME!);
|
||||
await xfs.chmodPromise(ppath.join(home, `lastKnownGood.json`), 0o644);
|
||||
await xfs.chmodPromise(home, 0o755);
|
||||
});
|
||||
|
||||
it(`should support running in project scope`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
// Reset to default
|
||||
|
@ -497,15 +887,10 @@ describe(`read-only and offline environment`, () => {
|
|||
exitCode: 0,
|
||||
});
|
||||
|
||||
// Let corepack discover the latest yarn version.
|
||||
// BUG: This should not be necessary with a fully specified version in package.json plus populated corepack cache.
|
||||
// Engine.executePackageManagerRequest needs to defer the fallback work. This requires a big refactoring.
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
});
|
||||
|
||||
// Make COREPACK_HOME ro
|
||||
const home = npath.toPortablePath(folderUtils.getCorepackHomeFolder());
|
||||
// Make a lastKnownGood.json file with not JSON-parsable content:
|
||||
await xfs.writeFilePromise(ppath.join(home, `lastKnownGood.json`), `{`);
|
||||
await xfs.chmodPromise(ppath.join(home, `lastKnownGood.json`), 0o444);
|
||||
await xfs.chmodPromise(home, 0o555);
|
||||
|
||||
|
@ -811,16 +1196,35 @@ it(`should support package managers in ESM format`, async () => {
|
|||
});
|
||||
});
|
||||
|
||||
it(`should show a warning on stderr before downloading when enable`, async() => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
process.env.COREPACK_ENABLE_DOWNLOAD_PROMPT = `1`;
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {
|
||||
packageManager: `yarn@3.0.0`,
|
||||
describe(`should show a warning on stderr before downloading when enable`, () => {
|
||||
it(`when enabled by the environment`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
process.env.COREPACK_ENABLE_DOWNLOAD_PROMPT = `1`;
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {
|
||||
packageManager: `yarn@3.0.0`,
|
||||
});
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `3.0.0\n`,
|
||||
stderr: `! Corepack is about to download https://repo.yarnpkg.com/3.0.0/packages/yarnpkg-cli/bin/yarn.js\n`,
|
||||
});
|
||||
});
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `3.0.0\n`,
|
||||
stderr: `! Corepack is about to download https://repo.yarnpkg.com/3.0.0/packages/yarnpkg-cli/bin/yarn.js\n`,
|
||||
});
|
||||
|
||||
it(`should ignore setting in .corepack.env`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeFilePromise(
|
||||
ppath.join(cwd, `.corepack.env` as Filename),
|
||||
`COREPACK_ENABLE_DOWNLOAD_PROMPT=1\n`,
|
||||
);
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {
|
||||
packageManager: `yarn@3.0.0`,
|
||||
});
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `3.0.0\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -850,8 +1254,8 @@ it(`should download yarn classic from custom registry`, async () => {
|
|||
process.env.COREPACK_ENABLE_DOWNLOAD_PROMPT = `1`;
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: /^1\.\d+\.\d+\r?\n$/,
|
||||
stderr: /^! Corepack is about to download https:\/\/registry\.npmmirror\.com\/yarn\/-\/yarn-1\.\d+\.\d+\.tgz\r?\n$/,
|
||||
stdout: expect.stringMatching(/^1\.\d+\.\d+\r?\n$/),
|
||||
stderr: expect.stringMatching(/^! Corepack is about to download https:\/\/registry\.npmmirror\.com\/yarn\/-\/yarn-1\.\d+\.\d+\.tgz\r?\n$/),
|
||||
});
|
||||
|
||||
// Should keep working with cache
|
||||
|
@ -899,7 +1303,7 @@ it(`should download latest pnpm from custom registry`, async () => {
|
|||
await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `pnpm: Hello from custom registry\n`,
|
||||
stderr: /^! The local project doesn't define a 'packageManager' field\. Corepack will now add one referencing pnpm@1\.9998\.9999@sha1\./,
|
||||
stderr: ``,
|
||||
});
|
||||
|
||||
// Should keep working with cache
|
||||
|
@ -911,6 +1315,156 @@ it(`should download latest pnpm from custom registry`, async () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe(`should pick up COREPACK_INTEGRITY_KEYS from env`, () => {
|
||||
beforeEach(() => {
|
||||
process.env.AUTH_TYPE = `COREPACK_NPM_TOKEN`; // See `_registryServer.mjs`
|
||||
process.env.COREPACK_DEFAULT_TO_LATEST = `1`;
|
||||
});
|
||||
|
||||
it(`from env variable`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stdout: ``,
|
||||
stderr: expect.stringContaining(`No compatible signature found in package metadata`),
|
||||
});
|
||||
|
||||
process.env.COREPACK_INTEGRITY_KEYS = `0`;
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `pnpm: Hello from custom registry\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it(`from .corepack.env file`, async t => {
|
||||
// Skip that test on Node.js 18.x as it lacks support for .env files.
|
||||
if (process.version.startsWith(`v18.`)) t.skip();
|
||||
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stdout: ``,
|
||||
stderr: expect.stringContaining(`No compatible signature found in package metadata`),
|
||||
});
|
||||
|
||||
await xfs.writeFilePromise(ppath.join(cwd, `.corepack.env` as Filename), `COREPACK_INTEGRITY_KEYS=0\n`);
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `pnpm: Hello from custom registry\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it(`from env file defined by COREPACK_ENV_FILE`, async t => {
|
||||
// Skip that test on Node.js 18.x as it lacks support for .env files.
|
||||
if (process.version.startsWith(`v18.`)) t.skip();
|
||||
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {
|
||||
});
|
||||
|
||||
await xfs.writeFilePromise(ppath.join(cwd, `.corepack.env` as Filename), `COREPACK_INTEGRITY_KEYS={}\n`);
|
||||
await xfs.writeFilePromise(ppath.join(cwd, `.other.env` as Filename), `COREPACK_INTEGRITY_KEYS=0\n`);
|
||||
|
||||
// By default, Corepack should be using .corepack.env and fail.
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stdout: ``,
|
||||
stderr: expect.stringContaining(`No compatible signature found in package metadata`),
|
||||
});
|
||||
|
||||
process.env.COREPACK_ENV_FILE = `.other.env`;
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `pnpm: Hello from custom registry\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it(`from env even if there's a .corepack.env file`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {
|
||||
});
|
||||
|
||||
await xfs.writeFilePromise(ppath.join(cwd, `.corepack.env` as Filename), `COREPACK_INTEGRITY_KEYS={}\n`);
|
||||
|
||||
// By default, Corepack should be using .corepack.env (or the built-in ones on Node.js 18.x) and fail.
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stdout: ``,
|
||||
stderr: expect.stringContaining(`No compatible signature found in package metadata`),
|
||||
});
|
||||
|
||||
process.env.COREPACK_INTEGRITY_KEYS = ``;
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `pnpm: Hello from custom registry\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it(`should ignore .corepack.env file if COREPACK_ENV_FILE is set to 0`, async t => {
|
||||
// Skip that test on Node.js 18.x as it lacks support for .env files.
|
||||
if (process.version.startsWith(`v18.`)) t.skip();
|
||||
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {
|
||||
});
|
||||
|
||||
await xfs.writeFilePromise(ppath.join(cwd, `.corepack.env` as Filename), `COREPACK_INTEGRITY_KEYS=0\n`);
|
||||
|
||||
process.env.COREPACK_ENV_FILE = `0`;
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stdout: ``,
|
||||
stderr: expect.stringContaining(`No compatible signature found in package metadata`),
|
||||
});
|
||||
|
||||
delete process.env.COREPACK_ENV_FILE;
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `pnpm: Hello from custom registry\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it(`from env file defined by COREPACK_ENV_FILE`, async t => {
|
||||
// Skip that test on Node.js 18.x as it lacks support for .env files.
|
||||
if (process.version.startsWith(`v18.`)) t.skip();
|
||||
|
||||
process.env.COREPACK_ENV_FILE = `.other.env`;
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), {
|
||||
});
|
||||
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stdout: ``,
|
||||
stderr: expect.stringContaining(`No compatible signature found in package metadata`),
|
||||
});
|
||||
|
||||
await xfs.writeFilePromise(ppath.join(cwd, `.other.env` as Filename), `COREPACK_INTEGRITY_KEYS=0\n`);
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `pnpm: Hello from custom registry\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
for (const authType of [`COREPACK_NPM_REGISTRY`, `COREPACK_NPM_TOKEN`, `COREPACK_NPM_PASSWORD`, `PROXY`]) {
|
||||
describe(`custom registry with auth ${authType}`, () => {
|
||||
beforeEach(() => {
|
||||
|
@ -967,122 +1521,139 @@ for (const authType of [`COREPACK_NPM_REGISTRY`, `COREPACK_NPM_TOKEN`, `COREPACK
|
|||
describe(`handle integrity checks`, () => {
|
||||
beforeEach(() => {
|
||||
process.env.AUTH_TYPE = `COREPACK_NPM_TOKEN`; // See `_registryServer.mjs`
|
||||
process.env.COREPACK_DEFAULT_TO_LATEST = `1`;
|
||||
});
|
||||
|
||||
it(`should return no error when signature matches`, async () => {
|
||||
process.env.TEST_INTEGRITY = `valid`; // See `_registryServer.mjs`
|
||||
describe(`when signature matches`, () => {
|
||||
beforeEach(() => {
|
||||
process.env.TEST_INTEGRITY = `valid`; // See `_registryServer.mjs`
|
||||
});
|
||||
|
||||
it(`should return no error when calling 'corepack use'`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
// Skip rest of the test on Windows & Node.js 18.x as it inevitably times out otherwise.
|
||||
if (process.version.startsWith(`v18.`) && os.platform() === `win32`) return;
|
||||
|
||||
// Removing home directory to force the "re-download"
|
||||
await xfs.rmPromise(process.env.COREPACK_HOME as any, {recursive: true});
|
||||
|
||||
await Promise.all([
|
||||
expect(runCli(cwd, [`use`, `pnpm`], true)).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `Installing pnpm@1.9998.9999 in the project...\n\npnpm: Hello from custom registry\n`,
|
||||
stderr: ``,
|
||||
}),
|
||||
expect(runCli(cwd, [`use`, `yarn@1.x`], true)).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `Installing yarn@1.9998.9999 in the project...\n\nyarn: Hello from custom registry\n`,
|
||||
stderr: ``,
|
||||
}),
|
||||
expect(runCli(cwd, [`use`, `yarn@latest`], true)).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `Installing yarn@5.9999.9999 in the project...\n\nyarn: Hello from custom registry\n`,
|
||||
stderr: ``,
|
||||
}),
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it(`should return no error when fetching latest version`, async () => {
|
||||
process.env.COREPACK_DEFAULT_TO_LATEST = `1`;
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await Promise.all([
|
||||
expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `pnpm: Hello from custom registry\n`,
|
||||
stderr: ``,
|
||||
}),
|
||||
expect(runCli(cwd, [`yarn@1.x`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `yarn: Hello from custom registry\n`,
|
||||
stderr: ``,
|
||||
}),
|
||||
expect(runCli(cwd, [`yarn@5.x`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `yarn: Hello from custom registry\n`,
|
||||
stderr: ``,
|
||||
}),
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
it(`should return an error when signature does not match with a range`, async () => {
|
||||
process.env.TEST_INTEGRITY = `invalid_signature`; // See `_registryServer.mjs`
|
||||
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await Promise.all([
|
||||
expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `pnpm: Hello from custom registry\n`,
|
||||
stderr: ``,
|
||||
}),
|
||||
expect(runCli(cwd, [`yarn@1.x`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `yarn: Hello from custom registry\n`,
|
||||
stderr: ``,
|
||||
}),
|
||||
expect(runCli(cwd, [`yarn@5.x`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `yarn: Hello from custom registry\n`,
|
||||
stderr: ``,
|
||||
}),
|
||||
]);
|
||||
|
||||
// Skip rest of the test on Windows & Node.js 18.x as it inevitably times out otherwise.
|
||||
if (process.version.startsWith(`v18.`) && os.platform() === `win32`) return;
|
||||
|
||||
// Removing home directory to force the "re-download"
|
||||
await xfs.rmPromise(process.env.COREPACK_HOME as any, {recursive: true});
|
||||
|
||||
await Promise.all([
|
||||
expect(runCli(cwd, [`use`, `pnpm`], true)).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `Installing pnpm@1.9998.9999 in the project...\n\npnpm: Hello from custom registry\n`,
|
||||
stderr: ``,
|
||||
}),
|
||||
expect(runCli(cwd, [`use`, `yarn@1.x`], true)).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `Installing yarn@1.9998.9999 in the project...\n\nyarn: Hello from custom registry\n`,
|
||||
stderr: ``,
|
||||
}),
|
||||
expect(runCli(cwd, [`use`, `yarn@latest`], true)).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `Installing yarn@5.9999.9999 in the project...\n\nyarn: Hello from custom registry\n`,
|
||||
stderr: ``,
|
||||
}),
|
||||
]);
|
||||
await expect(runCli(cwd, [`pnpm@1.x`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: expect.stringContaining(`Signature does not match`),
|
||||
stdout: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
it(`should return an error when signature does not match with a tag`, async () => {
|
||||
process.env.TEST_INTEGRITY = `invalid_signature`; // See `_registryServer.mjs`
|
||||
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await expect(runCli(cwd, [`pnpm@1.x`, `--version`], true)).resolves.toMatchObject({
|
||||
await expect(runCli(cwd, [`pnpm@latest`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: /Signature does not match/,
|
||||
stdout: ``,
|
||||
});
|
||||
await expect(runCli(cwd, [`yarn@stable`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: /Signature does not match/,
|
||||
stderr: expect.stringContaining(`Signature does not match`),
|
||||
stdout: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
it(`should return an error when hash does not match without a tag`, async () => {
|
||||
process.env.TEST_INTEGRITY = `invalid_integrity`; // See `_registryServer.mjs`
|
||||
process.env.COREPACK_DEFAULT_TO_LATEST = `1`; // Necessary as the version defined in `config.json` does not exist on the custom registry.
|
||||
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: /Mismatch hashes. Expected [a-f0-9]{128}, got [a-f0-9]{128}/,
|
||||
stderr: expect.stringMatching(/Mismatch hashes. Expected [a-f0-9]{128}, got [a-f0-9]{128}/),
|
||||
stdout: ``,
|
||||
});
|
||||
// A second time to validate the invalid version was not cached.
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: /Mismatch hashes. Expected [a-f0-9]{128}, got [a-f0-9]{128}/,
|
||||
stderr: expect.stringMatching(/Mismatch hashes. Expected [a-f0-9]{128}, got [a-f0-9]{128}/),
|
||||
stdout: ``,
|
||||
});
|
||||
await expect(runCli(cwd, [`yarn`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: /Mismatch hashes. Expected [a-f0-9]{128}, got [a-f0-9]{128}/,
|
||||
stderr: expect.stringMatching(/Mismatch hashes. Expected [a-f0-9]{128}, got [a-f0-9]{128}/),
|
||||
stdout: ``,
|
||||
});
|
||||
await expect(runCli(cwd, [`use`, `pnpm`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stdout: /Mismatch hashes. Expected [a-f0-9]{128}, got [a-f0-9]{128}/,
|
||||
stdout: expect.stringMatching(/Mismatch hashes. Expected [a-f0-9]{128}, got [a-f0-9]{128}/),
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
});
|
||||
it(`should return an error when signature does not match without a tag`, async () => {
|
||||
process.env.TEST_INTEGRITY = `invalid_signature`; // See `_registryServer.mjs`
|
||||
process.env.COREPACK_DEFAULT_TO_LATEST = `1`; // Necessary as the version defined in `config.json` does not exist on the custom registry.
|
||||
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: /Signature does not match/,
|
||||
stderr: expect.stringContaining(`Signature does not match`),
|
||||
stdout: ``,
|
||||
});
|
||||
// A second time to validate the invalid version was not cached.
|
||||
await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: /Signature does not match/,
|
||||
stderr: expect.stringContaining(`Signature does not match`),
|
||||
stdout: ``,
|
||||
});
|
||||
await expect(runCli(cwd, [`yarn`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: /Signature does not match/,
|
||||
stderr: expect.stringContaining(`Signature does not match`),
|
||||
stdout: ``,
|
||||
});
|
||||
await expect(runCli(cwd, [`use`, `pnpm`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stdout: /Signature does not match/,
|
||||
stdout: expect.stringContaining(`Signature does not match`),
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
|
@ -1093,12 +1664,12 @@ describe(`handle integrity checks`, () => {
|
|||
await xfs.mktempPromise(async cwd => {
|
||||
await expect(runCli(cwd, [`yarn@1.9998.9999`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: /Signature does not match/,
|
||||
stderr: expect.stringContaining(`Signature does not match`),
|
||||
stdout: ``,
|
||||
});
|
||||
await expect(runCli(cwd, [`use`, `yarn@1.9998.9999`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stdout: /Signature does not match/,
|
||||
stdout: expect.stringContaining(`Signature does not match`),
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
|
@ -1109,12 +1680,12 @@ describe(`handle integrity checks`, () => {
|
|||
await xfs.mktempPromise(async cwd => {
|
||||
await expect(runCli(cwd, [`yarn@1.9998.9999`, `--version`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stderr: /Mismatch hashes. Expected [a-f0-9]{128}, got [a-f0-9]{128}/,
|
||||
stderr: expect.stringMatching(/Mismatch hashes. Expected [a-f0-9]{128}, got [a-f0-9]{128}/),
|
||||
stdout: ``,
|
||||
});
|
||||
await expect(runCli(cwd, [`use`, `yarn@1.9998.9999`], true)).resolves.toMatchObject({
|
||||
exitCode: 1,
|
||||
stdout: /Mismatch hashes. Expected [a-f0-9]{128}, got [a-f0-9]{128}/,
|
||||
stdout: expect.stringMatching(/Mismatch hashes. Expected [a-f0-9]{128}, got [a-f0-9]{128}/),
|
||||
stderr: ``,
|
||||
});
|
||||
});
|
||||
|
|
BIN
tests/nocks.db
BIN
tests/nocks.db
Binary file not shown.
|
@ -6,7 +6,7 @@ const OLD_ENV = process.env;
|
|||
// in case the local machine already set these values.
|
||||
const processEnv = Object.fromEntries(
|
||||
Object.entries(process.env).filter(
|
||||
([key]) => key !== `FORCE_COLOR` && !key.startsWith(`COREPACK_`),
|
||||
([key]) => key !== `FORCE_COLOR` && key !== `DEBUG` && !key.startsWith(`COREPACK_`),
|
||||
),
|
||||
);
|
||||
|
||||
|
|
Loading…
Reference in New Issue