mirror of
https://github.com/pnpm/pnpm.git
synced 2025-12-25 08:08:14 -05:00
fix: patch-commit should auto apply patches in workspaces (#6120)
close #6048
This commit is contained in:
6
.changeset/gentle-spies-develop.md
Normal file
6
.changeset/gentle-spies-develop.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-patching": patch
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
`patch-commit` should auto apply patches in workspaces [#6048](https://github.com/pnpm/pnpm/issues/6048)
|
||||
@@ -34,9 +34,11 @@
|
||||
"homepage": "https://github.com/pnpm/pnpm/blob/main/patching/plugin-commands-patching#readme",
|
||||
"devDependencies": {
|
||||
"@pnpm/plugin-commands-patching": "workspace:*",
|
||||
"@pnpm/filter-workspace-packages": "workspace:*",
|
||||
"@pnpm/prepare": "workspace:*",
|
||||
"@pnpm/registry-mock": "3.4.0",
|
||||
"@types/ramda": "0.28.20"
|
||||
"@types/ramda": "0.28.20",
|
||||
"write-yaml-file": "^4.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pnpm/cli-utils": "workspace:*",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { docsUrl } from '@pnpm/cli-utils'
|
||||
import { types as allTypes } from '@pnpm/config'
|
||||
import { Config, types as allTypes } from '@pnpm/config'
|
||||
import { install } from '@pnpm/plugin-commands-installation'
|
||||
import { readPackageJsonFromDir } from '@pnpm/read-package-json'
|
||||
import { tryReadProjectManifest } from '@pnpm/read-project-manifest'
|
||||
@@ -29,7 +29,7 @@ export function help () {
|
||||
})
|
||||
}
|
||||
|
||||
export async function handler (opts: install.InstallCommandOptions, params: string[]) {
|
||||
export async function handler (opts: install.InstallCommandOptions & Pick<Config, 'rootProjectManifest'>, params: string[]) {
|
||||
const userDir = params[0]
|
||||
const lockfileDir = opts.lockfileDir ?? opts.dir ?? process.cwd()
|
||||
const patchesDir = path.join(lockfileDir, 'patches')
|
||||
@@ -41,19 +41,28 @@ export async function handler (opts: install.InstallCommandOptions, params: stri
|
||||
const patchContent = await diffFolders(srcDir, userDir)
|
||||
const patchFileName = pkgNameAndVersion.replace('/', '__')
|
||||
await fs.promises.writeFile(path.join(patchesDir, `${patchFileName}.patch`), patchContent, 'utf8')
|
||||
let { manifest, writeProjectManifest } = await tryReadProjectManifest(lockfileDir)
|
||||
if (!manifest) {
|
||||
manifest = {}
|
||||
}
|
||||
if (!manifest.pnpm) {
|
||||
manifest.pnpm = {
|
||||
const { writeProjectManifest, manifest } = await tryReadProjectManifest(lockfileDir)
|
||||
|
||||
const rootProjectManifest = opts.rootProjectManifest ?? manifest ?? {}
|
||||
|
||||
if (!rootProjectManifest.pnpm) {
|
||||
rootProjectManifest.pnpm = {
|
||||
patchedDependencies: {},
|
||||
}
|
||||
} else if (!manifest.pnpm.patchedDependencies) {
|
||||
manifest.pnpm.patchedDependencies = {}
|
||||
} else if (!rootProjectManifest.pnpm.patchedDependencies) {
|
||||
rootProjectManifest.pnpm.patchedDependencies = {}
|
||||
}
|
||||
manifest.pnpm.patchedDependencies![pkgNameAndVersion] = `patches/${patchFileName}.patch`
|
||||
await writeProjectManifest(manifest)
|
||||
rootProjectManifest.pnpm.patchedDependencies![pkgNameAndVersion] = `patches/${patchFileName}.patch`
|
||||
await writeProjectManifest(rootProjectManifest)
|
||||
|
||||
if (opts?.selectedProjectsGraph?.[lockfileDir]) {
|
||||
opts.selectedProjectsGraph[lockfileDir].package.manifest = rootProjectManifest
|
||||
}
|
||||
|
||||
if (opts?.allProjectsGraph?.[lockfileDir].package.manifest) {
|
||||
opts.allProjectsGraph[lockfileDir].package.manifest = rootProjectManifest
|
||||
}
|
||||
|
||||
return install.handler(opts)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import fs from 'fs'
|
||||
import os from 'os'
|
||||
import path from 'path'
|
||||
import { prepare } from '@pnpm/prepare'
|
||||
import { prepare, preparePackages } from '@pnpm/prepare'
|
||||
import { install } from '@pnpm/plugin-commands-installation'
|
||||
import { readProjects } from '@pnpm/filter-workspace-packages'
|
||||
import writeYamlFile from 'write-yaml-file'
|
||||
import tempy from 'tempy'
|
||||
import { patch, patchCommit } from '@pnpm/plugin-commands-patching'
|
||||
import { readProjectManifest } from '@pnpm/read-project-manifest'
|
||||
@@ -263,6 +266,106 @@ describe('patching should work when there is a no EOL in the patched file', () =
|
||||
})
|
||||
})
|
||||
|
||||
describe('patch and commit in workspaces', () => {
|
||||
let defaultPatchOption: patch.PatchCommandOptions
|
||||
let cacheDir: string
|
||||
let storeDir: string
|
||||
|
||||
beforeEach(() => {
|
||||
preparePackages([
|
||||
{
|
||||
location: '.',
|
||||
package: {
|
||||
name: 'patch-commit-workspaces',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'project-1',
|
||||
version: '1.0.0',
|
||||
dependencies: {
|
||||
'is-positive': '1.0.0',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'project-2',
|
||||
version: '1.0.0',
|
||||
dependencies: {
|
||||
'is-positive': '1.0.0',
|
||||
'project-1': '1',
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
cacheDir = path.resolve('cache')
|
||||
storeDir = path.resolve('store')
|
||||
|
||||
defaultPatchOption = {
|
||||
cacheDir,
|
||||
dir: process.cwd(),
|
||||
pnpmHomeDir: '',
|
||||
rawConfig: {
|
||||
registry: `http://localhost:${REGISTRY_MOCK_PORT}/`,
|
||||
},
|
||||
registries: { default: `http://localhost:${REGISTRY_MOCK_PORT}/` },
|
||||
storeDir,
|
||||
userConfig: {},
|
||||
}
|
||||
})
|
||||
|
||||
test('patch commit should work in workspaces', async () => {
|
||||
await writeYamlFile('pnpm-workspace.yaml', { packages: ['project-1', 'project-2'] })
|
||||
const { allProjects, allProjectsGraph, selectedProjectsGraph } = await readProjects(process.cwd(), [])
|
||||
await install.handler({
|
||||
...DEFAULT_OPTS,
|
||||
cacheDir,
|
||||
storeDir,
|
||||
allProjects,
|
||||
allProjectsGraph,
|
||||
dir: process.cwd(),
|
||||
selectedProjectsGraph,
|
||||
workspaceDir: process.cwd(),
|
||||
saveLockfile: true,
|
||||
})
|
||||
|
||||
const output = await patch.handler(defaultPatchOption, ['is-positive@1.0.0'])
|
||||
const patchDir = getPatchDirFromPatchOutput(output)
|
||||
const tempDir = os.tmpdir()
|
||||
|
||||
expect(patchDir).toContain(tempDir)
|
||||
expect(fs.existsSync(patchDir)).toBe(true)
|
||||
|
||||
expect(fs.readFileSync(path.join(patchDir, 'license'), 'utf8')).toContain('The MIT License (MIT)')
|
||||
|
||||
fs.appendFileSync(path.join(patchDir, 'index.js'), '// test patching', 'utf8')
|
||||
fs.unlinkSync(path.join(patchDir, 'license'))
|
||||
|
||||
await patchCommit.handler({
|
||||
...DEFAULT_OPTS,
|
||||
allProjects,
|
||||
allProjectsGraph,
|
||||
selectedProjectsGraph,
|
||||
dir: process.cwd(),
|
||||
cacheDir,
|
||||
storeDir,
|
||||
lockfileDir: process.cwd(),
|
||||
workspaceDir: process.cwd(),
|
||||
saveLockfile: true,
|
||||
}, [patchDir])
|
||||
|
||||
const { manifest } = await readProjectManifest(process.cwd())
|
||||
expect(manifest.pnpm?.patchedDependencies).toStrictEqual({
|
||||
'is-positive@1.0.0': 'patches/is-positive@1.0.0.patch',
|
||||
})
|
||||
const patchContent = fs.readFileSync('patches/is-positive@1.0.0.patch', 'utf8')
|
||||
expect(patchContent).toContain('diff --git')
|
||||
expect(patchContent).toContain('// test patching')
|
||||
expect(fs.readFileSync('project-1/node_modules/is-positive/index.js', 'utf8')).toContain('// test patching')
|
||||
expect(fs.existsSync('project-1/node_modules/is-positive/license')).toBe(false)
|
||||
expect(fs.readFileSync('project-2/node_modules/is-positive/index.js', 'utf8')).toContain('// test patching')
|
||||
expect(fs.existsSync('project-2/node_modules/is-positive/license')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
function getPatchDirFromPatchOutput (output: string) {
|
||||
const [firstLine] = output.split('\n')
|
||||
return firstLine.substring(firstLine.indexOf(':') + 1).trim()
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
{
|
||||
"path": "../../store/store-connection-manager"
|
||||
},
|
||||
{
|
||||
"path": "../../workspace/filter-workspace-packages"
|
||||
},
|
||||
{
|
||||
"path": "../apply-patch"
|
||||
}
|
||||
|
||||
6
pnpm-lock.yaml
generated
6
pnpm-lock.yaml
generated
@@ -2519,6 +2519,9 @@ importers:
|
||||
specifier: ^1.0.1
|
||||
version: 1.0.1
|
||||
devDependencies:
|
||||
'@pnpm/filter-workspace-packages':
|
||||
specifier: workspace:*
|
||||
version: link:../../workspace/filter-workspace-packages
|
||||
'@pnpm/plugin-commands-patching':
|
||||
specifier: workspace:*
|
||||
version: 'link:'
|
||||
@@ -2531,6 +2534,9 @@ importers:
|
||||
'@types/ramda':
|
||||
specifier: 0.28.20
|
||||
version: 0.28.20
|
||||
write-yaml-file:
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0
|
||||
|
||||
pkg-manager/client:
|
||||
dependencies:
|
||||
|
||||
@@ -168,7 +168,7 @@ export async function main (inputArgv: string[]) {
|
||||
}
|
||||
|
||||
if (
|
||||
(cmd === 'install' || cmd === 'import' || cmd === "dedupe") &&
|
||||
(cmd === 'install' || cmd === 'import' || cmd === 'dedupe' || cmd === 'patch-commit') &&
|
||||
typeof workspaceDir === 'string'
|
||||
) {
|
||||
cliOptions['recursive'] = true
|
||||
|
||||
Reference in New Issue
Block a user