feat: always read configs from root of workspace

A .npmrc file in the root of a workspace can contain configs shared
by all workspace packages.

The workspace-level configs have bigger priority than global level
configs and less priority than local-level configs.

```
<global>/npmrc < <workspace>/.npmrc < <package>/.npmrc
```

PR #1310
This commit is contained in:
Zoltan Kochan
2018-08-02 21:19:34 -07:00
committed by Zoltan Kochan
parent 0b71b3d1be
commit ce38b80f03
11 changed files with 105 additions and 46 deletions

View File

@@ -32,8 +32,9 @@
"@types/camelcase": "^4.1.0",
"@types/node": "^9.4.6 || 10",
"@types/which": "^1.3.1",
"@zkochan/npm-conf": "^1.1.0",
"@zkochan/npm-conf": "^1.2.0",
"camelcase": "^5.0.0",
"find-up": "^3.0.0",
"which": "^1.3.0"
},
"devDependencies": {

View File

@@ -3,8 +3,9 @@ dependencies:
'@types/camelcase': 4.1.0
'@types/node': 10.5.4
'@types/which': 1.3.1
'@zkochan/npm-conf': 1.1.0
'@zkochan/npm-conf': 1.2.0
camelcase: 5.0.0
find-up: 3.0.0
which: 1.3.1
devDependencies:
'@types/tape': 4.2.32
@@ -85,7 +86,7 @@ packages:
dev: true
resolution:
integrity: sha1-TPO97s9S8vasjzKw2IpoLrSEiXk=
/@zkochan/npm-conf/1.1.0:
/@zkochan/npm-conf/1.2.0:
dependencies:
config-chain: 1.1.11
pify: 3.0.0
@@ -93,7 +94,7 @@ packages:
engines:
node: '>=6'
resolution:
integrity: sha512-mkr67K2ONHmEE2Tlf1ccl+f4/gJpYr7Sfh53xMa6bZc3iJmftseHGQCro7GXhzoGcYg6LpGEww2ElOyKrj+beQ==
integrity: sha512-FHTKDRhT4FzdEw80L5k1NEI0OgDJgIUhMGlC4HlUXD7NQzNItSqnJLlW+vGKjDcFmVLHPIEoYKx5GCQWeLOGMg==
/acorn/3.0.4:
dev: true
engines:
@@ -918,6 +919,14 @@ packages:
node: '>=4'
resolution:
integrity: sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
/find-up/3.0.0:
dependencies:
locate-path: 3.0.0
dev: false
engines:
node: '>=6'
resolution:
integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
/flatten/1.0.2:
dev: true
resolution:
@@ -1378,6 +1387,15 @@ packages:
node: '>=4'
resolution:
integrity: sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=
/locate-path/3.0.0:
dependencies:
p-locate: 3.0.0
path-exists: 3.0.0
dev: false
engines:
node: '>=6'
resolution:
integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
/lodash.partition/4.6.0:
dev: true
resolution:
@@ -1893,6 +1911,14 @@ packages:
node: '>=4'
resolution:
integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==
/p-limit/2.0.0:
dependencies:
p-try: 2.0.0
dev: false
engines:
node: '>=6'
resolution:
integrity: sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==
/p-locate/2.0.0:
dependencies:
p-limit: 1.3.0
@@ -1901,12 +1927,26 @@ packages:
node: '>=4'
resolution:
integrity: sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=
/p-locate/3.0.0:
dependencies:
p-limit: 2.0.0
dev: false
engines:
node: '>=6'
resolution:
integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
/p-try/1.0.0:
dev: true
engines:
node: '>=4'
resolution:
integrity: sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=
/p-try/2.0.0:
dev: false
engines:
node: '>=6'
resolution:
integrity: sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==
/package-json/2.4.0:
dependencies:
got: 5.7.1
@@ -1990,7 +2030,6 @@ packages:
resolution:
integrity: sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=
/path-exists/3.0.0:
dev: true
engines:
node: '>=4'
resolution:
@@ -3053,8 +3092,9 @@ specifiers:
'@types/node': ^9.4.6 || 10
'@types/tape': ^4.2.32
'@types/which': ^1.3.1
'@zkochan/npm-conf': ^1.1.0
'@zkochan/npm-conf': ^1.2.0
camelcase: ^5.0.0
find-up: ^3.0.0
mos: ^2.0.0-alpha.3
mos-plugin-readme: ^1.0.4
package-preview: ^1.0.1

View File

@@ -1,6 +1,7 @@
import loadNpmConf = require('@zkochan/npm-conf')
import npmTypes = require('@zkochan/npm-conf/lib/types')
import camelcase = require('camelcase')
import findUp = require('find-up')
import path = require('path')
import whichcb = require('which')
@@ -49,8 +50,11 @@ export const types = Object.assign({
'use-store-server': Boolean,
'verify-store-integrity': Boolean,
'workspace-concurrency': Number,
'workspace-prefix': String,
}, npmTypes.types)
const WORKSPACE_MANIFEST_FILENAME = 'pnpm-workspace.yaml'
export default async (
opts: {
cliArgs: object,
@@ -76,6 +80,9 @@ export default async (
}
} catch (err) {} // tslint:disable-line:no-empty
const workspaceManifestLocation = await findUp(WORKSPACE_MANIFEST_FILENAME, {
cwd: cliArgs['prefix'] || process.cwd(), // tslint:disable-line
})
const npmConfig = loadNpmConf(null, types, {
'bail': true,
'globalconfig': npmDefaults.globalconfig,
@@ -86,6 +93,7 @@ export default async (
'unsafe-perm': npmDefaults['unsafe-perm'],
'userconfig': npmDefaults.userconfig,
'workspace-concurrency': 4,
'workspace-prefix': workspaceManifestLocation && path.dirname(workspaceManifestLocation),
})
process.execPath = originalExecPath

View File

@@ -7,3 +7,8 @@ declare module '@zkochan/npm-conf/lib/types' {
const anything: any;
export = anything;
}
declare module 'find-up' {
const anything: any;
export = anything;
}

View File

@@ -45,7 +45,6 @@
"diable": "^4.0.1",
"execa": "^0.10.0",
"find-packages": "^2.2.0",
"find-up": "^3.0.0",
"get-port": "^4.0.0",
"graceful-fs": "^4.1.11",
"graph-sequencer": "^2.0.0",

View File

@@ -24,7 +24,6 @@ dependencies:
diable: 4.0.1
execa: 0.10.0
find-packages: 2.2.0
find-up: 3.0.0
get-port: 4.0.0
graceful-fs: 4.1.11
graph-sequencer: 2.0.0
@@ -2316,14 +2315,6 @@ packages:
node: '>=4'
resolution:
integrity: sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
/find-up/3.0.0:
dependencies:
locate-path: 3.0.0
dev: false
engines:
node: '>=6'
resolution:
integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
/flat-colors/3.0.0:
dev: false
resolution:
@@ -3498,15 +3489,6 @@ packages:
node: '>=4'
resolution:
integrity: sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=
/locate-path/3.0.0:
dependencies:
p-locate: 3.0.0
path-exists: 3.0.0
dev: false
engines:
node: '>=6'
resolution:
integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
/lockfile/1.0.3:
dev: true
resolution:
@@ -4329,14 +4311,6 @@ packages:
node: '>=4'
resolution:
integrity: sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=
/p-locate/3.0.0:
dependencies:
p-limit: 2.0.0
dev: false
engines:
node: '>=6'
resolution:
integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
/p-map/1.2.0:
dev: false
engines:
@@ -6466,7 +6440,6 @@ specifiers:
execa: ^0.10.0
exists-link: ^2.0.0
find-packages: ^2.2.0
find-up: ^3.0.0
get-port: ^4.0.0
graceful-fs: ^4.1.11
graph-sequencer: ^2.0.0

View File

@@ -1,13 +1,10 @@
import findUp = require('find-up')
import path = require('path')
import pathAbsolute = require('path-absolute')
import R = require('ramda')
import {
link,
linkFromGlobal,
linkToGlobal,
} from 'supi'
import {WORKSPACE_MANIFEST_FILENAME} from '../constants'
import createStoreController from '../createStoreController'
import findWorkspacePackages from '../findWorkspacePackages'
import {PnpmOptions} from '../types'
@@ -33,11 +30,9 @@ export default async (
const [pkgPaths, pkgNames] = R.partition((inp) => inp.startsWith('.'), input)
if (pkgNames.length) {
const workspaceManifestLocation = await findUp(WORKSPACE_MANIFEST_FILENAME)
let globalPkgNames!: string[]
if (workspaceManifestLocation) {
const workspaceRoot = path.dirname(workspaceManifestLocation)
const pkgs = await findWorkspacePackages(workspaceRoot)
if (opts.workspacePrefix) {
const pkgs = await findWorkspacePackages(opts.workspacePrefix)
const pkgsFoundInWorkspace = pkgs.filter((pkg) => pkgNames.indexOf(pkg.manifest.name) !== -1)
pkgsFoundInWorkspace.forEach((pkgFromWorkspace) => pkgPaths.push(pkgFromWorkspace.path))

View File

@@ -73,6 +73,7 @@ export interface PnpmOptions {
shrinkwrapOnly?: boolean, // like npm's --package-lock-only
useStoreServer?: boolean,
workspaceConcurrency: number,
workspacePrefix?: string,
// cannot be specified via configs
update?: boolean,

View File

@@ -358,6 +358,7 @@ test('pnpmfile: run afterAllResolved hook', async (t: tape.Test) => {
hooks: {
afterAllResolved (shr, context) {
context.log('All resolved')
return shr
}
}
}

View File

@@ -135,6 +135,47 @@ test('recursive installation with package-specific .npmrc', async t => {
t.notOk(modulesYaml2 && modulesYaml2.shamefullyFlatten)
})
test('workspace .npmrc is always read', async (t: tape.Test) => {
const projects = preparePackages(t, [
{
name: 'project-1',
version: '1.0.0',
dependencies: {
'is-positive': '1.0.0',
},
},
{
name: 'project-2',
version: '1.0.0',
dependencies: {
'is-negative': '1.0.0',
},
},
])
await fs.writeFile('pnpm-workspace.yaml', '', 'utf8')
await fs.writeFile('.npmrc', 'shamefully-flatten = true', 'utf8')
await fs.writeFile('project-2/.npmrc', 'shamefully-flatten = false', 'utf8')
process.chdir('project-1')
await execPnpm('install')
t.ok(projects['project-1'].requireModule('is-positive'))
const modulesYaml1 = await projects['project-1'].loadModules()
t.ok(modulesYaml1 && modulesYaml1.shamefullyFlatten)
process.chdir('..')
process.chdir('project-2')
await execPnpm('install')
t.ok(projects['project-2'].requireModule('is-negative'))
const modulesYaml2 = await projects['project-2'].loadModules()
t.ok(modulesYaml2 && modulesYaml2.shamefullyFlatten === false)
})
test('recursive installation using server', async (t: tape.Test) => {
const projects = preparePackages(t, [
{

View File

@@ -93,11 +93,6 @@ declare module 'arr-flatten' {
export = anything;
}
declare module 'find-up' {
const anything: any;
export = anything;
}
declare module 'path-exists' {
const anything: any;
export = anything;