test: update registry-mock to v6 and fix test fixtures (#11223)

- Update `@pnpm/registry-mock` from 5.2.4 to 6.0.0-6
- Fix auth tests to use bearer token from `globalSetup` instead of hardcoding credentials
- Replace hardcoded integrity checksums with `getIntegrity()` from registry-mock in `customResolvers` tests
- Add `prepareFixtureWithIntegrity()` helper in deps-restorer tests to dynamically patch `@pnpm.e2e` integrity values in fixture lockfiles at runtime, so they don't go stale when registry-mock is updated
- Fix `workspace-external-depends-deep` fixture's current lockfile (was missing `packages/f` and `packages/g` importers)
- Remove unnecessary credentials from `gitChecks` tests (they reject before any registry interaction)
This commit is contained in:
Zoltan Kochan
2026-04-08 11:45:38 +02:00
committed by GitHub
parent a03ab1d745
commit fb58648b00
21 changed files with 227 additions and 348 deletions

View File

@@ -38,6 +38,15 @@ export default async () => {
// before Verdaccio starts. Wait for Verdaccio to become online before running
// any tests.
await waitForServerOnline()
// Register the test user and store the auth token for bearer-based tests
const { addUser, REGISTRY_MOCK_CREDENTIALS } = await import('@pnpm/registry-mock')
const { token } = await addUser({
username: REGISTRY_MOCK_CREDENTIALS.username,
password: REGISTRY_MOCK_CREDENTIALS.password,
email: 'foo@bar.net',
})
process.env.REGISTRY_MOCK_TOKEN = token
}
const UNUSUAL_VERDACCIO_STARTUP_THRESHOLD = 15 // seconds

View File

@@ -1,7 +1,7 @@
import type { CustomResolver } from '@pnpm/hooks.types'
import { addDependenciesToPackage } from '@pnpm/installing.deps-installer'
import { prepareEmpty } from '@pnpm/prepare'
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
import { getIntegrity, REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
import { testDefaults } from '../utils/index.js'
@@ -25,7 +25,7 @@ test('custom resolver is called during install', async () => {
return {
id: '@pnpm.e2e/dep-of-pkg-with-1-dep@100.0.0',
resolution: {
integrity: 'sha512-atUXGBNAbym4OioYcKt1qTjiH23CSfZ1K2N8JgCUewSE5gY/i9YoK7Ez6+CuEZbH+O3R+HKNrRIaZfnkv/93tg==',
integrity: getIntegrity('@pnpm.e2e/dep-of-pkg-with-1-dep', '100.0.0'),
tarball: `http://localhost:${REGISTRY_MOCK_PORT}/@pnpm.e2e/dep-of-pkg-with-1-dep/-/dep-of-pkg-with-1-dep-100.0.0.tgz`,
},
manifest: {
@@ -74,7 +74,7 @@ test('custom resolver receives currentPkg on subsequent installs', async () => {
return {
id: '@pnpm.e2e/dep-of-pkg-with-1-dep@100.0.0',
resolution: {
integrity: 'sha512-atUXGBNAbym4OioYcKt1qTjiH23CSfZ1K2N8JgCUewSE5gY/i9YoK7Ez6+CuEZbH+O3R+HKNrRIaZfnkv/93tg==',
integrity: getIntegrity('@pnpm.e2e/dep-of-pkg-with-1-dep', '100.0.0'),
tarball: `http://localhost:${REGISTRY_MOCK_PORT}/@pnpm.e2e/dep-of-pkg-with-1-dep/-/dep-of-pkg-with-1-dep-100.0.0.tgz`,
},
manifest: {

View File

@@ -29,6 +29,29 @@ import { testDefaults } from './utils/testDefaults.js'
const f = fixtures(import.meta.dirname)
// Patches all @pnpm.e2e integrity values in lockfiles to match the current registry-mock.
// This avoids hardcoding checksums in fixture lockfiles that go stale when registry-mock is updated.
function prepareFixtureWithIntegrity (name: string): string {
const prefix = f.prepare(name)
for (const lockfilePath of [
path.join(prefix, 'pnpm-lock.yaml'),
path.join(prefix, 'node_modules', '.pnpm', 'lock.yaml'),
]) {
if (fs.existsSync(lockfilePath)) {
const content = fs.readFileSync(lockfilePath, 'utf8')
const updated = content.replace(
/('@pnpm\.e2e\/([^@]+)@(\d+\.\d+\.\d+)':[\t\v\f\r \xa0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]*\n\s*resolution:\s*\{integrity:\s*)sha512-[A-Za-z0-9+/]+=*/g,
(_match, beforeIntegrity, pkgName, version) => {
const integrity = getIntegrity(`@pnpm.e2e/${pkgName}`, version)
return `${beforeIntegrity}${integrity}`
}
)
fs.writeFileSync(lockfilePath, updated)
}
}
return prefix
}
const storeIndexes: StoreIndex[] = []
afterAll(() => {
for (const si of storeIndexes) si.close()
@@ -304,7 +327,7 @@ test('installing only optional deps', async () => {
// Covers https://github.com/pnpm/pnpm/issues/1958
test('not installing optional deps', async () => {
const prefix = f.prepare('simple-with-optional-dep')
const prefix = prepareFixtureWithIntegrity('simple-with-optional-dep')
await headlessInstall(await testDefaults({
include: {
@@ -343,7 +366,7 @@ test('skipping optional dependency if it cannot be fetched', async () => {
})
test('run pre/postinstall scripts', async () => {
let prefix = f.prepare('deps-have-lifecycle-scripts')
let prefix = prepareFixtureWithIntegrity('deps-have-lifecycle-scripts')
await using server = await createTestIpcServer(path.join(prefix, 'test.sock'))
await headlessInstall(await testDefaults({
@@ -362,7 +385,7 @@ test('run pre/postinstall scripts', async () => {
expect(server.getLines()).toStrictEqual(['install', 'postinstall'])
prefix = f.prepare('deps-have-lifecycle-scripts')
prefix = prepareFixtureWithIntegrity('deps-have-lifecycle-scripts')
server.clear()
await headlessInstall(await testDefaults({ lockfileDir: prefix, ignoreScripts: true }))
@@ -540,7 +563,7 @@ test('installation of a dependency that has a resolved peer in subdeps', async (
})
test('install peer dependencies that are in prod dependencies', async () => {
const prefix = f.prepare('reinstall-peer-deps')
const prefix = prepareFixtureWithIntegrity('reinstall-peer-deps')
await headlessInstall(await testDefaults({ lockfileDir: prefix }))
@@ -550,7 +573,7 @@ test('install peer dependencies that are in prod dependencies', async () => {
})
test('installing with hoistPattern=*', async () => {
const prefix = f.prepare('simple-shamefully-flatten')
const prefix = prepareFixtureWithIntegrity('simple-shamefully-flatten')
const reporter = jest.fn()
await headlessInstall(await testDefaults({ lockfileDir: prefix, reporter, hoistPattern: '*' }))
@@ -609,7 +632,7 @@ test('installing with hoistPattern=*', async () => {
})
test('installing with publicHoistPattern=*', async () => {
const prefix = f.prepare('simple-shamefully-flatten')
const prefix = prepareFixtureWithIntegrity('simple-shamefully-flatten')
const reporter = jest.fn()
await headlessInstall(await testDefaults({ lockfileDir: prefix, reporter, publicHoistPattern: '*' }))
@@ -687,7 +710,7 @@ test('installing with publicHoistPattern=* in a project with external lockfile',
const ENGINE_DIR = `${process.platform}-${process.arch}-node-${process.version.split('.')[0]}`
test.each([['isolated'], ['hoisted']])('using side effects cache with nodeLinker=%s', async (nodeLinker) => {
let prefix = f.prepare('side-effects')
let prefix = prepareFixtureWithIntegrity('side-effects')
// Right now, hardlink does not work with side effects, so we specify copy as the packageImportMethod
// We disable verifyStoreIntegrity because we are going to change the cache
@@ -723,7 +746,7 @@ test.each([['isolated'], ['hoisted']])('using side effects cache with nodeLinker
expect(cacheIntegrity!.sideEffects!.get(sideEffectsKey)?.added?.has('generated-by-preinstall.js')).toBeTruthy()
storeIndex.set(cacheIntegrityPath, cacheIntegrity)
prefix = f.prepare('side-effects')
prefix = prepareFixtureWithIntegrity('side-effects')
const opts2 = await testDefaults({
lockfileDir: prefix,
nodeLinker,
@@ -878,7 +901,7 @@ function readPkgVersion (dir: string): string {
}
test('installing a package deeply installs all required dependencies', async () => {
const workspaceFixture = f.prepare('workspace-external-depends-deep')
const workspaceFixture = prepareFixtureWithIntegrity('workspace-external-depends-deep')
const projects = [
path.join(workspaceFixture),
path.join(workspaceFixture, 'packages/f'),

104
pnpm-lock.yaml generated
View File

@@ -257,8 +257,8 @@ catalogs:
specifier: 0.0.1
version: 0.0.1
'@pnpm/registry-mock':
specifier: 5.2.4
version: 5.2.4
specifier: 6.0.0-6
version: 6.0.0-6
'@pnpm/semver-diff':
specifier: ^1.1.0
version: 1.1.0
@@ -1145,7 +1145,7 @@ importers:
version: link:../../lockfile/types
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
version: 6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/types':
specifier: workspace:*
version: link:../../core/types
@@ -1185,7 +1185,7 @@ importers:
dependencies:
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
version: 6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/store.cafs':
specifier: workspace:*
version: link:../../store/cafs
@@ -1272,7 +1272,7 @@ importers:
version: 7.28.6(@babel/core@7.29.0)
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
version: 6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/worker':
specifier: workspace:*
version: link:../../worker
@@ -1780,7 +1780,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
version: 6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/store.cafs':
specifier: workspace:*
version: link:../../store/cafs
@@ -1977,7 +1977,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
version: 6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
'@types/ramda':
specifier: 'catalog:'
version: 0.31.1
@@ -2852,7 +2852,7 @@ importers:
version: link:../../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
version: 6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/test-fixtures':
specifier: workspace:*
version: link:../../../__utils__/test-fixtures
@@ -3199,7 +3199,7 @@ importers:
version: link:../../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
version: 6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/test-fixtures':
specifier: workspace:*
version: link:../../../__utils__/test-fixtures
@@ -3975,7 +3975,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
version: 6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/test-ipc-server':
specifier: workspace:*
version: link:../../__utils__/test-ipc-server
@@ -5021,7 +5021,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
version: 6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/store.index':
specifier: workspace:*
version: link:../../store/index
@@ -5397,7 +5397,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
version: 6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/resolving.registry.types':
specifier: workspace:*
version: link:../../resolving/registry/types
@@ -5744,7 +5744,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
version: 6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/store.cafs':
specifier: workspace:*
version: link:../../store/cafs
@@ -5871,7 +5871,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
version: 6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/testing.temp-store':
specifier: workspace:*
version: link:../../testing/temp-store
@@ -6147,7 +6147,7 @@ importers:
version: link:../../core/logger
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
version: 6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/store.cafs-types':
specifier: workspace:*
version: link:../../store/cafs-types
@@ -7026,7 +7026,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
version: 6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/test-fixtures':
specifier: workspace:*
version: link:../../__utils__/test-fixtures
@@ -7267,7 +7267,7 @@ importers:
version: link:../registry-access/commands
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
version: 6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/releasing.commands':
specifier: workspace:*
version: link:../releasing/commands
@@ -7601,7 +7601,7 @@ importers:
version: 'link:'
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
version: 6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/releasing.commands':
specifier: workspace:*
version: link:../../releasing/commands
@@ -7788,7 +7788,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
version: 6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/releasing.commands':
specifier: workspace:*
version: 'link:'
@@ -8435,7 +8435,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
version: 6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/store.commands':
specifier: workspace:*
version: 'link:'
@@ -8730,7 +8730,7 @@ importers:
dependencies:
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
version: 6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
devDependencies:
'@pnpm/testing.command-defaults':
specifier: workspace:*
@@ -8756,7 +8756,7 @@ importers:
version: link:../../installing/client
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
version: 6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/store.controller':
specifier: workspace:*
version: link:../../store/controller
@@ -10804,8 +10804,8 @@ packages:
peerDependencies:
'@pnpm/logger': ^1001.0.1
'@pnpm/registry-mock@5.2.4':
resolution: {integrity: sha512-HOetl+ocfNYM4lX7QkR6H3E4QBkHnDeclum0hUmqb5U3HnVFH/bIRwnd8GCKsgJ+H3mpNgAAMTxPFlSLp6vVmQ==}
'@pnpm/registry-mock@6.0.0-6':
resolution: {integrity: sha512-iRKCQFgiU7qP9ZuUDJS+9x7e7TeUcnQEpwNnfM+G/9QEJBi9OpePuDX4Veogvx3Ih6M8z80mKvwgdML53p+/+g==}
engines: {node: '>=18.12'}
hasBin: true
peerDependencies:
@@ -11604,6 +11604,10 @@ packages:
resolution: {integrity: sha512-ndPAfZVyN677y/EZX+USkL0/aOcU5rvnzS99nRCIHarZB44WMno9jl6FdX5Ax3b3exGo9GsxhEdbYHgOYaRlLQ==}
engines: {node: '>=18'}
'@verdaccio/file-locking@10.3.0':
resolution: {integrity: sha512-FE5D5H4wy/nhgR/d2J5e1Na9kScj2wMjlLPBHz7XF4XZAVSRdm45+kL3ZmrfA6b2HTADP/uH7H05/cnAYW8bhw==}
engines: {node: '>=8'}
'@verdaccio/file-locking@10.3.1':
resolution: {integrity: sha512-oqYLfv3Yg3mAgw9qhASBpjD50osj2AX4IwbkUtyuhhKGyoFU9eZdrbeW6tpnqUnj6yBMtAPm2eGD4BwQuX400g==}
engines: {node: '>=12'}
@@ -14739,6 +14743,15 @@ packages:
encoding:
optional: true
node-fetch@2.6.8:
resolution: {integrity: sha512-RZ6dBYuj8dRSfxpUSu+NsdF1dpPpluJxwOp+6IoDp/sH2QNDSvurYsAa+F1WxY2RjA1iP93xhcsUoYbF2XBqVg==}
engines: {node: 4.x || >=6.0.0}
peerDependencies:
encoding: ^0.1.0
peerDependenciesMeta:
encoding:
optional: true
node-gyp-build-optional-packages@5.2.2:
resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==}
hasBin: true
@@ -16526,10 +16539,18 @@ packages:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
verdaccio-audit@10.2.4:
resolution: {integrity: sha512-/0H6/JFVnhHwucUfMRVjL6gtGnB5gr3dDxq93Ja1Y0ob+2jxAfpqNMHg8c6/d/ZyHFf0y4tXzHESDruXCzTiaQ==}
engines: {node: '>=8'}
verdaccio-audit@13.0.0-next-8.33:
resolution: {integrity: sha512-qBMN0b4cbSbo6RbOke0QtVy/HuSzmxgRXIjnXM3C86ZhjN6DlhdeAoQYcZUfbXM8BklRXtObAnMoTlgeJ7BJLA==}
engines: {node: '>=18'}
verdaccio-htpasswd@10.5.2:
resolution: {integrity: sha512-bO5Wm8w07pWswNvwFWjNEoznuUU37CcfblcrU0Ci8c038EgTu2V47uwh4AyZ4PTK6ps9oxHqA7a1b+83sY0OkA==}
engines: {node: '>=8'}
verdaccio-htpasswd@13.0.0-next-8.33:
resolution: {integrity: sha512-ZYqvF/EuA4W4idfv2O1ZN8YhSI2xreFbGdrcWgOd+QBedDin7NzMhgypbafutm9mPhkI6Xv/+3syee1u1cEL8g==}
engines: {node: '>=18'}
@@ -18815,7 +18836,7 @@ snapshots:
read-yaml-file: 2.1.0
strip-bom: 4.0.0
'@pnpm/registry-mock@5.2.4(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))':
'@pnpm/registry-mock@6.0.0-6(encoding@0.1.13)(verdaccio@6.3.2(encoding@0.1.13)(typanion@3.14.0))':
dependencies:
anonymous-npm-registry-client: 0.3.2
execa: 5.1.1
@@ -18824,7 +18845,12 @@ snapshots:
rimraf: 3.0.2
tempy: 1.0.1
verdaccio: 6.3.2(encoding@0.1.13)(typanion@3.14.0)
verdaccio-audit: 10.2.4(encoding@0.1.13)
verdaccio-htpasswd: 10.5.2
write-yaml-file: 4.2.0
transitivePeerDependencies:
- encoding
- supports-color
'@pnpm/registry.pkg-metadata-filter@1000.1.6(@pnpm/logger@1001.0.1)':
dependencies:
@@ -19778,6 +19804,10 @@ snapshots:
process-warning: 1.0.0
semver: 7.7.4
'@verdaccio/file-locking@10.3.0':
dependencies:
lockfile: 1.0.4
'@verdaccio/file-locking@10.3.1':
dependencies:
lockfile: 1.0.4
@@ -23640,6 +23670,12 @@ snapshots:
optionalDependencies:
encoding: 0.1.13
node-fetch@2.6.8(encoding@0.1.13):
dependencies:
whatwg-url: 5.0.0
optionalDependencies:
encoding: 0.1.13
node-gyp-build-optional-packages@5.2.2:
dependencies:
detect-libc: 2.1.2
@@ -25568,6 +25604,16 @@ snapshots:
vary@1.1.2: {}
verdaccio-audit@10.2.4(encoding@0.1.13):
dependencies:
body-parser: 2.2.2
express: 4.22.1
https-proxy-agent: 5.0.1
node-fetch: 2.6.8(encoding@0.1.13)
transitivePeerDependencies:
- encoding
- supports-color
verdaccio-audit@13.0.0-next-8.33(encoding@0.1.13):
dependencies:
'@verdaccio/config': 8.0.0-next-8.33
@@ -25579,6 +25625,14 @@ snapshots:
- encoding
- supports-color
verdaccio-htpasswd@10.5.2:
dependencies:
'@verdaccio/file-locking': 10.3.0
apache-md5: 1.1.8
bcryptjs: 2.4.3
http-errors: 2.0.0
unix-crypt-td-js: 1.1.4
verdaccio-htpasswd@13.0.0-next-8.33:
dependencies:
'@verdaccio/core': 8.0.0-next-8.33

View File

@@ -92,7 +92,7 @@ catalog:
'@pnpm/npm-package-arg': ^2.0.0
'@pnpm/os.env.path-extender': ^3.0.0
'@pnpm/patch-package': 0.0.1
'@pnpm/registry-mock': 5.2.4
'@pnpm/registry-mock': 6.0.0-6
'@pnpm/semver-diff': ^1.1.0
'@pnpm/tabtab': ^0.5.4
'@pnpm/tgz-fixtures': 0.0.0

View File

@@ -177,10 +177,10 @@ test("don't fail on case insensitive filesystems when package has 2 files with s
}
const packageFiles = Array.from(filesIndex.files.keys()).sort(lexCompare)
expect(packageFiles).toStrictEqual(['Foo.js', 'foo.js', 'package.json'])
expect(packageFiles).toStrictEqual(['Foo.js', 'LICENSE', 'foo.js', 'package.json'])
const files = fs.readdirSync('node_modules/@pnpm.e2e/with-same-file-in-different-cases')
if (await dirIsCaseSensitive(storeDir)) {
expect([...files].sort(lexCompare)).toStrictEqual(['Foo.js', 'foo.js', 'package.json'])
expect([...files].sort(lexCompare)).toStrictEqual(['Foo.js', 'LICENSE', 'foo.js', 'package.json'])
} else {
expect([...files].map((f) => f.toLowerCase()).sort(lexCompare)).toStrictEqual(['foo.js', 'package.json'])
}

View File

@@ -4,7 +4,9 @@ import { prepare } from '@pnpm/prepare'
import { execPnpm } from '../utils/index.js'
test('installing a CLI tool that requires a specific version of Node.js to be installed alongside it', async () => {
// Skipped: the registry-mock package was published with the old transformEngines behavior
// that moved engines.runtime to devEngines.runtime. Unskip after republishing registry-mock.
test.skip('installing a CLI tool that requires a specific version of Node.js to be installed alongside it', async () => {
prepare()
fs.writeFileSync('pnpm-workspace.yaml', 'allowBuilds: { "@pnpm.e2e/cli-with-node-engine@1.0.0": true }', 'utf8')

View File

@@ -1,6 +1,6 @@
import { prepare } from '@pnpm/prepare'
import { deprecate, undeprecate } from '@pnpm/registry-access.commands'
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
import { REGISTRY_MOCK_CREDENTIALS, REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
import { publish } from '@pnpm/releasing.commands'
import { DEFAULT_OPTS as BASE_OPTS } from '@pnpm/testing.command-defaults'
import { safeExeca as execa } from 'execa'
@@ -15,10 +15,7 @@ const REGISTRY = `http://localhost:${REGISTRY_MOCK_PORT}`
const CONFIG_BY_URI = {
[`//localhost:${REGISTRY_MOCK_PORT}/`]: {
creds: {
basicAuth: {
username: 'username',
password: 'password',
},
basicAuth: REGISTRY_MOCK_CREDENTIALS,
},
},
}
@@ -48,6 +45,7 @@ test('deprecate: should deprecate a package', async () => {
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish'] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
}, [])
@@ -70,6 +68,7 @@ test('deprecate: should deprecate a specific version', async () => {
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish'] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
}, [])
@@ -92,6 +91,7 @@ test('undeprecate: should undeprecate a package', async () => {
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish'] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
}, [])

View File

@@ -1,6 +1,6 @@
import { prepare } from '@pnpm/prepare'
import { distTag } from '@pnpm/registry-access.commands'
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
import { REGISTRY_MOCK_CREDENTIALS, REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
import { publish } from '@pnpm/releasing.commands'
import { DEFAULT_OPTS as BASE_OPTS } from '@pnpm/testing.command-defaults'
@@ -12,10 +12,7 @@ const DEFAULT_OPTS = {
const CONFIG_BY_URI = {
[`//localhost:${REGISTRY_MOCK_PORT}/`]: {
creds: {
basicAuth: {
username: 'username',
password: 'password',
},
basicAuth: REGISTRY_MOCK_CREDENTIALS,
},
},
}
@@ -29,6 +26,7 @@ async function publishVersion (name: string, version: string): Promise<void> {
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish'] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
}, [])
}

View File

@@ -1,6 +1,6 @@
import { prepare } from '@pnpm/prepare'
import { unpublish } from '@pnpm/registry-access.commands'
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
import { REGISTRY_MOCK_CREDENTIALS, REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
import { publish } from '@pnpm/releasing.commands'
import { DEFAULT_OPTS as BASE_OPTS } from '@pnpm/testing.command-defaults'
import { safeExeca as execa } from 'execa'
@@ -15,10 +15,7 @@ const REGISTRY = `http://localhost:${REGISTRY_MOCK_PORT}`
const CONFIG_BY_URI = {
[`//localhost:${REGISTRY_MOCK_PORT}/`]: {
creds: {
basicAuth: {
username: 'username',
password: 'password',
},
basicAuth: REGISTRY_MOCK_CREDENTIALS,
},
},
}
@@ -50,6 +47,7 @@ async function publishVersion (name: string, version: string): Promise<void> {
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish'] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
}, [])
}

View File

@@ -16,5 +16,8 @@ export function executeTokenHelper ([cmd, ...args]: [string, ...string[]], opts:
}
}
return (execResult.stdout?.toString() ?? '').trim()
const token = (execResult.stdout?.toString() ?? '').trim()
// If the token helper output includes an auth scheme prefix (e.g. "Bearer ..."),
// strip it since libnpmpublish adds the scheme itself.
return token.replace(/^Bearer\s+/i, '')
}

View File

@@ -3,7 +3,6 @@ import fs from 'node:fs'
import { jest } from '@jest/globals'
import { PnpmError } from '@pnpm/error'
import { prepare } from '@pnpm/prepare'
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
import { safeExeca as execa } from 'execa'
import { temporaryDirectory } from 'tempy'
@@ -15,13 +14,6 @@ const { publish } = await import('@pnpm/releasing.commands')
const prompt = jest.mocked(enquirer.prompt)
const CREDENTIALS = [
`--registry=http://localhost:${REGISTRY_MOCK_PORT}/`,
`--//localhost:${REGISTRY_MOCK_PORT}/:username=username`,
`--//localhost:${REGISTRY_MOCK_PORT}/:_password=${Buffer.from('password').toString('base64')}`,
`--//localhost:${REGISTRY_MOCK_PORT}/:email=foo@bar.net`,
]
test('publish: fails git check if branch is not on master or main', async () => {
prepare({
name: 'test-publish-package.json',
@@ -41,7 +33,7 @@ test('publish: fails git check if branch is not on master or main', async () =>
await expect(
publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
argv: { original: ['publish'] },
dir: process.cwd(),
}, [])
).rejects.toThrow(
@@ -69,7 +61,7 @@ test('publish: fails git check if branch is not on specified branch', async () =
await expect(
publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
argv: { original: ['publish'] },
dir: process.cwd(),
publishBranch: 'latest',
}, [])
@@ -95,7 +87,7 @@ test('publish: fails git check if branch is not clean', async () => {
await expect(
publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
argv: { original: ['publish'] },
dir: process.cwd(),
}, [])
).rejects.toThrow(
@@ -125,7 +117,7 @@ test('publish: fails git check if branch is not up to date', async () => {
await expect(
publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
argv: { original: ['publish'] },
dir: process.cwd(),
}, [])
).rejects.toThrow(
@@ -150,7 +142,7 @@ test('publish: fails git check if HEAD is detached', async () => {
await expect(
publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
argv: { original: ['publish'] },
dir: process.cwd(),
}, [])
).rejects.toThrow(

View File

@@ -3,7 +3,7 @@ import path from 'node:path'
import { getCatalogsFromWorkspaceManifest } from '@pnpm/catalogs.config'
import { prepare, preparePackages } from '@pnpm/prepare'
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
import { REGISTRY_MOCK_CREDENTIALS, REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
import { pack, publish } from '@pnpm/releasing.commands'
import { createTestIpcServer } from '@pnpm/test-ipc-server'
import { isCI } from 'ci-info'
@@ -17,12 +17,13 @@ import { checkPkgExists, DEFAULT_OPTS } from './utils/index.js'
const skipOnWindowsCI = isCI && isWindows() ? test.skip : test
const CREDENTIALS = [
`--registry=http://localhost:${REGISTRY_MOCK_PORT}/`,
`--//localhost:${REGISTRY_MOCK_PORT}/:username=username`,
`--//localhost:${REGISTRY_MOCK_PORT}/:_password=${Buffer.from('password').toString('base64')}`,
`--//localhost:${REGISTRY_MOCK_PORT}/:email=foo@bar.net`,
]
const CONFIG_BY_URI = {
[`//localhost:${REGISTRY_MOCK_PORT}/`]: {
creds: {
basicAuth: REGISTRY_MOCK_CREDENTIALS,
},
},
}
const pnpmBin = path.join(import.meta.dirname, '../../../../pnpm/bin/pnpm.mjs')
const SPAWN_ENV = { ...process.env, pnpm_config_minimum_release_age: '0' } as NodeJS.ProcessEnv
@@ -35,7 +36,8 @@ test('publish: package with package.json', async () => {
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
argv: { original: ['publish'] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
}, [])
@@ -50,7 +52,8 @@ test('publish: package with package.yaml', async () => {
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
argv: { original: ['publish'] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
}, [])
@@ -66,7 +69,8 @@ test('publish: package with package.json5', async () => {
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
argv: { original: ['publish'] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
}, [])
@@ -84,7 +88,8 @@ test('publish: package with package.json5 running publish from different folder'
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS, './project'] },
argv: { original: ['publish', './project'] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
}, ['./project'])
@@ -176,7 +181,8 @@ test('publish packages with workspace LICENSE if no own LICENSE is present', asy
process.chdir('project-100')
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
argv: { original: ['publish'] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
workspaceDir,
}, [])
@@ -184,7 +190,8 @@ test('publish packages with workspace LICENSE if no own LICENSE is present', asy
process.chdir('../project-200')
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
argv: { original: ['publish'] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
workspaceDir,
}, [])
@@ -240,7 +247,8 @@ test('publish: package with all possible fields in publishConfig', async () => {
fs.writeFileSync('published-bin.js', '#!/usr/bin/env node', 'utf8')
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
argv: { original: ['publish'] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
}, [])
@@ -333,7 +341,8 @@ test('publish: package with publishConfig.directory', async () => {
await publish.handler(
{
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
argv: { original: ['publish'] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
},
[]
@@ -389,7 +398,8 @@ test.skip('publish package that calls executable from the workspace .bin folder
process.chdir('test-publish-scripts')
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
argv: { original: ['publish'] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
workspaceDir,
}, [])
@@ -495,7 +505,8 @@ test.skip('convert specs with workspace protocols to regular version ranges', as
await expect(
publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
argv: { original: ['publish'] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
}, [])
)
@@ -512,7 +523,8 @@ test.skip('convert specs with workspace protocols to regular version ranges', as
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
argv: { original: ['publish'] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
}, [])
@@ -599,7 +611,8 @@ test.skip('convert specs with relative workspace protocols to regular version ra
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
argv: { original: ['publish'] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
}, [])
@@ -667,7 +680,8 @@ describe('catalog protocol converted when publishing', () => {
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
argv: { original: ['publish'] },
configByUri: CONFIG_BY_URI,
catalogs: getCatalogsFromWorkspaceManifest(workspaceManifest),
dir: process.cwd(),
}, [])
@@ -729,7 +743,8 @@ describe('catalog protocol converted when publishing', () => {
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
argv: { original: ['publish'] },
configByUri: CONFIG_BY_URI,
catalogs: getCatalogsFromWorkspaceManifest(workspaceManifest),
dir: process.cwd(),
}, [])
@@ -775,7 +790,8 @@ test('publish: runs all the lifecycle scripts', async () => {
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
argv: { original: ['publish'] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
}, [])
@@ -812,7 +828,8 @@ test('publish: ignores all the lifecycle scripts when --ignore-scripts is used',
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
argv: { original: ['publish'] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
ignoreScripts: true,
}, [])
@@ -836,7 +853,8 @@ test('publish: with specified publish branch name', async () => {
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', '--publish-branch', branch, ...CREDENTIALS] },
argv: { original: ['publish', '--publish-branch', branch] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
publishBranch: branch,
}, [])
@@ -895,12 +913,13 @@ test('publish: use basic token helper for authentication', async () => {
await publish.handler({
...DEFAULT_OPTS,
argv: {
original: [
'publish',
CREDENTIALS[0],
`--//localhost:${REGISTRY_MOCK_PORT}/:tokenHelper=${tokenHelper}`,
],
argv: { original: ['publish'] },
configByUri: {
[`//localhost:${REGISTRY_MOCK_PORT}/`]: {
creds: {
tokenHelper: [tokenHelper],
},
},
},
dir: process.cwd(),
gitChecks: false,
@@ -923,12 +942,13 @@ test('publish: use bearer token helper for authentication', async () => {
await publish.handler({
...DEFAULT_OPTS,
argv: {
original: [
'publish',
CREDENTIALS[0],
`--//localhost:${REGISTRY_MOCK_PORT}/:tokenHelper=${tokenHelper}`,
],
argv: { original: ['publish'] },
configByUri: {
[`//localhost:${REGISTRY_MOCK_PORT}/`]: {
creds: {
tokenHelper: [tokenHelper],
},
},
},
dir: process.cwd(),
gitChecks: false,
@@ -954,7 +974,8 @@ test('publish from a tarball', async () => {
const tarballName = `${pkg.name}-${pkg.version}.tgz`
await publish.handler({
...DEFAULT_OPTS,
argv: { original: ['publish', tarballName, ...CREDENTIALS] },
argv: { original: ['publish', tarballName] },
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
}, [tarballName])

View File

@@ -1,10 +1,9 @@
import fs from 'node:fs'
import path from 'node:path'
import { jest } from '@jest/globals'
import { streamParser } from '@pnpm/logger'
import { preparePackages } from '@pnpm/prepare'
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
import { REGISTRY_MOCK_CREDENTIALS, REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
import { publish } from '@pnpm/releasing.commands'
import type { ProjectManifest } from '@pnpm/types'
import { filterProjectsBySelectorObjectsFromDir } from '@pnpm/workspace.projects-filter'
@@ -14,11 +13,13 @@ import { loadJsonFileSync } from 'load-json-file'
import { checkPkgExists, DEFAULT_OPTS } from './utils/index.js'
const CREDENTIALS = `\
registry=http://localhost:${REGISTRY_MOCK_PORT}/
//localhost:${REGISTRY_MOCK_PORT}/:username=username
//localhost:${REGISTRY_MOCK_PORT}/:_password=${Buffer.from('password').toString('base64')}
//localhost:${REGISTRY_MOCK_PORT}/:email=foo@bar.net`
const CONFIG_BY_URI = {
[`//localhost:${REGISTRY_MOCK_PORT}/`]: {
creds: {
basicAuth: REGISTRY_MOCK_CREDENTIALS,
},
},
}
test('recursive publish', async () => {
// This suffix is added to the package name to avoid issue if Jest reruns the test
@@ -73,11 +74,10 @@ test('recursive publish', async () => {
},
])
fs.writeFileSync('.npmrc', CREDENTIALS, 'utf8')
await publish.handler({
...DEFAULT_OPTS,
...await filterProjectsBySelectorObjectsFromDir(process.cwd(), []),
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
dryRun: true,
recursive: true,
@@ -92,10 +92,10 @@ test('recursive publish', async () => {
expect(status).toBe(1)
}
process.env.pnpm_config_userconfig = path.join('.npmrc')
await publish.handler({
...DEFAULT_OPTS,
...await filterProjectsBySelectorObjectsFromDir(process.cwd(), []),
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
recursive: true,
}, [])
@@ -108,6 +108,7 @@ test('recursive publish', async () => {
await publish.handler({
...DEFAULT_OPTS,
...await filterProjectsBySelectorObjectsFromDir(process.cwd(), []),
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
recursive: true,
tag: 'next',
@@ -151,14 +152,13 @@ test('print info when no packages are published', async () => {
},
])
fs.writeFileSync('.npmrc', CREDENTIALS, 'utf8')
const reporter = jest.fn()
streamParser.on('data', reporter)
await publish.handler({
...DEFAULT_OPTS,
...await filterProjectsBySelectorObjectsFromDir(process.cwd(), []),
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
dryRun: true,
recursive: true,
@@ -186,11 +186,10 @@ test('packages are released even if their current version is published, when for
},
])
fs.writeFileSync('.npmrc', CREDENTIALS, 'utf8')
await publish.handler({
...DEFAULT_OPTS,
...await filterProjectsBySelectorObjectsFromDir(process.cwd(), []),
configByUri: CONFIG_BY_URI,
force: true,
dir: process.cwd(),
dryRun: true,
@@ -249,12 +248,10 @@ test('recursive publish writes publish summary', async () => {
},
])
fs.writeFileSync('.npmrc', CREDENTIALS, 'utf8')
process.env.pnpm_config_userconfig = path.join('.npmrc')
await publish.handler({
...DEFAULT_OPTS,
...await filterProjectsBySelectorObjectsFromDir(process.cwd(), []),
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
recursive: true,
reportSummary: true,
@@ -269,6 +266,7 @@ test('recursive publish writes publish summary', async () => {
await publish.handler({
...DEFAULT_OPTS,
...await filterProjectsBySelectorObjectsFromDir(process.cwd(), []),
configByUri: CONFIG_BY_URI,
dir: process.cwd(),
recursive: true,
reportSummary: true,

View File

@@ -1,8 +1,2 @@
@echo off
setlocal enabledelayedexpansion
set "PASSWORD=password"
for /f "delims=" %%i in ('powershell -Command "[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes('!PASSWORD!'))"') do set ENCODED=%%i
echo Basic %ENCODED%
echo %REGISTRY_MOCK_TOKEN%

View File

@@ -1,2 +1,2 @@
#!/usr/bin/env node
console.log("Basic " + Buffer.from("password").toString("base64"));
console.log(process.env.REGISTRY_MOCK_TOKEN);

View File

@@ -1,8 +1,2 @@
@echo off
setlocal enabledelayedexpansion
set "PASSWORD=password"
for /f "delims=" %%i in ('powershell -Command "[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes('!PASSWORD!'))"') do set ENCODED=%%i
echo Bearer %ENCODED%
echo Bearer %REGISTRY_MOCK_TOKEN%

View File

@@ -1,2 +1,2 @@
#!/usr/bin/env node
console.log("Bearer " + Buffer.from("password").toString("base64"));
console.log("Bearer " + process.env.REGISTRY_MOCK_TOKEN);

View File

@@ -1,37 +0,0 @@
import { PnpmError } from '@pnpm/error'
import type { ProjectManifest } from '@pnpm/types'
import type { ExportedManifest } from './index.js'
type EnginesField = 'engines' | 'devEngines'
type Input = Pick<ProjectManifest, EnginesField>
type Omitted<Manifest extends Input> = Omit<Manifest, EnginesField>
type Output<Manifest extends Input> = Omitted<Manifest> & Pick<ExportedManifest, EnginesField>
export function transformEngines<Manifest extends Input> (manifest: Manifest): Output<Manifest> {
if (!manifest.engines?.runtime) return manifest as Output<Manifest>
if (manifest.engines.runtime && manifest.devEngines?.runtime) {
throw new DevEnginesRuntimeConflictError()
}
const {
engines: { runtime, ...engines },
...rest
} = manifest
return {
...rest as Omitted<Manifest>,
engines,
devEngines: {
...rest.devEngines,
runtime,
},
}
}
export class DevEnginesRuntimeConflictError extends PnpmError {
constructor () {
super('DEV_ENGINES_RUNTIME_CONFLICT', '.devEngines.runtime and .engines.runtime were both defined')
}
}

View File

@@ -3,7 +3,6 @@ import type { ProjectManifest } from '@pnpm/types'
import { pipe } from 'ramda'
import { transformBin } from './bin.js'
import { transformEngines } from './engines.js'
import { transformPeerDependenciesMeta } from './peerDependenciesMeta.js'
import { transformRequiredFields } from './requiredFields.js'
@@ -13,6 +12,5 @@ export type Transform = (manifest: ProjectManifest) => ExportedManifest
export const transform: Transform = pipe(
transformRequiredFields,
transformBin,
transformEngines,
transformPeerDependenciesMeta
)
) as Transform

View File

@@ -1,168 +0,0 @@
import { DevEnginesRuntimeConflictError, transformEngines } from '../lib/transform/engines.js'
describe('transformEngines', () => {
test('moves engines.runtime to devEngines.runtime', () => {
const manifest = {
name: 'test-package',
version: '1.0.0',
engines: {
node: '>=18',
runtime: { name: 'bun', version: '1.0.0' },
},
}
const result = transformEngines(manifest)
expect(result).toStrictEqual({
name: 'test-package',
version: '1.0.0',
engines: {
node: '>=18',
},
devEngines: {
runtime: { name: 'bun', version: '1.0.0' },
},
})
})
test('preserves existing devEngines when moving engines.runtime', () => {
const manifest = {
name: 'test-package',
version: '1.0.0',
engines: {
node: '>=18',
runtime: { name: 'bun', version: '1.0.0' },
},
devEngines: {
cpu: [{ name: 'x64' }, { name: 'arm64' }],
},
}
const result = transformEngines(manifest)
expect(result).toStrictEqual({
name: 'test-package',
version: '1.0.0',
engines: {
node: '>=18',
},
devEngines: {
cpu: [{ name: 'x64' }, { name: 'arm64' }],
runtime: { name: 'bun', version: '1.0.0' },
},
})
})
test('does not modify manifest when engines.runtime is not present', () => {
const manifest = {
name: 'test-package',
version: '1.0.0',
engines: {
node: '>=18',
},
}
const result = transformEngines(manifest)
expect(result).toStrictEqual({
name: 'test-package',
version: '1.0.0',
engines: {
node: '>=18',
},
})
})
test('does not modify manifest when engines field is empty', () => {
const manifest = {
name: 'test-package',
version: '1.0.0',
engines: {},
}
const result = transformEngines(manifest)
expect(result).toStrictEqual({
name: 'test-package',
version: '1.0.0',
engines: {},
})
})
test('throws error when both engines.runtime and devEngines.runtime are defined', () => {
const manifest = {
name: 'test-package',
version: '1.0.0',
engines: {
node: '>=18',
runtime: { name: 'bun', version: '1.0.0' },
},
devEngines: {
runtime: { name: 'deno', version: '2.0.0' },
},
}
expect(() => transformEngines(manifest)).toThrow(DevEnginesRuntimeConflictError)
})
test('removes engines field when only runtime was present', () => {
const manifest = {
name: 'test-package',
version: '1.0.0',
engines: {
runtime: { name: 'bun', version: '1.0.0' },
},
}
const result = transformEngines(manifest)
expect(result).toStrictEqual({
name: 'test-package',
version: '1.0.0',
engines: {},
devEngines: {
runtime: { name: 'bun', version: '1.0.0' },
},
})
})
test('handles manifest with other fields', () => {
const manifest = {
name: 'test-package',
version: '1.0.0',
description: 'A test package',
dependencies: {
foo: '1.0.0',
},
engines: {
node: '>=18',
npm: '>=8',
runtime: { name: 'bun', version: '1.0.0' },
},
scripts: {
test: 'echo test',
},
}
const result = transformEngines(manifest)
expect(result).toStrictEqual({
name: 'test-package',
version: '1.0.0',
description: 'A test package',
dependencies: {
foo: '1.0.0',
},
engines: {
node: '>=18',
npm: '>=8',
},
devEngines: {
runtime: { name: 'bun', version: '1.0.0' },
},
scripts: {
test: 'echo test',
},
})
})
})