diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index 7ac6b91e1de32c..9686d61a9ce826 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -203,14 +203,14 @@ This is an advance field and it's recommend you seek a config review before appl ## bumpVersion -Currently this setting supports `npm` only, so raise a feature request if you have a use for it with other package managers. +Currently this setting supports `helmv3` and `npm` only, so raise a feature request if you have a use for it with other package managers. It's purpose is if you want Renovate to update the `version` field within your file's `package.json` any time it updates dependencies within. Usually this is for automatic release purposes, so that you don't need to add another step after Renovate before you can release a new version. Configure this value to `"patch"`, `"minor"` or `"major"` to have Renovate update the version in your edited `package.json`. e.g. if you wish Renovate to always increase the target `package.json` version with a patch update, configure this to `"patch"`. -You can also configure this field to `"mirror:x"` where `x` is the name of a package in the `package.json`. +For `npm` only you can also configure this field to `"mirror:x"` where `x` is the name of a package in the `package.json`. Doing so means that the `package.json` `version` field will mirror whatever the version is that `x` depended on. Make sure that version is a pinned version of course, as otherwise it won't be valid. diff --git a/lib/config/definitions.ts b/lib/config/definitions.ts index 4b76f936e72e92..f580a3a83388ef 100644 --- a/lib/config/definitions.ts +++ b/lib/config/definitions.ts @@ -1023,7 +1023,7 @@ const options: RenovateOptions[] = [ }, { name: 'bumpVersion', - description: 'Bump the version in the package.json being updated', + description: 'Bump the version in the package file being updated', type: 'string', allowedValues: ['major', 'minor', 'patch'], }, diff --git a/lib/manager/common.ts b/lib/manager/common.ts index 654e79489835b6..8cfa32501ead31 100644 --- a/lib/manager/common.ts +++ b/lib/manager/common.ts @@ -225,6 +225,12 @@ export interface ManagerApi { language?: string; supportsLockFileMaintenance?: boolean; + bumpPackageVersion?( + content: string, + currentValue: string, + bumpVersion: ReleaseType | string + ): Result; + extractAllPackageFiles?( config: ExtractConfig, files: string[] diff --git a/lib/manager/helmv3/__snapshots__/extract.spec.ts.snap b/lib/manager/helmv3/__snapshots__/extract.spec.ts.snap index 624293839e15af..460d146a0ab52d 100644 --- a/lib/manager/helmv3/__snapshots__/extract.spec.ts.snap +++ b/lib/manager/helmv3/__snapshots__/extract.spec.ts.snap @@ -19,6 +19,7 @@ Object { ], }, ], + "packageFileVersion": "0.1.0", } `; @@ -34,6 +35,7 @@ Object { ], }, ], + "packageFileVersion": "0.1.0", } `; @@ -63,6 +65,7 @@ Object { "skipReason": "no-repository", }, ], + "packageFileVersion": "0.1.0", } `; @@ -86,5 +89,6 @@ Object { "skipReason": "local-dependency", }, ], + "packageFileVersion": "0.1.0", } `; diff --git a/lib/manager/helmv3/__snapshots__/update.spec.ts.snap b/lib/manager/helmv3/__snapshots__/update.spec.ts.snap new file mode 100644 index 00000000000000..d9413b5b4ab0c1 --- /dev/null +++ b/lib/manager/helmv3/__snapshots__/update.spec.ts.snap @@ -0,0 +1,15 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`lib/manager/helmv3/update .bumpPackageVersion() increments 1`] = ` +"apiVersion: v2 +name: test +version: 0.0.3 +" +`; + +exports[`lib/manager/helmv3/update .bumpPackageVersion() updates 1`] = ` +"apiVersion: v2 +name: test +version: 0.1.0 +" +`; diff --git a/lib/manager/helmv3/extract.ts b/lib/manager/helmv3/extract.ts index f81f075a565542..4f5c2709985ffc 100644 --- a/lib/manager/helmv3/extract.ts +++ b/lib/manager/helmv3/extract.ts @@ -37,6 +37,7 @@ export function extractPackageFile( logger.debug({ fileName }, 'Failed to parse helm Chart.yaml'); return null; } + const packageFileVersion = chart.version; let deps: PackageDependency[] = []; if (!is.nonEmptyArray(chart?.dependencies)) { logger.debug({ fileName }, 'Chart has no dependencies'); @@ -84,6 +85,7 @@ export function extractPackageFile( const res = { deps, datasource: datasourceHelm.id, + packageFileVersion, }; return res; } diff --git a/lib/manager/helmv3/index.ts b/lib/manager/helmv3/index.ts index 0152904b54d2f3..a2a9b0a841b3a1 100644 --- a/lib/manager/helmv3/index.ts +++ b/lib/manager/helmv3/index.ts @@ -1,5 +1,6 @@ export { updateArtifacts } from './artifacts'; export { extractPackageFile } from './extract'; +export { bumpPackageVersion } from './update'; export const supportsLockFileMaintenance = true; diff --git a/lib/manager/helmv3/update.spec.ts b/lib/manager/helmv3/update.spec.ts new file mode 100644 index 00000000000000..31a892206877c7 --- /dev/null +++ b/lib/manager/helmv3/update.spec.ts @@ -0,0 +1,34 @@ +import yaml from 'js-yaml'; +import * as helmv3Updater from './update'; + +describe('lib/manager/helmv3/update', () => { + describe('.bumpPackageVersion()', () => { + const content = yaml.safeDump({ + apiVersion: 'v2', + name: 'test', + version: '0.0.2', + }); + it('increments', () => { + const res = helmv3Updater.bumpPackageVersion(content, '0.0.2', 'patch'); + expect(res).toMatchSnapshot(); + expect(res).not.toEqual(content); + }); + it('no ops', () => { + const res = helmv3Updater.bumpPackageVersion(content, '0.0.1', 'patch'); + expect(res).toEqual(content); + }); + it('updates', () => { + const res = helmv3Updater.bumpPackageVersion(content, '0.0.1', 'minor'); + expect(res).toMatchSnapshot(); + expect(res).not.toEqual(content); + }); + it('returns content if bumping errors', () => { + const res = helmv3Updater.bumpPackageVersion( + content, + '0.0.2', + true as any + ); + expect(res).toEqual(content); + }); + }); +}); diff --git a/lib/manager/helmv3/update.ts b/lib/manager/helmv3/update.ts new file mode 100644 index 00000000000000..f95a13b87df65a --- /dev/null +++ b/lib/manager/helmv3/update.ts @@ -0,0 +1,41 @@ +import { ReleaseType, inc } from 'semver'; +import { logger } from '../../logger'; + +export function bumpPackageVersion( + content: string, + currentValue: string, + bumpVersion: ReleaseType | string +): string { + logger.debug( + { bumpVersion, currentValue }, + 'Checking if we should bump Chart.yaml version' + ); + let newChartVersion: string; + try { + newChartVersion = inc(currentValue, bumpVersion as ReleaseType); + if (!newChartVersion) { + throw new Error('semver inc failed'); + } + logger.debug({ newChartVersion }); + const bumpedContent = content.replace( + /^(version:\s*).*$/m, + `$1${newChartVersion}` + ); + if (bumpedContent === content) { + logger.debug('Version was already bumped'); + } else { + logger.debug('Bumped Chart.yaml version'); + } + return bumpedContent; + } catch (err) { + logger.warn( + { + content, + currentValue, + bumpVersion, + }, + 'Failed to bumpVersion' + ); + return content; + } +} diff --git a/lib/manager/npm/index.ts b/lib/manager/npm/index.ts index 7f028ab6c88e41..d17181db0e7eef 100644 --- a/lib/manager/npm/index.ts +++ b/lib/manager/npm/index.ts @@ -2,7 +2,7 @@ import { LANGUAGE_JAVASCRIPT } from '../../constants/languages'; import * as npmVersioning from '../../versioning/npm'; export { extractAllPackageFiles } from './extract'; -export { updateDependency } from './update'; +export { bumpPackageVersion, updateDependency } from './update'; export { getRangeStrategy } from './range'; export const language = LANGUAGE_JAVASCRIPT; diff --git a/lib/manager/npm/update.ts b/lib/manager/npm/update.ts index 9ec6d21a43751f..c13903ae58c950 100644 --- a/lib/manager/npm/update.ts +++ b/lib/manager/npm/update.ts @@ -9,9 +9,6 @@ export function bumpPackageVersion( currentValue: string, bumpVersion: ReleaseType | string ): string { - if (!bumpVersion) { - return content; - } logger.debug( { bumpVersion, currentValue }, 'Checking if we should bump package.json version' @@ -89,11 +86,7 @@ export function updateDependency({ const oldVersion: string = parsedContents[depType][depName]; if (oldVersion === newValue) { logger.trace('Version is already updated'); - return bumpPackageVersion( - fileContent, - upgrade.packageFileVersion, - upgrade.bumpVersion - ); + return fileContent; } // Update the file = this is what we want parsedContents[depType][depName] = newValue; @@ -180,11 +173,7 @@ export function updateDependency({ } } } - return bumpPackageVersion( - newFileContent, - upgrade.packageFileVersion, - upgrade.bumpVersion - ); + return newFileContent; } catch (err) { logger.debug({ err }, 'updateDependency error'); return null; diff --git a/lib/workers/branch/__snapshots__/get-updated.spec.ts.snap b/lib/workers/branch/__snapshots__/get-updated.spec.ts.snap index 1917689508f564..84acb475c96cb7 100644 --- a/lib/workers/branch/__snapshots__/get-updated.spec.ts.snap +++ b/lib/workers/branch/__snapshots__/get-updated.spec.ts.snap @@ -1,5 +1,33 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`workers/branch/get-updated getUpdatedPackageFiles() bumps versions in autoReplace managers 1`] = ` +Object { + "artifactErrors": Array [], + "reuseExistingBranch": undefined, + "updatedArtifacts": Array [], + "updatedPackageFiles": Array [ + Object { + "contents": "version: 0.0.2", + "name": "undefined", + }, + ], +} +`; + +exports[`workers/branch/get-updated getUpdatedPackageFiles() bumps versions in updateDependency managers 1`] = ` +Object { + "artifactErrors": Array [], + "reuseExistingBranch": undefined, + "updatedArtifacts": Array [], + "updatedPackageFiles": Array [ + Object { + "contents": "new version", + "name": "undefined", + }, + ], +} +`; + exports[`workers/branch/get-updated getUpdatedPackageFiles() handles autoreplace base updated 1`] = ` Object { "artifactErrors": Array [], diff --git a/lib/workers/branch/get-updated.spec.ts b/lib/workers/branch/get-updated.spec.ts index 2fcf25c41a7e1e..baafc2c8d51eaf 100644 --- a/lib/workers/branch/get-updated.spec.ts +++ b/lib/workers/branch/get-updated.spec.ts @@ -2,6 +2,7 @@ import { defaultConfig, git, mocked } from '../../../test/util'; import * as datasourceGitSubmodules from '../../datasource/git-submodules'; import * as _composer from '../../manager/composer'; import * as _gitSubmodules from '../../manager/git-submodules'; +import * as _helmv3 from '../../manager/helmv3'; import * as _npm from '../../manager/npm'; import { BranchConfig } from '../common'; import * as _autoReplace from './auto-replace'; @@ -9,10 +10,12 @@ import { getUpdatedPackageFiles } from './get-updated'; const composer = mocked(_composer); const gitSubmodules = mocked(_gitSubmodules); +const helmv3 = mocked(_helmv3); const npm = mocked(_npm); const autoReplace = mocked(_autoReplace); jest.mock('../../manager/composer'); +jest.mock('../../manager/helmv3'); jest.mock('../../manager/npm'); jest.mock('../../manager/git-submodules'); jest.mock('../../util/git'); @@ -169,5 +172,27 @@ describe('workers/branch/get-updated', () => { const res = await getUpdatedPackageFiles(config); expect(res).toMatchSnapshot(); }); + it('bumps versions in updateDependency managers', async () => { + config.upgrades.push({ + branchName: undefined, + bumpVersion: 'patch', + manager: 'npm', + }); + npm.updateDependency.mockReturnValue('old version'); + npm.bumpPackageVersion.mockReturnValue('new version'); + const res = await getUpdatedPackageFiles(config); + expect(res).toMatchSnapshot(); + }); + it('bumps versions in autoReplace managers', async () => { + config.upgrades.push({ + branchName: undefined, + bumpVersion: 'patch', + manager: 'helmv3', + }); + autoReplace.doAutoReplace.mockResolvedValueOnce('version: 0.0.1'); + helmv3.bumpPackageVersion.mockReturnValue('version: 0.0.2'); + const res = await getUpdatedPackageFiles(config); + expect(res).toMatchSnapshot(); + }); }); }); diff --git a/lib/workers/branch/get-updated.ts b/lib/workers/branch/get-updated.ts index 66a2c8b04a099e..89248a98c48d07 100644 --- a/lib/workers/branch/get-updated.ts +++ b/lib/workers/branch/get-updated.ts @@ -56,14 +56,22 @@ export async function getUpdatedPackageFiles( reuseExistingBranch: false, }); } + const bumpPackageVersion = get(manager, 'bumpPackageVersion'); const updateDependency = get(manager, 'updateDependency'); if (!updateDependency) { - const res = await doAutoReplace( + let res = await doAutoReplace( upgrade, existingContent, reuseExistingBranch ); if (res) { + if (bumpPackageVersion && upgrade.bumpVersion) { + res = await bumpPackageVersion( + res, + upgrade.packageFileVersion, + upgrade.bumpVersion + ); + } if (res === existingContent) { logger.debug({ packageFile, depName }, 'No content changed'); if (upgrade.rangeStrategy === 'update-lockfile') { @@ -84,10 +92,17 @@ export async function getUpdatedPackageFiles( logger.error({ packageFile, depName }, 'Could not autoReplace'); throw new Error(WORKER_FILE_UPDATE_FAILED); } - const newContent = await updateDependency({ + let newContent = await updateDependency({ fileContent: existingContent, upgrade, }); + if (bumpPackageVersion && upgrade.bumpVersion) { + newContent = await bumpPackageVersion( + newContent, + upgrade.packageFileVersion, + upgrade.bumpVersion + ); + } if (!newContent) { if (config.reuseExistingBranch) { logger.debug(