Files
pnpm/pnpm11/cache/commands/test/cacheList.cmd.test.ts
Zoltan Kochan 430d892741 feat(pnpr)!: serve every ecosystem under its own prefix (#17087)
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.
2026-10-18 16:55:55 +02:00

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/`)
})
})