mirror of
https://github.com/pnpm/pnpm.git
synced 2025-12-23 23:29:17 -05:00
* feat(cli/config)!: breaking changes * refactor(test): remove `deepNullProto` and reuse `getOutputString` * feat(cli/config/list): censor protected settings * test: censorship of protected settings * docs(changeset): censorship of protected settings * fix: eslint * feat(config)!: exclude non-option from `rawConfig` * fix: eslint * refactor: move default registries to builtin (#9886) * feat(config)!: filter rc settings * feat(config): don't exclude non-options This reverts commita79f72dbfb. * feat(cli/config/get)!: print array as json * test: fix * docs(changeset): correct * test: fix * feat(cli/config)!: only kebabize option fields (wip) * chore(git): revert the implementation This reverts commit529f9bdd47. * test: restore This reverts commitd8191e0ed8. * feat(cli/config)!: only kebabize option fields (wip) * feat: use `types` instead * feat(cli/config/get)!: only kebabize rc fields * test: add * test: non-rc kebab-case keys * test: correct * docs(changeset): correct * docs(changeset): style * docs(changeset): correct * test: only kebabize rc fields * fix: import path * fix: eslint * fix: `isCamelCase` * feat(cli/config/set)!: forbid unknown rc fields * test: fix existing test * test: refuse unsupported rc settings * feat: hint * feat(cli/config/set)!: refuse kebab-case workspace-specific settings * feat(config)!: ignore non-camelCase from `pnpm-workspace.yaml` * test: config get * test: config list * refactor: extract shared code into its own package * test: `isCamelCase` * feat(cli/config/list)!: consistent naming cases * refactor: make it more reusable * feat(cli/config/get)!: consistent naming cases * feat(cli/config/get): censor protected settings * test: `get ''` should be the same as `list` * docs(test): quotation marks * refactor: remove unnecessary `test.each` * docs(changeset): case changes * test: unknown keys * docs(changeset): correct * docs(changeset): non camelCase from `pnpm-workspace.yaml` * fix: eslint * docs(changeset): correct terminology * docs(changeset): clarify * feat!: do not load non-auth and non-registry * fix: implementation * test: no hidden settings * fix: eslint * fix: do not drop default values * test: fix * test: remove irrelevant tests * test: fix (wip) * fix: auth * test: skip an inapplicable test * test: temporary skip a test * test: fix 'respects testPattern' * test: fix 'respects changedFilesIgnorePattern' * test: fix 'changedFilesIgnorePattern is respected' * test: rename a test * test: fix `package-lock=false` * feat: exception for `managePackageManagerVersions` * test: `managePackageManagerVersions: false` * test: fix (wip) * test: workaround * fix: default `optional` to `true` * fix: `filter` on `pnpm-workspace.yaml` * test: fix * test: disable ones that no longer apply * chore(git): revert incorrect change * fix: `filter` on `pnpm-workspace.yaml` (#10127) * fix: `filter` on `pnpm-workspace.yaml` * docs: changeset * fix: actual fix * fix: don't set default on config * docs(readme): correct a package description * fix: typo * test: fix * test: use a field that wouldn't be ignored * test: replace some `.npmrc` with `pnpm-workspace.yaml` * docs(changeset): less awkward wordings * docs(changeset): correction
255 lines
9.9 KiB
TypeScript
255 lines
9.9 KiB
TypeScript
import fs from 'fs'
|
|
import path from 'path'
|
|
import { preparePackages } from '@pnpm/prepare'
|
|
import { fixtures } from '@pnpm/test-fixtures'
|
|
import { sync as writeYamlFile } from 'write-yaml-file'
|
|
import { execPnpm } from './utils/index.js'
|
|
|
|
const f = fixtures(import.meta.dirname)
|
|
|
|
const PKG_FILES = [
|
|
...fs.readdirSync(f.find('injected-dep-files')),
|
|
'package.json',
|
|
].sort()
|
|
|
|
function prepareInjectedDepsWorkspace (syncInjectedDepsAfterScripts: string[]) {
|
|
const scripts = {
|
|
build1: 'node ./build1.cjs',
|
|
build2: 'node ./build2.cjs',
|
|
build3: 'node ./build3.cjs',
|
|
}
|
|
preparePackages([
|
|
{
|
|
name: 'foo',
|
|
version: '0.0.0',
|
|
dependencies: {
|
|
'is-positive': '1.0.0',
|
|
},
|
|
scripts,
|
|
},
|
|
{
|
|
name: 'bar',
|
|
version: '0.0.0',
|
|
dependencies: {
|
|
foo: 'workspace:*',
|
|
},
|
|
scripts,
|
|
},
|
|
{
|
|
name: 'baz',
|
|
version: '0.0.0',
|
|
dependencies: {
|
|
bar: 'workspace:*',
|
|
},
|
|
scripts,
|
|
},
|
|
])
|
|
|
|
for (const pkgName of ['foo', 'bar', 'baz']) {
|
|
f.copy('injected-dep-files', pkgName)
|
|
}
|
|
|
|
writeYamlFile('pnpm-workspace.yaml', {
|
|
packages: ['*'],
|
|
reporter: 'append-only',
|
|
injectWorkspacePackages: true,
|
|
dedupeInjectedDeps: false,
|
|
syncInjectedDepsAfterScripts,
|
|
})
|
|
}
|
|
|
|
test('with sync-injected-deps-after-scripts', async () => {
|
|
prepareInjectedDepsWorkspace(['build1', 'build2', 'build3'])
|
|
|
|
await execPnpm(['install'])
|
|
expect(fs.readdirSync('node_modules/.pnpm')).toContain('foo@file+foo')
|
|
expect(fs.readdirSync('node_modules/.pnpm')).toContain('bar@file+bar')
|
|
expect(fs.readdirSync('node_modules/.pnpm/foo@file+foo/node_modules/foo').sort()).toStrictEqual(PKG_FILES)
|
|
expect(
|
|
fs.readFileSync('node_modules/.pnpm/foo@file+foo/node_modules/foo/should-be-modified-by-build1.txt', 'utf-8')
|
|
).toBe('Before modification\n')
|
|
expect(fs.readdirSync('node_modules/.pnpm/bar@file+bar/node_modules/bar').sort()).toStrictEqual(PKG_FILES)
|
|
expect(
|
|
fs.readFileSync('node_modules/.pnpm/bar@file+bar/node_modules/bar/should-be-modified-by-build1.txt', 'utf-8')
|
|
).toBe('Before modification\n')
|
|
|
|
// build1 should update the injected files
|
|
{
|
|
await execPnpm(['--recursive', 'run', 'build1'])
|
|
|
|
// injected foo
|
|
expect(fs.readdirSync('node_modules/.pnpm/foo@file+foo/node_modules/foo')).not.toContain('should-be-deleted-by-build1.txt')
|
|
expect(
|
|
fs.readFileSync('node_modules/.pnpm/foo@file+foo/node_modules/foo/should-be-added-by-build1.txt', 'utf-8')
|
|
).toBe(path.resolve('foo/build1.cjs'))
|
|
expect(
|
|
fs.readFileSync('node_modules/.pnpm/foo@file+foo/node_modules/foo/should-be-modified-by-build1.txt', 'utf-8')
|
|
).toBe('After modification')
|
|
|
|
// injected bar
|
|
expect(fs.readdirSync('node_modules/.pnpm/bar@file+bar/node_modules/bar')).not.toContain('should-be-deleted-by-build1.txt')
|
|
expect(
|
|
fs.readFileSync('node_modules/.pnpm/bar@file+bar/node_modules/bar/should-be-added-by-build1.txt', 'utf-8')
|
|
).toBe(path.resolve('bar/build1.cjs'))
|
|
expect(
|
|
fs.readFileSync('node_modules/.pnpm/bar@file+bar/node_modules/bar/should-be-modified-by-build1.txt', 'utf-8')
|
|
).toBe('After modification')
|
|
}
|
|
|
|
// build2 should update the injected files
|
|
{
|
|
await execPnpm(['--recursive', 'run', 'build2'])
|
|
|
|
// injected foo
|
|
expect(
|
|
fs.readFileSync('node_modules/.pnpm/foo@file+foo/node_modules/foo/created-by-build2.txt', 'utf-8')
|
|
).toBe(path.resolve('foo/build2.cjs'))
|
|
|
|
// injected bar
|
|
expect(
|
|
fs.readFileSync('node_modules/.pnpm/bar@file+bar/node_modules/bar/created-by-build2.txt', 'utf-8')
|
|
).toBe(path.resolve('bar/build2.cjs'))
|
|
}
|
|
})
|
|
|
|
test('without sync-injected-deps-after-scripts', async () => {
|
|
prepareInjectedDepsWorkspace([])
|
|
|
|
await execPnpm(['install'])
|
|
expect(fs.readdirSync('node_modules/.pnpm')).toContain('foo@file+foo')
|
|
expect(fs.readdirSync('node_modules/.pnpm')).toContain('bar@file+bar')
|
|
expect(fs.readdirSync('node_modules/.pnpm/foo@file+foo/node_modules/foo').sort()).toStrictEqual(PKG_FILES)
|
|
expect(
|
|
fs.readFileSync('node_modules/.pnpm/foo@file+foo/node_modules/foo/should-be-modified-by-build1.txt', 'utf-8')
|
|
).toBe('Before modification\n')
|
|
expect(fs.readdirSync('node_modules/.pnpm/bar@file+bar/node_modules/bar').sort()).toStrictEqual(PKG_FILES)
|
|
expect(
|
|
fs.readFileSync('node_modules/.pnpm/bar@file+bar/node_modules/bar/should-be-modified-by-build1.txt', 'utf-8')
|
|
).toBe('Before modification\n')
|
|
|
|
// build1 should not update the injected files
|
|
{
|
|
await execPnpm(['--recursive', 'run', 'build1'])
|
|
|
|
// injected foo
|
|
expect(fs.readdirSync('node_modules/.pnpm/foo@file+foo/node_modules/foo')).toContain('should-be-deleted-by-build1.txt')
|
|
expect(fs.readdirSync('node_modules/.pnpm/foo@file+foo/node_modules/foo')).not.toContain('should-be-added-by-build1.txt')
|
|
|
|
// injected bar
|
|
expect(fs.readdirSync('node_modules/.pnpm/bar@file+bar/node_modules/bar')).toContain('should-be-deleted-by-build1.txt')
|
|
expect(fs.readdirSync('node_modules/.pnpm/bar@file+bar/node_modules/bar')).not.toContain('should-be-added-by-build1.txt')
|
|
}
|
|
|
|
// build2 should not update the injected files
|
|
{
|
|
await execPnpm(['--recursive', 'run', 'build2'])
|
|
|
|
// injected foo
|
|
expect(fs.readdirSync('node_modules/.pnpm/foo@file+foo/node_modules/foo')).not.toContain('created-by-build2.txt')
|
|
|
|
// injected bar
|
|
expect(fs.readdirSync('node_modules/.pnpm/bar@file+bar/node_modules/bar')).not.toContain('created-by-build2.txt')
|
|
}
|
|
})
|
|
|
|
test('filter scripts', async () => {
|
|
prepareInjectedDepsWorkspace(['build1'])
|
|
|
|
await execPnpm(['install'])
|
|
expect(fs.readdirSync('node_modules/.pnpm')).toContain('foo@file+foo')
|
|
expect(fs.readdirSync('node_modules/.pnpm')).toContain('bar@file+bar')
|
|
expect(fs.readdirSync('node_modules/.pnpm/foo@file+foo/node_modules/foo').sort()).toStrictEqual(PKG_FILES)
|
|
expect(
|
|
fs.readFileSync('node_modules/.pnpm/foo@file+foo/node_modules/foo/should-be-modified-by-build1.txt', 'utf-8')
|
|
).toBe('Before modification\n')
|
|
expect(fs.readdirSync('node_modules/.pnpm/bar@file+bar/node_modules/bar').sort()).toStrictEqual(PKG_FILES)
|
|
expect(
|
|
fs.readFileSync('node_modules/.pnpm/bar@file+bar/node_modules/bar/should-be-modified-by-build1.txt', 'utf-8')
|
|
).toBe('Before modification\n')
|
|
|
|
// build1 should update the injected files
|
|
{
|
|
await execPnpm(['--recursive', 'run', 'build1'])
|
|
|
|
// injected foo
|
|
expect(fs.readdirSync('node_modules/.pnpm/foo@file+foo/node_modules/foo')).not.toContain('should-be-deleted-by-build1.txt')
|
|
expect(
|
|
fs.readFileSync('node_modules/.pnpm/foo@file+foo/node_modules/foo/should-be-added-by-build1.txt', 'utf-8')
|
|
).toBe(path.resolve('foo/build1.cjs'))
|
|
expect(
|
|
fs.readFileSync('node_modules/.pnpm/foo@file+foo/node_modules/foo/should-be-modified-by-build1.txt', 'utf-8')
|
|
).toBe('After modification')
|
|
|
|
// injected bar
|
|
expect(fs.readdirSync('node_modules/.pnpm/bar@file+bar/node_modules/bar')).not.toContain('should-be-deleted-by-build1.txt')
|
|
expect(
|
|
fs.readFileSync('node_modules/.pnpm/bar@file+bar/node_modules/bar/should-be-added-by-build1.txt', 'utf-8')
|
|
).toBe(path.resolve('bar/build1.cjs'))
|
|
expect(
|
|
fs.readFileSync('node_modules/.pnpm/bar@file+bar/node_modules/bar/should-be-modified-by-build1.txt', 'utf-8')
|
|
).toBe('After modification')
|
|
}
|
|
|
|
// build2 should not update the injected files
|
|
{
|
|
await execPnpm(['--recursive', 'run', 'build2'])
|
|
|
|
// injected foo
|
|
expect(fs.readdirSync('node_modules/.pnpm/foo@file+foo/node_modules/foo')).not.toContain('created-by-build2.txt')
|
|
|
|
// injected bar
|
|
expect(fs.readdirSync('node_modules/.pnpm/bar@file+bar/node_modules/bar')).not.toContain('created-by-build2.txt')
|
|
}
|
|
})
|
|
|
|
test('directories and symlinks', async () => {
|
|
prepareInjectedDepsWorkspace(['build1', 'build2', 'build3'])
|
|
|
|
await execPnpm(['install'])
|
|
expect(fs.readdirSync('node_modules/.pnpm')).toContain('foo@file+foo')
|
|
expect(fs.readdirSync('node_modules/.pnpm')).toContain('bar@file+bar')
|
|
expect(fs.readdirSync('node_modules/.pnpm/foo@file+foo/node_modules/foo').sort()).toStrictEqual(PKG_FILES)
|
|
expect(fs.readdirSync('node_modules/.pnpm/bar@file+bar/node_modules/bar').sort()).toStrictEqual(PKG_FILES)
|
|
|
|
// build3 should update the injected files
|
|
{
|
|
await execPnpm(['--filter=foo', 'run', 'build3'])
|
|
|
|
// should create empty-dirs at source
|
|
expect(fs.readdirSync('foo/empty-dirs/a/a')).toStrictEqual([])
|
|
expect(fs.readdirSync('foo/empty-dirs/a/b')).toStrictEqual([])
|
|
expect(fs.readdirSync('foo/empty-dirs/b/a')).toStrictEqual([])
|
|
expect(fs.readdirSync('foo/empty-dirs/b/b')).toStrictEqual([])
|
|
|
|
// should not create empty-dirs at the injected location
|
|
expect(fs.readdirSync('node_modules/.pnpm/foo@file+foo/node_modules/foo')).not.toContain('empty-dirs')
|
|
|
|
// should recreate a directories tree at the injected location
|
|
expect(fs.readdirSync('node_modules/.pnpm/foo@file+foo/node_modules/foo')).toContain('files')
|
|
expect(
|
|
fs.readdirSync('node_modules/.pnpm/foo@file+foo/node_modules/foo/files')
|
|
.sort()
|
|
).toStrictEqual(['foo', 'foo_bar.txt'])
|
|
expect(
|
|
fs.readdirSync('node_modules/.pnpm/foo@file+foo/node_modules/foo/files/foo')
|
|
.sort()
|
|
).toStrictEqual(['bar.txt', 'foo'])
|
|
expect(
|
|
fs.readdirSync('node_modules/.pnpm/foo@file+foo/node_modules/foo/files/foo/foo')
|
|
.sort()
|
|
).toStrictEqual(['foo.txt'])
|
|
|
|
// should recreate the structure of the symlinks at the injected location
|
|
// NOTE: The current implementation of @pnpm/directory-fetcher would treat symlinks to dir at real dir
|
|
// because it uses fs.stat instead of fs.lstat, so testing with fs.realpathSync wouldn't work.
|
|
expect(fs.readFileSync('node_modules/.pnpm/foo@file+foo/node_modules/foo/link-to-a-file', 'utf-8')).toBe('This is foo_bar')
|
|
expect(
|
|
fs.readdirSync('node_modules/.pnpm/foo@file+foo/node_modules/foo/link-to-a-dir')
|
|
.sort()
|
|
).toStrictEqual(
|
|
fs.readdirSync('node_modules/.pnpm/foo@file+foo/node_modules/foo/files/foo')
|
|
.sort()
|
|
)
|
|
}
|
|
})
|