diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index cec8095debea21d7342e5d71e1ab3cf61e111a08..94c6e74e0c5a98b036c450a112f1f45d5dc36dff 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -1924,6 +1924,7 @@ This way Renovate can use GitHub's [Commit signing support for bots and other Gi ## postUpdateOptions +- `bundlerConservative`: Enable conservative mode for `bundler` (Ruby dependencies). This will only update the immediate dependency in the lockfile instead of all subdependencies - `gomodMassage`: Enable massaging `replace` directives before calling `go` commands - `gomodTidy`: Run `go mod tidy` after Go module updates. This is implicitly enabled for major module updates when `gomodUpdateImportPaths` is enabled - `gomodTidy1.17`: Run `go mod tidy -compat=1.17` after Go module updates. diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index 4f4920eded6bfb1d47b86c36cf73c6c480b45373..37bb30e434b1448bbea632063b42e21097c6ceff 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -1853,6 +1853,7 @@ const options: RenovateOptions[] = [ type: 'array', default: [], allowedValues: [ + 'bundlerConservative', 'gomodMassage', 'gomodUpdateImportPaths', 'gomodTidy', diff --git a/lib/modules/manager/bundler/artifacts.spec.ts b/lib/modules/manager/bundler/artifacts.spec.ts index 47807c32bb1b7f5ddaac36566474a069a6068744..46fe6e91a7fdb64cc57e56c2a48a0a3c2a1961bb 100644 --- a/lib/modules/manager/bundler/artifacts.spec.ts +++ b/lib/modules/manager/bundler/artifacts.spec.ts @@ -128,6 +128,36 @@ describe('modules/manager/bundler/artifacts', () => { expect(execSnapshots).toMatchSnapshot(); }); + it('supports conservative mode', async () => { + fs.readLocalFile.mockResolvedValueOnce('Current Gemfile.lock'); + fs.writeLocalFile.mockResolvedValueOnce(); + fs.readLocalFile.mockResolvedValueOnce(null); + const execSnapshots = mockExecAll(exec); + git.getRepoStatus.mockResolvedValueOnce({ + modified: ['Gemfile.lock'], + } as StatusResult); + fs.readLocalFile.mockResolvedValueOnce('Updated Gemfile.lock'); + expect( + await updateArtifacts({ + packageFileName: 'Gemfile', + updatedDeps: [{ depName: 'foo' }, { depName: 'bar' }], + newPackageFileContent: 'Updated Gemfile content', + config: { + ...config, + postUpdateOptions: [ + ...(config.postUpdateOptions ?? []), + 'bundlerConservative', + ], + }, + }) + ).toEqual([updatedGemfileLock]); + expect(execSnapshots).toMatchObject([ + expect.objectContaining({ + cmd: 'bundler lock --conservative --update foo bar', + }), + ]); + }); + describe('Docker', () => { beforeEach(() => { GlobalConfig.set({ diff --git a/lib/modules/manager/bundler/artifacts.ts b/lib/modules/manager/bundler/artifacts.ts index f628afb66ac1e6cb97a4bda5752f77b241ccd0a2..495260a1c5dfd3154d4d182514b6f8ecb6118db4 100644 --- a/lib/modules/manager/bundler/artifacts.ts +++ b/lib/modules/manager/bundler/artifacts.ts @@ -1,4 +1,5 @@ import { lt } from '@renovatebot/ruby-semver'; +import is from '@sindresorhus/is'; import { quote } from 'shlex'; import { BUNDLER_INVALID_CREDENTIALS, @@ -61,6 +62,12 @@ export async function updateArtifacts( return null; } + const args = [ + config.postUpdateOptions?.includes('bundlerConservative') && + '--conservative', + '--update', + ].filter(is.nonEmptyString); + try { await writeLocalFile(packageFileName, newPackageFileContent); @@ -69,7 +76,7 @@ export async function updateArtifacts( if (config.isLockFileMaintenance) { cmd = 'bundler lock --update'; } else { - cmd = `bundler lock --update ${updatedDeps + cmd = `bundler lock ${args.join(' ')} ${updatedDeps .map((dep) => `${dep.depName}`) .filter((dep) => dep !== 'ruby') .map(quote)