Skip to content

Commit

Permalink
fix(plugin-commands-publishing): should pack main file or bin files d…
Browse files Browse the repository at this point in the history
…efined in publishConfig (#7538)

close #4195
  • Loading branch information
await-ovo committed Jan 20, 2024
1 parent 04f6233 commit e363af8
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 24 deletions.
8 changes: 8 additions & 0 deletions .changeset/smooth-buckets-drop.md
Original file line number Diff line number Diff line change
@@ -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 changes: 1 addition & 1 deletion __typings__/typed.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
9 changes: 7 additions & 2 deletions fs/packlist/src/index.ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down
60 changes: 39 additions & 21 deletions releasing/plugin-commands-publishing/src/pack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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 })
Expand All @@ -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)
Expand All @@ -125,42 +139,35 @@ 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
}

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))
Expand All @@ -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 })
}
37 changes: 37 additions & 0 deletions releasing/plugin-commands-publishing/test/pack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
})

0 comments on commit e363af8

Please sign in to comment.