mirror of
https://github.com/pnpm/pnpm.git
synced 2025-12-23 23:29:17 -05:00
fix(plugin-commands-publishing): should pack main file or bin files defined in publishConfig (#7538)
close #4195
This commit is contained in:
8
.changeset/smooth-buckets-drop.md
Normal file
8
.changeset/smooth-buckets-drop.md
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-publishing": patch
|
||||
"@pnpm-private/typings": patch
|
||||
"@pnpm/fs.packlist": patch
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
`pnpm publish` should pack "main" file or "bin" files defined in "publishConfig" [#4195](https://github.com/pnpm/pnpm/issues/4195).
|
||||
2
__typings__/typed.d.ts
vendored
2
__typings__/typed.d.ts
vendored
@@ -214,6 +214,6 @@ declare module '@pnpm/npm-conf/lib/types' {
|
||||
}
|
||||
|
||||
declare module 'npm-packlist' {
|
||||
function npmPacklist (opts: { path: string }): Promise<string[]>
|
||||
function npmPacklist (opts: { path: string, packageJsonCache?: Map<string, Record<string, unknown>> }): Promise<string[]>
|
||||
export = npmPacklist
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import npmPacklist from 'npm-packlist'
|
||||
|
||||
export async function packlist (pkgDir: string): Promise<string[]> {
|
||||
const files = await npmPacklist({ path: pkgDir })
|
||||
export async function packlist (pkgDir: string, opts?: {
|
||||
packageJsonCache?: Record<string, Record<string, unknown>>
|
||||
}): Promise<string[]> {
|
||||
const packageJsonCacheMap = opts?.packageJsonCache
|
||||
? new Map(Object.entries(opts.packageJsonCache))
|
||||
: undefined
|
||||
const files = await npmPacklist({ path: pkgDir, packageJsonCache: packageJsonCacheMap })
|
||||
// There's a bug in the npm-packlist version that we use,
|
||||
// it sometimes returns duplicates.
|
||||
// Related issue: https://github.com/pnpm/pnpm/issues/6997
|
||||
|
||||
@@ -7,7 +7,7 @@ import { readProjectManifest } from '@pnpm/cli-utils'
|
||||
import { createExportableManifest } from '@pnpm/exportable-manifest'
|
||||
import { packlist } from '@pnpm/fs.packlist'
|
||||
import { getBinsFromPackageManifest } from '@pnpm/package-bins'
|
||||
import { type DependencyManifest } from '@pnpm/types'
|
||||
import { type ProjectManifest, type DependencyManifest } from '@pnpm/types'
|
||||
import fg from 'fast-glob'
|
||||
import pick from 'ramda/src/pick'
|
||||
import realpathMissing from 'realpath-missing'
|
||||
@@ -95,8 +95,18 @@ export async function handler (
|
||||
throw new PnpmError('PACKAGE_VERSION_NOT_FOUND', `Package version is not defined in the ${manifestFileName}.`)
|
||||
}
|
||||
const tarballName = `${manifest.name.replace('@', '').replace('/', '-')}-${manifest.version}.tgz`
|
||||
const files = await packlist(dir)
|
||||
const filesMap: Record<string, string> = Object.fromEntries(files.map((file) => [`package/${file}`, path.join(dir, file)]))
|
||||
const publishManifest = await createPublishManifest({
|
||||
projectDir: dir,
|
||||
modulesDir: path.join(opts.dir, 'node_modules'),
|
||||
manifest,
|
||||
embedReadme: opts.embedReadme,
|
||||
})
|
||||
const files = await packlist(dir, {
|
||||
packageJsonCache: {
|
||||
[path.join(dir, 'package.json')]: publishManifest as Record<string, unknown>,
|
||||
},
|
||||
})
|
||||
const filesMap = Object.fromEntries(files.map((file) => [`package/${file}`, path.join(dir, file)]))
|
||||
// cspell:disable-next-line
|
||||
if (opts.workspaceDir != null && dir !== opts.workspaceDir && !files.some((file) => /LICEN[CS]E(\..+)?/i.test(file))) {
|
||||
const licenses = await findLicenses({ cwd: opts.workspaceDir })
|
||||
@@ -111,10 +121,14 @@ export async function handler (
|
||||
await packPkg({
|
||||
destFile: path.join(destDir, tarballName),
|
||||
filesMap,
|
||||
projectDir: dir,
|
||||
embedReadme: opts.embedReadme,
|
||||
modulesDir: path.join(opts.dir, 'node_modules'),
|
||||
packGzipLevel: opts.packGzipLevel,
|
||||
manifest: publishManifest,
|
||||
bins: [
|
||||
...(await getBinsFromPackageManifest(publishManifest as DependencyManifest, dir)).map(({ path }) => path),
|
||||
...(manifest.publishConfig?.executableFiles ?? [])
|
||||
.map((executableFile) => path.join(dir, executableFile)),
|
||||
],
|
||||
})
|
||||
if (!opts.ignoreScripts) {
|
||||
await _runScriptsIfPresent(['postpack'], entryManifest)
|
||||
@@ -125,9 +139,10 @@ export async function handler (
|
||||
return path.relative(opts.dir, path.join(dir, tarballName))
|
||||
}
|
||||
|
||||
async function readReadmeFile (filesMap: Record<string, string>) {
|
||||
const readmePath = Object.keys(filesMap).find(name => /^package\/readme\.md$/i.test(name))
|
||||
const readmeFile = readmePath ? await fs.promises.readFile(filesMap[readmePath], 'utf8') : undefined
|
||||
async function readReadmeFile (projectDir: string) {
|
||||
const files = await fs.promises.readdir(projectDir)
|
||||
const readmePath = files.find(name => /readme\.md$/i.test(name))
|
||||
const readmeFile = readmePath ? await fs.promises.readFile(path.join(projectDir, readmePath), 'utf8') : undefined
|
||||
|
||||
return readmeFile
|
||||
}
|
||||
@@ -135,32 +150,24 @@ async function readReadmeFile (filesMap: Record<string, string>) {
|
||||
async function packPkg (opts: {
|
||||
destFile: string
|
||||
filesMap: Record<string, string>
|
||||
projectDir: string
|
||||
embedReadme?: boolean
|
||||
modulesDir: string
|
||||
packGzipLevel?: number
|
||||
bins: string[]
|
||||
manifest: ProjectManifest
|
||||
}): Promise<void> {
|
||||
const {
|
||||
destFile,
|
||||
filesMap,
|
||||
projectDir,
|
||||
embedReadme,
|
||||
bins,
|
||||
manifest,
|
||||
} = opts
|
||||
const { manifest } = await readProjectManifest(projectDir)
|
||||
const bins = [
|
||||
...(await getBinsFromPackageManifest(manifest as DependencyManifest, projectDir)).map(({ path }) => path),
|
||||
...(manifest.publishConfig?.executableFiles ?? [])
|
||||
.map((executableFile) => path.join(projectDir, executableFile)),
|
||||
]
|
||||
const mtime = new Date('1985-10-26T08:15:00.000Z')
|
||||
const pack = tar.pack()
|
||||
await Promise.all(Object.entries(filesMap).map(async ([name, source]) => {
|
||||
const isExecutable = bins.some((bin) => path.relative(bin, source) === '')
|
||||
const mode = isExecutable ? 0o755 : 0o644
|
||||
if (/^package\/package\.(json|json5|yaml)/.test(name)) {
|
||||
const readmeFile = embedReadme ? await readReadmeFile(filesMap) : undefined
|
||||
const publishManifest = await createExportableManifest(projectDir, manifest, { readmeFile, modulesDir: opts.modulesDir })
|
||||
pack.entry({ mode, mtime, name: 'package/package.json' }, JSON.stringify(publishManifest, null, 2))
|
||||
pack.entry({ mode, mtime, name: 'package/package.json' }, JSON.stringify(manifest, null, 2))
|
||||
return
|
||||
}
|
||||
pack.entry({ mode, mtime, name }, fs.readFileSync(source))
|
||||
@@ -174,3 +181,14 @@ async function packPkg (opts: {
|
||||
}).on('error', reject)
|
||||
})
|
||||
}
|
||||
|
||||
async function createPublishManifest (opts: {
|
||||
projectDir: string
|
||||
embedReadme?: boolean
|
||||
modulesDir: string
|
||||
manifest: ProjectManifest
|
||||
}) {
|
||||
const { projectDir, embedReadme, modulesDir, manifest } = opts
|
||||
const readmeFile = embedReadme ? await readReadmeFile(projectDir) : undefined
|
||||
return createExportableManifest(projectDir, manifest, { readmeFile, modulesDir })
|
||||
}
|
||||
|
||||
@@ -309,3 +309,40 @@ test('pack: custom pack-gzip-level', async () => {
|
||||
const tgz2 = fs.statSync(path.resolve('../big/test-publish-package.json-0.0.0.tgz'))
|
||||
expect(tgz1.size).not.toEqual(tgz2.size)
|
||||
})
|
||||
|
||||
test('pack: should resolve correct files from publishConfig', async () => {
|
||||
prepare({
|
||||
name: 'custom-publish-dir',
|
||||
version: '0.0.0',
|
||||
main: './index.ts',
|
||||
bin: './bin.js',
|
||||
files: [
|
||||
'./a.js',
|
||||
],
|
||||
publishConfig: {
|
||||
main: './dist-index.js',
|
||||
bin: './dist-bin.js',
|
||||
},
|
||||
})
|
||||
fs.writeFileSync('./a.js', 'a', 'utf8')
|
||||
fs.writeFileSync('./index.ts', 'src-index', 'utf8')
|
||||
fs.writeFileSync('./bin.js', 'src-bin-src', 'utf8')
|
||||
fs.writeFileSync('./dist-index.js', 'dist-index', 'utf8')
|
||||
fs.writeFileSync('./dist-bin.js', 'dist-bin', 'utf8')
|
||||
|
||||
await pack.handler({
|
||||
...DEFAULT_OPTS,
|
||||
argv: { original: [] },
|
||||
dir: process.cwd(),
|
||||
extraBinPaths: [],
|
||||
packDestination: process.cwd(),
|
||||
})
|
||||
await tar.x({ file: 'custom-publish-dir-0.0.0.tgz' })
|
||||
|
||||
expect(await exists('./package/bin.js')).toBeFalsy()
|
||||
expect(await exists('./package/index.ts')).toBeFalsy()
|
||||
expect(await exists('./package/package.json')).toBeTruthy()
|
||||
expect(await exists('./package/a.js')).toBeTruthy()
|
||||
expect(await exists('./package/dist-index.js')).toBeTruthy()
|
||||
expect(await exists('./package/dist-bin.js')).toBeTruthy()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user