From 77e106841cd4490353ca23205227ee57fdefef28 Mon Sep 17 00:00:00 2001 From: Rhys Arkins <rhys@arkins.net> Date: Wed, 9 Aug 2023 09:08:22 +0200 Subject: [PATCH] fix(bundler): update patch, minor, major separately (#23770) Co-authored-by: Michael Kriese <michael.kriese@visualon.de> --- lib/modules/manager/bundler/artifacts.spec.ts | 43 +++---------- lib/modules/manager/bundler/artifacts.ts | 60 ++++++++----------- 2 files changed, 34 insertions(+), 69 deletions(-) diff --git a/lib/modules/manager/bundler/artifacts.spec.ts b/lib/modules/manager/bundler/artifacts.spec.ts index 225205793e..f90b772d99 100644 --- a/lib/modules/manager/bundler/artifacts.spec.ts +++ b/lib/modules/manager/bundler/artifacts.spec.ts @@ -16,7 +16,6 @@ import { ExecError } from '../../../util/exec/exec-error'; import type { StatusResult } from '../../../util/git/types'; import * as _datasource from '../../datasource'; import type { UpdateArtifactsConfig } from '../types'; -import { buildArgs } from './artifacts'; import * as _bundlerHostRules from './host-rules'; import { updateArtifacts } from '.'; @@ -51,38 +50,6 @@ const updatedGemfileLock = { }; describe('modules/manager/bundler/artifacts', () => { - describe('buildArgs', () => { - it('returns only --update arg when no config is specified', () => { - const config: UpdateArtifactsConfig = {}; - expect(buildArgs(config)).toStrictEqual(['--update']); - }); - - it('adds --conservative when bundlerConservative is set as postUpdateOption', () => { - const config: UpdateArtifactsConfig = { - postUpdateOptions: ['bundlerConservative'], - }; - expect(buildArgs(config)).toStrictEqual(['--conservative', '--update']); - }); - - it('adds --patch and --strict when update type is patch', () => { - const config: UpdateArtifactsConfig = { updateType: 'patch' }; - expect(buildArgs(config)).toStrictEqual([ - '--patch', - '--strict', - '--update', - ]); - }); - - it('adds --minor and --strict when update type is minor', () => { - const config: UpdateArtifactsConfig = { updateType: 'minor' }; - expect(buildArgs(config)).toStrictEqual([ - '--minor', - '--strict', - '--update', - ]); - }); - }); - describe('updateArtifacts', () => { beforeEach(() => { jest.resetAllMocks(); @@ -196,7 +163,10 @@ describe('modules/manager/bundler/artifacts', () => { expect( await updateArtifacts({ packageFileName: 'Gemfile', - updatedDeps: [{ depName: 'foo' }, { depName: 'bar' }], + updatedDeps: [ + { depName: 'foo', updateType: 'minor' }, + { depName: 'bar', updateType: 'patch' }, + ], newPackageFileContent: 'Updated Gemfile content', config: { ...config, @@ -210,7 +180,10 @@ describe('modules/manager/bundler/artifacts', () => { ).toEqual([updatedGemfileLock]); expect(execSnapshots).toMatchObject([ expect.objectContaining({ - cmd: 'bundler lock --patch --strict --conservative --update foo bar', + cmd: 'bundler lock --patch --strict --conservative --update bar', + }), + expect.objectContaining({ + cmd: 'bundler lock --minor --strict --conservative --update foo', }), ]); }); diff --git a/lib/modules/manager/bundler/artifacts.ts b/lib/modules/manager/bundler/artifacts.ts index 9f25465218..7e363484ce 100644 --- a/lib/modules/manager/bundler/artifacts.ts +++ b/lib/modules/manager/bundler/artifacts.ts @@ -18,11 +18,7 @@ import { import { getRepoStatus } from '../../../util/git'; import { newlineRegex, regEx } from '../../../util/regex'; import { isValid } from '../../versioning/ruby'; -import type { - UpdateArtifact, - UpdateArtifactsConfig, - UpdateArtifactsResult, -} from '../types'; +import type { UpdateArtifact, UpdateArtifactsResult } from '../types'; import { getBundlerConstraint, getLockFilePath, @@ -35,26 +31,6 @@ import { const hostConfigVariablePrefix = 'BUNDLE_'; -export function buildArgs(config: UpdateArtifactsConfig): string[] { - const args: string[] = []; - // --major is the default and does not need to be handled separately. - switch (config.updateType) { - case 'patch': - args.push('--patch', '--strict'); - break; - case 'minor': - args.push('--minor', '--strict'); - break; - } - - if (config.postUpdateOptions?.includes('bundlerConservative')) { - args.push('--conservative'); - } - - args.push('--update'); - return args; -} - function buildBundleHostVariable(hostRule: HostRule): Record<string, string> { if (!hostRule.resolvedHost || hostRule.resolvedHost.includes('-')) { return {}; @@ -108,8 +84,6 @@ export async function updateArtifacts( return null; } - const args = buildArgs(config); - const updatedDepNames = updatedDeps .map(({ depName }) => depName) .filter(is.nonEmptyStringAndNotWhitespace); @@ -117,15 +91,33 @@ export async function updateArtifacts( try { await writeLocalFile(packageFileName, newPackageFileContent); - let cmd: string; + const commands: string[] = []; if (config.isLockFileMaintenance) { - cmd = 'bundler lock --update'; + commands.push('bundler lock --update'); } else { - cmd = `bundler lock ${args.join(' ')} ${updatedDepNames - .filter((dep) => dep !== 'ruby') - .map(quote) - .join(' ')}`; + const updateTypes = { + patch: '--patch --strict ', + minor: '--minor --strict ', + major: '', + }; + for (const [updateType, updateArg] of Object.entries(updateTypes)) { + const deps = updatedDeps + .filter((dep) => (dep.updateType ?? 'major') === updateType) + .map((dep) => dep.depName) + .filter(is.string) + .filter((dep) => dep !== 'ruby'); + let additionalArgs = ''; + if (config.postUpdateOptions?.includes('bundlerConservative')) { + additionalArgs = '--conservative '; + } + if (deps.length) { + const cmd = `bundler lock ${updateArg}${additionalArgs}--update ${deps + .map(quote) + .join(' ')}`; + commands.push(cmd); + } + } } const bundlerHostRules = findAllAuthenticatable({ @@ -200,7 +192,7 @@ export async function updateArtifacts( ], preCommands, }; - await exec(cmd, execOptions); + await exec(commands, execOptions); const status = await getRepoStatus(); if (!status.modified.includes(lockFileName)) { -- GitLab