Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/famous-rocks-glow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@pnpm/lifecycle": patch
pnpm: patch
---

Quote args for scripts with shell-quote to support new lines (on POSIX only) [#8980](https://github.com/pnpm/pnpm/issues/8980).
2 changes: 2 additions & 0 deletions exec/lifecycle/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@pnpm/types": "workspace:*",
"is-windows": "catalog:",
"path-exists": "catalog:",
"shell-quote": "catalog:",
"run-groups": "catalog:"
},
"devDependencies": {
Expand All @@ -55,6 +56,7 @@
"@pnpm/test-ipc-server": "workspace:*",
"@types/is-windows": "catalog:",
"@types/rimraf": "catalog:",
"@types/shell-quote": "catalog:",
"@zkochan/rimraf": "catalog:",
"load-json-file": "catalog:"
},
Expand Down
8 changes: 6 additions & 2 deletions exec/lifecycle/src/runLifecycleHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { type DependencyManifest, type ProjectManifest, type PrepareExecutionEnv
import { PnpmError } from '@pnpm/error'
import { existsSync } from 'fs'
import isWindows from 'is-windows'
import { quote as shellQuote } from 'shell-quote'

function noop () {} // eslint-disable-line:no-empty

Expand Down Expand Up @@ -87,8 +88,11 @@ Please unset the script-shell option, or configure it to a .exe instead.
break
}
if (opts.args?.length && m.scripts?.[stage]) {
const escapedArgs = opts.args.map((arg) => JSON.stringify(arg))
m.scripts[stage] = `${m.scripts[stage]} ${escapedArgs.join(' ')}`
// It is impossible to quote a command line argument that contains newline for Windows cmd.
const escapedArgs = isWindows()
? opts.args.map((arg) => JSON.stringify(arg)).join(' ')
: shellQuote(opts.args)
m.scripts[stage] = `${m.scripts[stage]} ${escapedArgs}`
}
// This script is used to prevent the usage of npm or Yarn.
// It does nothing, when pnpm is used, so we may skip its execution.
Expand Down
6 changes: 6 additions & 0 deletions exec/lifecycle/test/fixtures/escape-newline/echo.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env node

const fs = require('fs');
const path = require('path');

fs.writeFileSync(path.join(__dirname, 'output.json'), JSON.stringify(process.argv.slice(2), null, 2))
7 changes: 7 additions & 0 deletions exec/lifecycle/test/fixtures/escape-newline/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "issue-8980",
"version": "1.0.0",
"scripts": {
"echo": "node echo.sh"
}
}
17 changes: 17 additions & 0 deletions exec/lifecycle/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,23 @@ test('runLifecycleHook() escapes the args passed to the script', async () => {
expect((await import(path.join(pkgRoot, 'output.json'))).default).toStrictEqual(['Revert "feature (#1)"'])
})

test('runLifecycleHook() passes newline correctly', async () => {
const pkgRoot = f.find('escape-newline')
const pkg = await import(path.join(pkgRoot, 'package.json'))
await runLifecycleHook('echo', pkg, {
depPath: '[email protected]',
pkgRoot,
rawConfig: {},
rootModulesDir,
unsafePerm: true,
args: ['a\nb'],
})

expect((await import(path.join(pkgRoot, 'output.json'))).default).toStrictEqual([
process.platform === 'win32' ? 'a\\nb' : 'a\nb',
])
})

test('runLifecycleHook() sets frozen-lockfile to false', async () => {
const pkgRoot = f.find('inspect-frozen-lockfile')
await using server = await createTestIpcServer(path.join(pkgRoot, 'test.sock'))
Expand Down
13 changes: 7 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion pnpm/test/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ test('recursive test: pass the args to the command that is specified in the buil

const result = execPnpmSync(['-r', 'test', 'arg', '--flag=true'])

expect((result.stdout as Buffer).toString('utf8')).toMatch(/ts-node test "arg" "--flag=true"/)
expect((result.stdout as Buffer).toString('utf8')).toMatch(
process.platform === 'win32' ? /ts-node test "arg" "--flag=true"/ : /ts-node test arg --flag\\=true/
)
})

test('start: run "node server.js" by default', async () => {
Expand Down