Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(manager/npm): handle pnpm lockfile updates #26770

Merged
merged 20 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
cd4fefb
feat: handle pnpm lockfile update
guillaumeduboc Jan 20, 2024
3add996
Merge branch 'main' into feat/pnpm-lockfile-update
guillaumeduboc Jan 20, 2024
64d1e6e
Update lib/modules/manager/npm/post-update/index.ts
guillaumeduboc Jan 21, 2024
04dcd9d
chore: prettify suggestion
guillaumeduboc Jan 21, 2024
5093211
chore: remove unnecessary options from test
guillaumeduboc Jan 21, 2024
cf70b44
refactor: improve commands definition and logging
guillaumeduboc Jan 21, 2024
74cc623
fix: skip install if only lockfile updates
guillaumeduboc Jan 21, 2024
c460ce8
Merge branch 'main' into feat/pnpm-lockfile-update
guillaumeduboc Jan 21, 2024
ef147fd
Merge branch 'main' into feat/pnpm-lockfile-update
guillaumeduboc Jan 22, 2024
3b591a8
chore: reverting rename
guillaumeduboc Jan 22, 2024
9627ef9
Merge branch 'main' into feat/pnpm-lockfile-update
guillaumeduboc Jan 22, 2024
08d554c
chore: remove wrong comment
guillaumeduboc Jan 22, 2024
20bcbe8
Merge branch 'main' into feat/pnpm-lockfile-update
guillaumeduboc Feb 17, 2024
2f92ca8
chore: skip commands if no upgrades
guillaumeduboc Feb 17, 2024
21706ed
chore: handle pnpm in updateLockedDependency
guillaumeduboc Feb 17, 2024
d266f2d
chore: add test case for lock file updates mixed with regular updates
guillaumeduboc Feb 18, 2024
f6cea8f
chore: improve performance for regular updates
guillaumeduboc Feb 18, 2024
5dabf4f
chore: add test for no upgrades
guillaumeduboc Feb 18, 2024
965dce3
Merge branch 'main' into feat/pnpm-lockfile-update
guillaumeduboc Feb 18, 2024
d1b722f
Merge branch 'main' into feat/pnpm-lockfile-update
guillaumeduboc Feb 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/usage/configuration-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -3327,7 +3327,7 @@ Behavior:
- `bump` = e.g. bump the range even if the new version satisfies the existing range, e.g. `^1.0.0` -> `^1.1.0`
- `replace` = Replace the range with a newer one if the new version falls outside it, and update nothing otherwise
- `widen` = Widen the range with newer one, e.g. `^1.0.0` -> `^1.0.0 || ^2.0.0`
- `update-lockfile` = Update the lock file when in-range updates are available, otherwise `replace` for updates out of range. Works for `bundler`, `cargo`, `composer`, `npm`, `yarn`, `terraform` and `poetry` so far
- `update-lockfile` = Update the lock file when in-range updates are available, otherwise `replace` for updates out of range. Works for `bundler`, `cargo`, `composer`, `npm`, `yarn`, `pnpm`, `terraform` and `poetry` so far
- `in-range-only` = Update the lock file when in-range updates are available, ignore package file updates

