feat: copy license files from workspace root when package has none

close #1804
This commit is contained in:
Zoltan Kochan
2019-05-06 01:53:39 +03:00
parent 9e66cb03e7
commit 576752f199
4 changed files with 158 additions and 4 deletions

View File

@@ -48,11 +48,13 @@
"camelcase-keys": "5.2.0",
"chalk": "2.4.2",
"common-tags": "1.8.0",
"cp-file": "7.0.0",
"cross-spawn": "6.0.5",
"delay": "4.2.0",
"diable": "4.0.2",
"dir-is-case-sensitive": "1.0.2",
"execa": "1.0.0",
"fast-glob": "2.2.6",
"find-packages": "5.0.0",
"get-port": "5.0.0",
"graceful-fs": "4.1.15",

View File

@@ -1,4 +1,7 @@
import readImporterManifest from '@pnpm/read-importer-manifest'
import cpFile = require('cp-file')
import fg = require('fast-glob')
import fs = require('mz/fs')
import path = require('path')
import rimraf = require('rimraf-then')
import writeJsonFile = require('write-json-file')
@@ -17,7 +20,7 @@ export default async function (
const prefix = args.length && args[0] || process.cwd()
let _status!: number
await fakeRegularManifest(prefix, async () => {
await fakeRegularManifest(prefix, opts.workspacePrefix || prefix, async () => {
const { status } = await runNpm(['publish', ...opts.argv.original.slice(1)])
_status = status
})
@@ -32,7 +35,7 @@ export async function pack (
command: string,
) {
let _status!: number
await fakeRegularManifest(opts.prefix, async () => {
await fakeRegularManifest(opts.prefix, opts.workspacePrefix || opts.prefix, async () => {
const { status } = await runNpm(['pack', ...opts.argv.original.slice(1)])
_status = status
})
@@ -41,7 +44,15 @@ export async function pack (
}
}
async function fakeRegularManifest (prefix: string, fn: () => Promise<void>) {
const LICENSE_GLOB = 'LICEN{S,C}E{,.*}'
const findLicenses = fg.bind(fg, [LICENSE_GLOB]) as (opts: { cwd: string }) => Promise<string[]>
async function fakeRegularManifest (prefix: string, workspacePrefix: string, fn: () => Promise<void>) {
// If a workspace package has no License of its own,
// license files from the root of the workspace are used
const copiedLicenses: string[] = prefix !== workspacePrefix && (await findLicenses({ cwd: prefix })).length === 0
? await copyLicenses(workspacePrefix, prefix) : []
const { fileName, manifest, writeImporterManifest } = await readImporterManifest(prefix)
const exoticManifestFormat = fileName !== 'package.json'
if (exoticManifestFormat) {
@@ -53,4 +64,24 @@ async function fakeRegularManifest (prefix: string, fn: () => Promise<void>) {
await rimraf(path.join(prefix, 'package.json'))
await writeImporterManifest(manifest, true)
}
await Promise.all(
copiedLicenses.map((copiedLicense) => fs.unlink(copiedLicense))
)
}
async function copyLicenses (sourceDir: string, destDir: string) {
const licenses = await findLicenses({ cwd: sourceDir })
if (licenses.length === 0) return []
const copiedLicenses: string[] = []
await Promise.all(
licenses
.map((licenseRelPath) => path.join(sourceDir, licenseRelPath))
.map((licensePath) => {
const licenseCopyDest = path.join(destDir, path.basename(licensePath))
copiedLicenses.push(licenseCopyDest)
return cpFile(licensePath, licenseCopyDest)
})
)
return copiedLicenses
}

View File

@@ -1,7 +1,9 @@
import prepare from '@pnpm/prepare'
import prepare, { preparePackages } from '@pnpm/prepare'
import fs = require('mz/fs')
import exists = require('path-exists')
import tape = require('tape')
import promisifyTape from 'tape-promise'
import writeYamlFile = require('write-yaml-file')
import { execPnpm } from './utils'
const test = promisifyTape(tape)
@@ -59,3 +61,79 @@ test('publish: package with package.json5 running publish from different folder'
t.ok(await exists('project/package.json5'))
t.notOk(await exists('project/package.json'))
})
test('pack packages with workspace LICENSE if no own LICENSE is present', async (t: tape.Test) => {
preparePackages(t, [
{
name: 'project-1',
version: '1.0.0',
},
{
name: 'project-2',
version: '1.0.0',
},
{
name: 'target',
version: '1.0.0',
},
], { manifestFormat: 'YAML' })
await writeYamlFile('pnpm-workspace.yaml', { packages: ['**', '!store/**'] })
await fs.writeFile('LICENSE', 'workspace license', 'utf8')
await fs.writeFile('project-2/LICENSE', 'project-2 license', 'utf8')
process.chdir('project-1')
await execPnpm('pack')
process.chdir('../project-2')
await execPnpm('pack')
process.chdir('../target')
await execPnpm('add', '../project-1/project-1-1.0.0.tgz', '../project-2/project-2-1.0.0.tgz')
t.equal(await fs.readFile('node_modules/project-1/LICENSE', 'utf8'), 'workspace license')
t.equal(await fs.readFile('node_modules/project-2/LICENSE', 'utf8'), 'project-2 license')
process.chdir('..')
t.notOk(await exists('project-1/LICENSE'))
t.ok(await exists('project-2/LICENSE'))
})
test('publish packages with workspace LICENSE if no own LICENSE is present', async (t: tape.Test) => {
preparePackages(t, [
{
name: 'project-100',
version: '1.0.0',
},
{
name: 'project-200',
version: '1.0.0',
},
{
name: 'target',
version: '1.0.0',
},
], { manifestFormat: 'YAML' })
await writeYamlFile('pnpm-workspace.yaml', { packages: ['**', '!store/**'] })
await fs.writeFile('LICENSE', 'workspace license', 'utf8')
await fs.writeFile('project-200/LICENSE', 'project-200 license', 'utf8')
process.chdir('project-100')
await execPnpm('publish', ...CREDENTIALS)
process.chdir('../project-200')
await execPnpm('publish', ...CREDENTIALS)
process.chdir('../target')
await execPnpm('add', 'project-100', 'project-200', '--no-link-workspace-packages')
t.equal(await fs.readFile('node_modules/project-100/LICENSE', 'utf8'), 'workspace license')
t.equal(await fs.readFile('node_modules/project-200/LICENSE', 'utf8'), 'project-200 license')
process.chdir('..')
t.notOk(await exists('project-100/LICENSE'))
t.ok(await exists('project-200/LICENSE'))
})

43
pnpm-lock.yaml generated
View File

@@ -1412,11 +1412,13 @@ importers:
camelcase-keys: 5.2.0
chalk: 2.4.2
common-tags: 1.8.0
cp-file: 7.0.0
cross-spawn: 6.0.5
delay: 4.2.0
diable: 4.0.2
dir-is-case-sensitive: 1.0.2
execa: 1.0.0
fast-glob: 2.2.6
find-packages: 'link:../find-packages'
get-port: 5.0.0
graceful-fs: 4.1.15
@@ -1540,6 +1542,7 @@ importers:
camelcase-keys: 5.2.0
chalk: 2.4.2
common-tags: 1.8.0
cp-file: 7.0.0
cross-spawn: 6.0.5
deep-require-cwd: 1.0.0
delay: 4.2.0
@@ -1547,6 +1550,7 @@ importers:
dir-is-case-sensitive: 1.0.2
execa: 1.0.0
exists-link: 2.0.0
fast-glob: 2.2.6
find-packages: 5.0.0
get-port: 5.0.0
graceful-fs: 4.1.15
@@ -4467,6 +4471,17 @@ packages:
dev: false
resolution:
integrity: sha512-16ZvhVjVhEP75sMflsPtXcwbly+79os1zhBVcpRWNmnwifEbZChW+0URYING/A2ehBwp8i0pOXJYzdpiGO3Ivw==
/cp-file/7.0.0:
dependencies:
graceful-fs: 4.1.15
make-dir: 3.0.0
nested-error-stacks: 2.1.0
p-event: 4.1.0
dev: false
engines:
node: '>=8'
resolution:
integrity: sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==
/cpr/3.0.1:
dependencies:
graceful-fs: 4.1.15
@@ -6811,6 +6826,14 @@ packages:
node: '>=6'
resolution:
integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==
/make-dir/3.0.0:
dependencies:
semver: 6.0.0
dev: false
engines:
node: '>=8'
resolution:
integrity: sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==
/make-error/1.3.5:
dev: true
resolution:
@@ -7434,6 +7457,10 @@ packages:
dev: false
resolution:
integrity: sha1-5tq3/r9a2Bbqgc9cYpxaDr3nLBo=
/nested-error-stacks/2.1.0:
dev: false
resolution:
integrity: sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==
/next-path/1.0.0:
engines:
node: '>=6'
@@ -7794,6 +7821,14 @@ packages:
node: '>=4'
resolution:
integrity: sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=
/p-event/4.1.0:
dependencies:
p-timeout: 2.0.1
dev: false
engines:
node: '>=8'
resolution:
integrity: sha512-4vAd06GCsgflX4wHN1JqrMzBh/8QZ4j+rzp0cd2scXRwuBEv+QR3wrVA5aLhWDLw4y2WgDKvzWF3CCLmVM1UgA==
/p-every/2.0.0:
dependencies:
p-map: 2.1.0
@@ -7880,6 +7915,14 @@ packages:
node: '>=8'
resolution:
integrity: sha512-MF/HIbq6GeBqTrTIl5OJubzkGU+qfFhAFi0gnTAK6rgEIJIknEiABHOTtQu4e6JiXjIwuMPMUFQzyHh5QjCl1g==
/p-timeout/2.0.1:
dependencies:
p-finally: 1.0.0
dev: false
engines:
node: '>=4'
resolution:
integrity: sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==
/p-try/1.0.0:
dev: true
engines: