pnpr served npm at the server root when npm was the only configured ecosystem and moved it under /npm/ as soon as a second ecosystem was added. Adding an ecosystem therefore broke every .npmrc registry URL, every tarball URL already written into a lockfile, named-registry URLs, and OIDC workload publish paths, and /npm meant the package `npm` on one server and the ecosystem prefix on another. This settles section A1 of pnpm/tasks#131: every ecosystem is always prefixed. - Ecosystem::base_path is now independent of the configuration. The per-configuration Registries::base_path and is_only_ecosystem are gone, and the routes, the resolver's tarball URLs, OIDC workload paths and pnpr's own-origin route classification all use it. - The default image registry still answers at /v2/ on the host root; an image client cannot be pointed at a prefix. The registry directory keeps its `prefixed` and `namedPrefixed` flags for the web UI. - The read-only token allowlist matched the npm audit endpoints at the root only, so read-only tokens were already refused for audits on multi-ecosystem servers. It now matches them under the npm prefix. - /metrics no longer switches between Prometheus metrics and the npm package `metrics` on the Accept header; the package is /npm/metrics. - The pnpm v11 and v12 test harnesses, the registry-mock crate and the integrated benchmark address the fixture registry at /npm/ and keep the server origin for the pnpr protocol endpoints. The benchmark asks each revision mock's registry directory whether npm is prefixed, so it can still compare against a pnpr revision from before this change.
106 lines
3.4 KiB
TypeScript
106 lines
3.4 KiB
TypeScript
import fs from 'node:fs'
|
|
import path from 'node:path'
|
|
|
|
import { beforeAll, describe, expect, test } from '@jest/globals'
|
|
import { cache } from '@pnpm/cache.commands'
|
|
import { ABBREVIATED_META_DIR } from '@pnpm/constants'
|
|
import { prepare } from '@pnpm/prepare'
|
|
import { REGISTRY_MOCK_PORT } from '@pnpm/testing.registry-mock'
|
|
import { rimrafSync } from '@zkochan/rimraf'
|
|
import { safeExeca as execa } from 'execa'
|
|
|
|
const pnpmBin = path.join(import.meta.dirname, '../../../pnpm/bin/pnpm.mjs')
|
|
const REGISTRY = `http://localhost:${REGISTRY_MOCK_PORT}/npm/`
|
|
|
|
describe('cache', () => {
|
|
let cacheDir: string
|
|
let storeDir: string
|
|
beforeAll(async () => {
|
|
prepare()
|
|
cacheDir = path.resolve('cache')
|
|
storeDir = path.resolve('store')
|
|
|
|
await execa('node', [
|
|
pnpmBin,
|
|
'add',
|
|
'is-negative@2.1.0',
|
|
`--store-dir=${storeDir}`,
|
|
`--cache-dir=${cacheDir}`,
|
|
'--config.resolution-mode=highest',
|
|
// The update check resolves `pnpm@latest` through the same cache, which
|
|
// would add a `pnpm.jsonl` entry to what these tests expect to find. It
|
|
// is off under CI, so leaving it on would only fail locally.
|
|
'--config.update-notifier=false',
|
|
`--registry=${REGISTRY}`,
|
|
])
|
|
rimrafSync('node_modules')
|
|
rimrafSync('pnpm-lock.yaml')
|
|
await execa('node', [
|
|
pnpmBin,
|
|
'add',
|
|
'is-negative@2.1.0',
|
|
'is-positive@1.0.0',
|
|
`--store-dir=${storeDir}`,
|
|
`--cache-dir=${cacheDir}`,
|
|
'--config.resolution-mode=highest',
|
|
'--config.update-notifier=false',
|
|
])
|
|
})
|
|
test('list all metadata from the cache', async () => {
|
|
const result = await cache.handler({
|
|
cacheDir,
|
|
cliOptions: {},
|
|
pnpmHomeDir: storeDir,
|
|
}, ['list'])
|
|
|
|
expect(result).toBe(`http%3A+localhost+${REGISTRY_MOCK_PORT}%2Fnpm/is-negative.jsonl
|
|
https%3A+registry.npmjs.org/is-negative.jsonl
|
|
https%3A+registry.npmjs.org/is-positive.jsonl`)
|
|
})
|
|
test('list all metadata from the cache related to the specified registry', async () => {
|
|
const result = await cache.handler({
|
|
cacheDir,
|
|
cliOptions: {
|
|
registry: 'https://registry.npmjs.org/',
|
|
},
|
|
pnpmHomeDir: storeDir,
|
|
}, ['list'])
|
|
|
|
expect(result).toBe(`https%3A+registry.npmjs.org/is-negative.jsonl
|
|
https%3A+registry.npmjs.org/is-positive.jsonl`)
|
|
})
|
|
test('list all metadata from the cache that matches a pattern', async () => {
|
|
const result = await cache.handler({
|
|
cacheDir,
|
|
cliOptions: {},
|
|
pnpmHomeDir: storeDir,
|
|
}, ['list', '*-positive'])
|
|
|
|
expect(result).toBe('https%3A+registry.npmjs.org/is-positive.jsonl')
|
|
})
|
|
test('list registries as decoded URLs, matching cache view', async () => {
|
|
const result = await cache.handler({
|
|
cacheDir,
|
|
cliOptions: {},
|
|
pnpmHomeDir: storeDir,
|
|
}, ['list-registries'])
|
|
|
|
expect(result).toBe(`http://localhost:${REGISTRY_MOCK_PORT}/npm/
|
|
https://registry.npmjs.org/`)
|
|
})
|
|
test('list registries skips stray files, as pnpm 12 does', async () => {
|
|
// A registry is a directory of `.jsonl` files. macOS drops a `.DS_Store`
|
|
// into any directory a user opens, which is not a registry.
|
|
fs.writeFileSync(path.join(cacheDir, ABBREVIATED_META_DIR, '.DS_Store'), '')
|
|
|
|
const result = await cache.handler({
|
|
cacheDir,
|
|
cliOptions: {},
|
|
pnpmHomeDir: storeDir,
|
|
}, ['list-registries'])
|
|
|
|
expect(result).toBe(`http://localhost:${REGISTRY_MOCK_PORT}/npm/
|
|
https://registry.npmjs.org/`)
|
|
})
|
|
})
|