Renovate's `"auto"` strategy works like this for npm:
Expand Down
11 changes: 5 additions & 6 deletions lib/modules/manager/npm/post-update/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,14 @@ export function determineLockFileDirs(
const pnpmShrinkwrapDirs: (string | undefined)[] = [];

for (const upgrade of config.upgrades) {
if (upgrade.updateType === 'lockFileMaintenance' || upgrade.isRemediation) {
if (
upgrade.updateType === 'lockFileMaintenance' ||
upgrade.isRemediation === true ||
upgrade.isLockfileUpdate === true
) {
yarnLockDirs.push(upgrade.managerData?.yarnLock);
npmLockDirs.push(upgrade.managerData?.npmLock);
pnpmShrinkwrapDirs.push(upgrade.managerData?.pnpmShrinkwrap);
continue;
}
if (upgrade.isLockfileUpdate) {
yarnLockDirs.push(upgrade.managerData?.yarnLock);
npmLockDirs.push(upgrade.managerData?.npmLock);
}
}

Expand Down
20 changes: 20 additions & 0 deletions lib/modules/manager/npm/post-update/pnpm.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,26 @@ describe('modules/manager/npm/post-update/pnpm', () => {
expect(execSnapshots).toMatchSnapshot();
});

it('performs lock file updates', async () => {
const execSnapshots = mockExecAll();
fs.readLocalFile.mockResolvedValue('package-lock-contents');
const res = await pnpmHelper.generateLockFile('some-folder', {}, config, [
{ packageName: 'some-dep', newVersion: '1.0.1', isLockfileUpdate: true },
{
packageName: 'some-other-dep',
newVersion: '1.1.0',
isLockfileUpdate: true,
},
]);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{
cmd: 'pnpm update --no-save some-dep@1.0.1 some-other-dep@1.1.0 --recursive --lockfile-only --ignore-scripts --ignore-pnpmfile',
},
]);
});

it('performs lock file maintenance', async () => {
const execSnapshots = mockExecAll();
fs.readLocalFile.mockResolvedValue('package-lock-contents');
Expand Down
36 changes: 29 additions & 7 deletions lib/modules/manager/npm/post-update/pnpm.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import is from '@sindresorhus/is';
import { quote } from 'shlex';
import upath from 'upath';
import { GlobalConfig } from '../../../../config/global';
import { TEMPORARY_ERROR } from '../../../../constants/error-messages';
Expand All @@ -10,6 +11,7 @@ import type {
ToolConstraint,
} from '../../../../util/exec/types';
import { deleteLocalFile, readLocalFile } from '../../../../util/fs';
import { uniqueStrings } from '../../../../util/string';
import { parseSingleYaml } from '../../../../util/yaml';
import type { PostUpdateConfig, Upgrade } from '../../types';
import { getNodeToolConstraint } from './node-version';
Expand All @@ -36,7 +38,7 @@ export async function generateLockFile(
let lockFile: string | null = null;
let stdout: string | undefined;
let stderr: string | undefined;
let cmd = 'pnpm';
const commands: string[] = [];
try {
const lazyPgkJson = lazyLoadPackageJson(lockFileDir);
const pnpmToolConstraint: ToolConstraint = {
Expand Down Expand Up @@ -66,16 +68,36 @@ export async function generateLockFile(
extraEnv.NPM_AUTH = env.NPM_AUTH;
extraEnv.NPM_EMAIL = env.NPM_EMAIL;
}
const commands: string[] = [];

cmd = 'pnpm';
let args = 'install --recursive --lockfile-only';
let args = '--recursive --lockfile-only';
if (!GlobalConfig.get('allowScripts') || config.ignoreScripts) {
args += ' --ignore-scripts';
args += ' --ignore-pnpmfile';
}
logger.trace({ cmd, args }, 'pnpm command');
commands.push(`${cmd} ${args}`);
logger.trace({ args }, 'pnpm command options');

if (
upgrades.length === 0 ||
guillaumeduboc marked this conversation as resolved.
Show resolved Hide resolved
!upgrades.every((upgrade) => upgrade.isLockfileUpdate)
) {
// This command updates the lock file based on package.json
commands.push(`pnpm install ${args}`);
}

// rangeStrategy = update-lockfile
const lockUpdates = upgrades.filter((upgrade) => upgrade.isLockfileUpdate);
guillaumeduboc marked this conversation as resolved.
Show resolved Hide resolved

if (lockUpdates.length) {
logger.debug('Performing lockfileUpdate (pnpm)');
commands.push(
`pnpm update --no-save ${lockUpdates
// TODO: types (#22198)
.map((update) => `${update.packageName!}@${update.newVersion!}`)
.filter(uniqueStrings)
.map(quote)
.join(' ')} ${args}`,
);
}

// postUpdateOptions
if (config.postUpdateOptions?.includes('pnpmDedupe')) {
Expand Down Expand Up @@ -104,7 +126,7 @@ export async function generateLockFile(
}
logger.debug(
{
cmd,
commands,
err,
stdout,
stderr,
Expand Down