From 9137121fb417ac8db9ec0f62981c6a983a2410fe Mon Sep 17 00:00:00 2001 From: chgl Date: Sat, 9 Jan 2021 15:38:30 +0000 Subject: [PATCH 1/7] wip: added support for bumping chart version from helm-values updates --- docs/usage/configuration-options.md | 2 +- lib/manager/common.ts | 3 +- .../__snapshots__/update.spec.ts.snap | 15 +++++ lib/manager/helm-values/extract.spec.ts | 36 ++++++++---- lib/manager/helm-values/extract.ts | 22 ++++++- lib/manager/helm-values/index.ts | 1 + lib/manager/helm-values/update.spec.ts | 58 +++++++++++++++++++ lib/manager/helm-values/update.ts | 44 ++++++++++++++ lib/manager/helm-values/util.ts | 52 +++++++++++++++++ lib/workers/branch/get-updated.ts | 6 +- 10 files changed, 223 insertions(+), 16 deletions(-) create mode 100644 lib/manager/helm-values/__snapshots__/update.spec.ts.snap create mode 100644 lib/manager/helm-values/update.spec.ts create mode 100644 lib/manager/helm-values/update.ts diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index d0d5738c2140b2..b4c189a994c4db 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -234,7 +234,7 @@ This is an advance field and it's recommend you seek a config review before appl ## bumpVersion -Currently this setting supports `helmv3` and `npm` only, so raise a feature request if you have a use for it with other package managers. +Currently this setting supports `helmv3`, `helm-values`, and `npm` only, so raise a feature request if you have a use for it with other package managers. Its 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. diff --git a/lib/manager/common.ts b/lib/manager/common.ts index 9f8cffb77a0ce5..5a0f240b920a5d 100644 --- a/lib/manager/common.ts +++ b/lib/manager/common.ts @@ -235,7 +235,8 @@ export interface ManagerApi { bumpPackageVersion?( content: string, currentValue: string, - bumpVersion: ReleaseType | string + bumpVersion: ReleaseType | string, + packageFile?: string ): Result; extractAllPackageFiles?( diff --git a/lib/manager/helm-values/__snapshots__/update.spec.ts.snap b/lib/manager/helm-values/__snapshots__/update.spec.ts.snap new file mode 100644 index 00000000000000..e1be96d3a072eb --- /dev/null +++ b/lib/manager/helm-values/__snapshots__/update.spec.ts.snap @@ -0,0 +1,15 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`lib/manager/helm-values/update .bumpPackageVersion() increments 1`] = ` +"apiVersion: v2 +name: test +version: 0.0.3 +" +`; + +exports[`lib/manager/helm-values/update .bumpPackageVersion() updates 1`] = ` +"apiVersion: v2 +name: test +version: 0.1.0 +" +`; diff --git a/lib/manager/helm-values/extract.spec.ts b/lib/manager/helm-values/extract.spec.ts index eb96bc4773717e..443f64614da38f 100644 --- a/lib/manager/helm-values/extract.spec.ts +++ b/lib/manager/helm-values/extract.spec.ts @@ -1,4 +1,5 @@ import { readFileSync } from 'fs'; +import { fs } from '../../../test/util'; import { extractPackageFile } from './extract'; const helmDefaultChartInitValues = readFileSync( @@ -15,26 +16,41 @@ describe('lib/manager/helm-values/extract', () => { describe('extractPackageFile()', () => { beforeEach(() => { jest.resetAllMocks(); + fs.readLocalFile = jest.fn(); }); - it('returns null for invalid yaml file content', () => { - const result = extractPackageFile('nothing here: ['); + it('returns null for invalid yaml file content', async () => { + const result = await extractPackageFile('nothing here: ['); expect(result).toBeNull(); }); - it('returns null for empty yaml file content', () => { - const result = extractPackageFile(''); + it('returns null for empty yaml file content', async () => { + const result = await extractPackageFile(''); expect(result).toBeNull(); }); - it('returns null for no file content', () => { - const result = extractPackageFile(null); + it('returns null for no file content', async () => { + const result = await extractPackageFile(null); expect(result).toBeNull(); }); - it('extracts from values.yaml correctly with same structure as "helm create"', () => { - const result = extractPackageFile(helmDefaultChartInitValues); + it('extracts from values.yaml correctly with same structure as "helm create"', async () => { + const result = await extractPackageFile(helmDefaultChartInitValues); expect(result).toMatchSnapshot(); }); - it('extracts from complex values file correctly"', () => { - const result = extractPackageFile(helmMultiAndNestedImageValues); + it('extracts from complex values file correctly"', async () => { + const result = await extractPackageFile(helmMultiAndNestedImageValues); expect(result).toMatchSnapshot(); }); + it('returns the package file version from the sibling Chart.yaml"', async () => { + fs.readLocalFile.mockResolvedValueOnce(` + apiVersion: v2 + appVersion: "1.0" + description: A Helm chart for Kubernetes + name: example + version: 0.1.0 + `); + const result = await extractPackageFile( + helmMultiAndNestedImageValues, + 'values.yaml' + ); + expect(result.packageFileVersion).toBe('0.1.0'); + }); }); }); diff --git a/lib/manager/helm-values/extract.ts b/lib/manager/helm-values/extract.ts index da5b127a65bd02..e35cb54b10476b 100644 --- a/lib/manager/helm-values/extract.ts +++ b/lib/manager/helm-values/extract.ts @@ -6,6 +6,7 @@ import { getDep } from '../dockerfile/extract'; import { HelmDockerImageDependency, + getParsedSiblingChartYaml, matchesHelmValuesDockerHeuristic, } from './util'; @@ -53,7 +54,10 @@ function findDependencies( return packageDependencies; } -export function extractPackageFile(content: string): PackageFile { +export async function extractPackageFile( + content: string, + fileName?: string +): Promise { let parsedContent: Record | HelmDockerImageDependency; try { // a parser that allows extracting line numbers would be preferable, with @@ -68,7 +72,21 @@ export function extractPackageFile(content: string): PackageFile { const deps = findDependencies(parsedContent, []); if (deps.length) { logger.debug({ deps }, 'Found dependencies in helm-values'); - return { deps }; + + // in Helm, the current package version is the version of the chart. + // This fetches this version by reading it from the Chart.yaml + // found in the same folder as the currently processed values file. + const siblingChart = await getParsedSiblingChartYaml(fileName); + const packageFileVersion = siblingChart?.version; + if (packageFileVersion) { + return { + deps, + packageFileVersion, + }; + } + return { + deps, + }; } } catch (err) /* istanbul ignore next */ { logger.error({ err }, 'Error parsing helm-values parsed content'); diff --git a/lib/manager/helm-values/index.ts b/lib/manager/helm-values/index.ts index 1ef75d28735eca..11d8f2279aefae 100644 --- a/lib/manager/helm-values/index.ts +++ b/lib/manager/helm-values/index.ts @@ -1,4 +1,5 @@ export { extractPackageFile } from './extract'; +export { bumpPackageVersion } from './update'; export const defaultConfig = { commitMessageTopic: 'helm values {{depName}}', diff --git a/lib/manager/helm-values/update.spec.ts b/lib/manager/helm-values/update.spec.ts new file mode 100644 index 00000000000000..f8797e13861d70 --- /dev/null +++ b/lib/manager/helm-values/update.spec.ts @@ -0,0 +1,58 @@ +import yaml from 'js-yaml'; +import { fs } from '../../../test/util'; +import * as helmValuesUpdater from './update'; + +describe('lib/manager/helm-values/update', () => { + describe('.bumpPackageVersion()', () => { + beforeEach(() => { + jest.resetAllMocks(); + fs.readLocalFile = jest.fn(); + fs.readLocalFile.mockResolvedValueOnce( + yaml.safeDump({ + apiVersion: 'v2', + name: 'test', + version: '0.0.2', + }) + ); + }); + const content = ''; + it('increments', async () => { + const res = await helmValuesUpdater.bumpPackageVersion( + content, + '0.0.2', + 'patch', + 'values.yaml' + ); + expect(res).toMatchSnapshot(); + expect(res).not.toEqual(content); + }); + it('no ops', async () => { + const res = await helmValuesUpdater.bumpPackageVersion( + content, + '0.0.1', + 'patch', + 'values.yaml' + ); + expect(res).toEqual(content); + }); + it('updates', async () => { + const res = await helmValuesUpdater.bumpPackageVersion( + content, + '0.0.1', + 'minor', + 'values.yaml' + ); + expect(res).toMatchSnapshot(); + expect(res).not.toEqual(content); + }); + it('returns content if bumping errors', async () => { + const res = await helmValuesUpdater.bumpPackageVersion( + content, + '0.0.2', + true as any, + 'values.yaml' + ); + expect(res).toEqual(content); + }); + }); +}); diff --git a/lib/manager/helm-values/update.ts b/lib/manager/helm-values/update.ts new file mode 100644 index 00000000000000..f924c94174a160 --- /dev/null +++ b/lib/manager/helm-values/update.ts @@ -0,0 +1,44 @@ +import { ReleaseType, inc } from 'semver'; +import { logger } from '../../logger'; +import { getSiblingChartYamlContent } from './util'; + +export async function bumpPackageVersion( + _content: string, + currentValue: string, + bumpVersion: ReleaseType | string, + packageFile: string +): Promise { + logger.debug( + { bumpVersion, currentValue }, + 'Checking if we should bump Chart.yaml version' + ); + const chartYamlContent = await getSiblingChartYamlContent(packageFile); + let newChartVersion: string; + try { + newChartVersion = inc(currentValue, bumpVersion as ReleaseType); + if (!newChartVersion) { + throw new Error('semver inc failed'); + } + logger.debug({ newChartVersion }); + const bumpedContent = chartYamlContent.replace( + /^(version:\s*).*$/m, + `$1${newChartVersion}` + ); + if (bumpedContent === chartYamlContent) { + logger.debug('Version was already bumped'); + } else { + logger.debug('Bumped Chart.yaml version'); + } + return bumpedContent; + } catch (err) { + logger.warn( + { + chartYamlContent, + currentValue, + bumpVersion, + }, + 'Failed to bumpVersion' + ); + return chartYamlContent; + } +} diff --git a/lib/manager/helm-values/util.ts b/lib/manager/helm-values/util.ts index d886c16d006335..ebfc3a37db0bf1 100644 --- a/lib/manager/helm-values/util.ts +++ b/lib/manager/helm-values/util.ts @@ -1,3 +1,6 @@ +import yaml from 'js-yaml'; +import { logger } from '../../logger'; +import { getSiblingFileName, readLocalFile } from '../../util/fs'; import { hasKey } from '../../util/object'; export type HelmDockerImageDependency = { @@ -30,3 +33,52 @@ export function matchesHelmValuesDockerHeuristic( hasKey('tag', data) ); } + +/** + * This function looks for a Chart.yaml in the same directory as @param fileName and + * returns its raw contents. + * + * @param fileName + */ +export async function getSiblingChartYamlContent( + fileName: string +): Promise { + try { + const chartFileName = getSiblingFileName(fileName, 'Chart.yaml'); + return await readLocalFile(chartFileName, 'utf8'); + } catch (err) { + logger.debug({ fileName }, 'Failed to read helm Chart.yaml'); + return null; + } +} + +/** + * This function looks for a Chart.yaml in the same directory as @param fileName and + * if it looks like a valid Helm Chart.yaml, it is parsed and returned as an object. + * + * @param fileName + */ +export async function getParsedSiblingChartYaml( + fileName: string +): Promise { + try { + const chartContents = await getSiblingChartYamlContent(fileName); + if (!chartContents) { + logger.debug({ fileName }, 'Failed to find helm Chart.yaml'); + return null; + } + // TODO: fix me + const chart = yaml.safeLoad(chartContents, { json: true }) as any; + if (!(chart?.apiVersion && chart.name && chart.version)) { + logger.debug( + { fileName }, + 'Failed to find required fields in Chart.yaml' + ); + return null; + } + return chart; + } catch (err) { + logger.debug({ fileName }, 'Failed to parse helm Chart.yaml'); + return null; + } +} diff --git a/lib/workers/branch/get-updated.ts b/lib/workers/branch/get-updated.ts index 89248a98c48d07..a0243a8fbbf1b5 100644 --- a/lib/workers/branch/get-updated.ts +++ b/lib/workers/branch/get-updated.ts @@ -69,7 +69,8 @@ export async function getUpdatedPackageFiles( res = await bumpPackageVersion( res, upgrade.packageFileVersion, - upgrade.bumpVersion + upgrade.bumpVersion, + packageFile ); } if (res === existingContent) { @@ -100,7 +101,8 @@ export async function getUpdatedPackageFiles( newContent = await bumpPackageVersion( newContent, upgrade.packageFileVersion, - upgrade.bumpVersion + upgrade.bumpVersion, + packageFile ); } if (!newContent) { From c6e648424a3dd49ac7554834746addc6bd23ab5f Mon Sep 17 00:00:00 2001 From: chgl Date: Sun, 10 Jan 2021 19:31:10 +0000 Subject: [PATCH 2/7] feat: support for bumping Helm chart version when updating Helm values --- lib/manager/common.ts | 7 ++ lib/manager/helm-values/update.spec.ts | 65 ++++++++++++------- lib/manager/helm-values/update.ts | 16 +++-- .../__snapshots__/get-updated.spec.ts.snap | 14 ++++ lib/workers/branch/get-updated.spec.ts | 20 ++++++ lib/workers/branch/get-updated.ts | 29 +++++++-- 6 files changed, 120 insertions(+), 31 deletions(-) diff --git a/lib/manager/common.ts b/lib/manager/common.ts index 634d350388ccd5..fb628d93134443 100644 --- a/lib/manager/common.ts +++ b/lib/manager/common.ts @@ -229,6 +229,13 @@ export interface UpdateDependencyConfig> { export interface BumpPackageVersionResult { bumpedContent: string | null; + // describes a file that was changed instead of or in addition to the packageFile + bumpedFile?: BumpedPackageFile; +} + +export interface BumpedPackageFile { + fileName: string | null; + newContent: string | null; } export interface ManagerApi { diff --git a/lib/manager/helm-values/update.spec.ts b/lib/manager/helm-values/update.spec.ts index f8797e13861d70..78da3ed33fd839 100644 --- a/lib/manager/helm-values/update.spec.ts +++ b/lib/manager/helm-values/update.spec.ts @@ -4,55 +4,76 @@ import * as helmValuesUpdater from './update'; describe('lib/manager/helm-values/update', () => { describe('.bumpPackageVersion()', () => { + const chartContent = yaml.safeDump({ + apiVersion: 'v2', + name: 'test', + version: '0.0.2', + }); + const helmValuesContent = yaml.safeDump({ + image: { + registry: 'docker.io', + repository: 'docker/whalesay', + tag: '1.0.0', + }, + }); beforeEach(() => { jest.resetAllMocks(); fs.readLocalFile = jest.fn(); - fs.readLocalFile.mockResolvedValueOnce( - yaml.safeDump({ - apiVersion: 'v2', - name: 'test', - version: '0.0.2', - }) - ); + fs.readLocalFile.mockResolvedValueOnce(chartContent); }); - const content = ''; it('increments', async () => { - const res = await helmValuesUpdater.bumpPackageVersion( - content, + const { + bumpedContent, + bumpedFile, + } = await helmValuesUpdater.bumpPackageVersion( + helmValuesContent, '0.0.2', 'patch', 'values.yaml' ); - expect(res).toMatchSnapshot(); - expect(res).not.toEqual(content); + expect(bumpedContent).toEqual(helmValuesContent); + expect(bumpedFile.fileName).toEqual('Chart.yaml'); + expect(bumpedFile.newContent).toMatchSnapshot(); }); it('no ops', async () => { - const res = await helmValuesUpdater.bumpPackageVersion( - content, + const { + bumpedContent, + bumpedFile, + } = await helmValuesUpdater.bumpPackageVersion( + helmValuesContent, '0.0.1', 'patch', 'values.yaml' ); - expect(res).toEqual(content); + expect(bumpedContent).toEqual(helmValuesContent); + expect(bumpedFile.newContent).toEqual(chartContent); }); it('updates', async () => { - const res = await helmValuesUpdater.bumpPackageVersion( - content, + const { + bumpedContent, + bumpedFile, + } = await helmValuesUpdater.bumpPackageVersion( + helmValuesContent, '0.0.1', 'minor', 'values.yaml' ); - expect(res).toMatchSnapshot(); - expect(res).not.toEqual(content); + expect(bumpedContent).toEqual(helmValuesContent); + expect(bumpedFile.newContent).toMatchSnapshot(); + expect(bumpedFile.fileName).toEqual('Chart.yaml'); }); it('returns content if bumping errors', async () => { - const res = await helmValuesUpdater.bumpPackageVersion( - content, + const { + bumpedContent, + bumpedFile, + } = await helmValuesUpdater.bumpPackageVersion( + helmValuesContent, '0.0.2', true as any, 'values.yaml' ); - expect(res).toEqual(content); + expect(bumpedContent).toEqual(helmValuesContent); + expect(bumpedFile).toBeUndefined(); }); }); }); diff --git a/lib/manager/helm-values/update.ts b/lib/manager/helm-values/update.ts index f924c94174a160..8c7e0199b735f5 100644 --- a/lib/manager/helm-values/update.ts +++ b/lib/manager/helm-values/update.ts @@ -1,17 +1,20 @@ import { ReleaseType, inc } from 'semver'; import { logger } from '../../logger'; +import { getSiblingFileName } from '../../util/fs'; +import { BumpPackageVersionResult } from '../common'; import { getSiblingChartYamlContent } from './util'; export async function bumpPackageVersion( - _content: string, + content: string, currentValue: string, bumpVersion: ReleaseType | string, packageFile: string -): Promise { +): Promise { logger.debug( { bumpVersion, currentValue }, 'Checking if we should bump Chart.yaml version' ); + const chartFileName = getSiblingFileName(packageFile, 'Chart.yaml'); const chartYamlContent = await getSiblingChartYamlContent(packageFile); let newChartVersion: string; try { @@ -29,7 +32,10 @@ export async function bumpPackageVersion( } else { logger.debug('Bumped Chart.yaml version'); } - return bumpedContent; + return { + bumpedContent: content, + bumpedFile: { fileName: chartFileName, newContent: bumpedContent }, + }; } catch (err) { logger.warn( { @@ -39,6 +45,8 @@ export async function bumpPackageVersion( }, 'Failed to bumpVersion' ); - return chartYamlContent; + return { + bumpedContent: content, + }; } } diff --git a/lib/workers/branch/__snapshots__/get-updated.spec.ts.snap b/lib/workers/branch/__snapshots__/get-updated.spec.ts.snap index 84acb475c96cb7..a9e0c316ca30d0 100644 --- a/lib/workers/branch/__snapshots__/get-updated.spec.ts.snap +++ b/lib/workers/branch/__snapshots__/get-updated.spec.ts.snap @@ -186,3 +186,17 @@ Object { ], } `; + +exports[`workers/branch/get-updated getUpdatedPackageFiles() bumps versions in helm values managers 1`] = ` +Object { + "artifactErrors": Array [], + "reuseExistingBranch": undefined, + "updatedArtifacts": Array [], + "updatedPackageFiles": Array [ + Object { + "contents": "version: 0.0.2", + "name": "/test/Chart.yaml", + }, + ], +} +`; diff --git a/lib/workers/branch/get-updated.spec.ts b/lib/workers/branch/get-updated.spec.ts index dd260a02b19e24..de81000d7908e9 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 _helmValues from '../../manager/helm-values'; import * as _helmv3 from '../../manager/helmv3'; import * as _npm from '../../manager/npm'; import { BranchConfig } from '../common'; @@ -11,11 +12,13 @@ import { getUpdatedPackageFiles } from './get-updated'; const composer = mocked(_composer); const gitSubmodules = mocked(_gitSubmodules); const helmv3 = mocked(_helmv3); +const helmValues = mocked(_helmValues); const npm = mocked(_npm); const autoReplace = mocked(_autoReplace); jest.mock('../../manager/composer'); jest.mock('../../manager/helmv3'); +jest.mock('../../manager/helm-values'); jest.mock('../../manager/npm'); jest.mock('../../manager/git-submodules'); jest.mock('../../util/git'); @@ -196,5 +199,22 @@ describe('workers/branch/get-updated', () => { const res = await getUpdatedPackageFiles(config); expect(res).toMatchSnapshot(); }); + it('bumps versions in helm values managers', async () => { + config.upgrades.push({ + branchName: undefined, + bumpVersion: 'patch', + manager: 'helm-values', + }); + autoReplace.doAutoReplace.mockResolvedValueOnce('existing content'); + helmValues.bumpPackageVersion.mockResolvedValue({ + bumpedContent: 'existing content', + bumpedFile: { + fileName: '/test/Chart.yaml', + newContent: '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 90e5645d0018eb..3f3c93976a53c1 100644 --- a/lib/workers/branch/get-updated.ts +++ b/lib/workers/branch/get-updated.ts @@ -3,7 +3,7 @@ import { WORKER_FILE_UPDATE_FAILED } from '../../constants/error-messages'; import * as datasourceGitSubmodules from '../../datasource/git-submodules'; import { logger } from '../../logger'; import { get } from '../../manager'; -import { ArtifactError } from '../../manager/common'; +import { ArtifactError, BumpedPackageFile } from '../../manager/common'; import { File, getFile } from '../../util/git'; import { BranchConfig } from '../common'; import { doAutoReplace } from './auto-replace'; @@ -64,15 +64,18 @@ export async function getUpdatedPackageFiles( existingContent, reuseExistingBranch ); + if (res) { + let bumpedPackageFile: BumpedPackageFile; if (bumpPackageVersion && upgrade.bumpVersion) { - const { bumpedContent } = await bumpPackageVersion( + const bumpResult = await bumpPackageVersion( res, upgrade.packageFileVersion, upgrade.bumpVersion, packageFile ); - res = bumpedContent; + res = bumpResult.bumpedContent; + bumpedPackageFile = bumpResult.bumpedFile; } if (res === existingContent) { logger.debug({ packageFile, depName }, 'No content changed'); @@ -84,6 +87,12 @@ export async function getUpdatedPackageFiles( logger.debug({ packageFile, depName }, 'Contents updated'); updatedFileContents[packageFile] = res; } + // indicates that the version was bumped in another file in + // addition to or instead of the packageFile + if (bumpedPackageFile) { + updatedFileContents[bumpedPackageFile.fileName] = + bumpedPackageFile.newContent; + } continue; // eslint-disable-line no-continue } else if (reuseExistingBranch) { return getUpdatedPackageFiles({ @@ -98,14 +107,16 @@ export async function getUpdatedPackageFiles( fileContent: existingContent, upgrade, }); + let bumpedPackageFile: BumpedPackageFile; if (bumpPackageVersion && upgrade.bumpVersion) { - const { bumpedContent } = await bumpPackageVersion( + const bumpResult = await bumpPackageVersion( newContent, upgrade.packageFileVersion, upgrade.bumpVersion, packageFile ); - newContent = bumpedContent; + newContent = bumpResult.bumpedContent; + bumpedPackageFile = bumpResult.bumpedFile; } if (!newContent) { if (config.reuseExistingBranch) { @@ -147,6 +158,14 @@ export async function getUpdatedPackageFiles( nonUpdatedFileContents[packageFile] = newContent; } } + if (bumpedPackageFile) { + logger.debug( + { bumpedPackageFile, depName }, + 'Updating bumpedPackageFile content' + ); + updatedFileContents[bumpedPackageFile.fileName] = + bumpedPackageFile.newContent; + } } } const updatedPackageFiles = Object.keys(updatedFileContents).map((name) => ({ From 8c3514ce16429be07348388924ba8340deb87cc1 Mon Sep 17 00:00:00 2001 From: chgl Date: Sun, 10 Jan 2021 22:44:09 +0100 Subject: [PATCH 3/7] test(unit): updated tests to achieve 100% coverage --- lib/manager/helm-values/extract.spec.ts | 24 +++++++++++++++++++ .../__snapshots__/get-updated.spec.ts.snap | 2 +- lib/workers/branch/get-updated.spec.ts | 2 +- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/lib/manager/helm-values/extract.spec.ts b/lib/manager/helm-values/extract.spec.ts index 443f64614da38f..4e168e63a6cafe 100644 --- a/lib/manager/helm-values/extract.spec.ts +++ b/lib/manager/helm-values/extract.spec.ts @@ -52,5 +52,29 @@ describe('lib/manager/helm-values/extract', () => { ); expect(result.packageFileVersion).toBe('0.1.0'); }); + it('does not fail if the sibling Chart.yaml is invalid', async () => { + fs.readLocalFile.mockResolvedValueOnce(` + invalidYaml: [ + `); + const result = await extractPackageFile( + helmMultiAndNestedImageValues, + 'values.yaml' + ); + expect(result).not.toBeNull(); + expect(result.packageFileVersion).toBeUndefined(); + }); + it('does not fail if the sibling Chart.yaml does not contain the required fields', async () => { + fs.readLocalFile.mockResolvedValueOnce(` + appVersion: v2 + name: test + version: is-missing + `); + const result = await extractPackageFile( + helmMultiAndNestedImageValues, + 'values.yaml' + ); + expect(result).not.toBeNull(); + expect(result.packageFileVersion).toBeUndefined(); + }); }); }); diff --git a/lib/workers/branch/__snapshots__/get-updated.spec.ts.snap b/lib/workers/branch/__snapshots__/get-updated.spec.ts.snap index a9e0c316ca30d0..0f501466bd6bf0 100644 --- a/lib/workers/branch/__snapshots__/get-updated.spec.ts.snap +++ b/lib/workers/branch/__snapshots__/get-updated.spec.ts.snap @@ -187,7 +187,7 @@ Object { } `; -exports[`workers/branch/get-updated getUpdatedPackageFiles() bumps versions in helm values managers 1`] = ` +exports[`workers/branch/get-updated getUpdatedPackageFiles() bumps versions in autoReplace managers with a bumpPackageFile different from the packageFile 1`] = ` Object { "artifactErrors": Array [], "reuseExistingBranch": undefined, diff --git a/lib/workers/branch/get-updated.spec.ts b/lib/workers/branch/get-updated.spec.ts index de81000d7908e9..fa31c886e3cd97 100644 --- a/lib/workers/branch/get-updated.spec.ts +++ b/lib/workers/branch/get-updated.spec.ts @@ -199,7 +199,7 @@ describe('workers/branch/get-updated', () => { const res = await getUpdatedPackageFiles(config); expect(res).toMatchSnapshot(); }); - it('bumps versions in helm values managers', async () => { + it('bumps versions in autoReplace managers with a bumpPackageFile different from the packageFile', async () => { config.upgrades.push({ branchName: undefined, bumpVersion: 'patch', From adfb18d2540cc4e9c16165f69badf302e3a2f84b Mon Sep 17 00:00:00 2001 From: chgl Date: Sun, 10 Jan 2021 22:45:11 +0100 Subject: [PATCH 4/7] refactor: only support bumpFile updates in autoReplace manager Because there isn't yet any non-autoreplace manager to test this with. --- lib/workers/branch/get-updated.ts | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/lib/workers/branch/get-updated.ts b/lib/workers/branch/get-updated.ts index 3f3c93976a53c1..b4fd810adbe75a 100644 --- a/lib/workers/branch/get-updated.ts +++ b/lib/workers/branch/get-updated.ts @@ -90,6 +90,10 @@ export async function getUpdatedPackageFiles( // indicates that the version was bumped in another file in // addition to or instead of the packageFile if (bumpedPackageFile) { + logger.debug( + { bumpedPackageFile, depName }, + 'Updating bumpedPackageFile content' + ); updatedFileContents[bumpedPackageFile.fileName] = bumpedPackageFile.newContent; } @@ -107,16 +111,14 @@ export async function getUpdatedPackageFiles( fileContent: existingContent, upgrade, }); - let bumpedPackageFile: BumpedPackageFile; if (bumpPackageVersion && upgrade.bumpVersion) { - const bumpResult = await bumpPackageVersion( + const { bumpedContent } = await bumpPackageVersion( newContent, upgrade.packageFileVersion, upgrade.bumpVersion, packageFile ); - newContent = bumpResult.bumpedContent; - bumpedPackageFile = bumpResult.bumpedFile; + newContent = bumpedContent; } if (!newContent) { if (config.reuseExistingBranch) { @@ -158,14 +160,6 @@ export async function getUpdatedPackageFiles( nonUpdatedFileContents[packageFile] = newContent; } } - if (bumpedPackageFile) { - logger.debug( - { bumpedPackageFile, depName }, - 'Updating bumpedPackageFile content' - ); - updatedFileContents[bumpedPackageFile.fileName] = - bumpedPackageFile.newContent; - } } } const updatedPackageFiles = Object.keys(updatedFileContents).map((name) => ({ From 9570c786a4b6359fd1b68c53c15b1104b902164c Mon Sep 17 00:00:00 2001 From: chgl Date: Sun, 10 Jan 2021 22:51:18 +0100 Subject: [PATCH 5/7] test(unit): fix accidentally wrong incorrect mock Chart.yaml --- lib/manager/helm-values/extract.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/manager/helm-values/extract.spec.ts b/lib/manager/helm-values/extract.spec.ts index 4e168e63a6cafe..0618923139bf61 100644 --- a/lib/manager/helm-values/extract.spec.ts +++ b/lib/manager/helm-values/extract.spec.ts @@ -65,9 +65,9 @@ describe('lib/manager/helm-values/extract', () => { }); it('does not fail if the sibling Chart.yaml does not contain the required fields', async () => { fs.readLocalFile.mockResolvedValueOnce(` - appVersion: v2 + apiVersion: v2 name: test - version: is-missing + version-is: missing `); const result = await extractPackageFile( helmMultiAndNestedImageValues, From d265ad2d12f87f5dc3545804e0e00a4e66c9fc07 Mon Sep 17 00:00:00 2001 From: chgl Date: Mon, 11 Jan 2021 00:30:42 +0100 Subject: [PATCH 6/7] refactor: made newChartVersion const and moved inside scope --- lib/manager/helm-values/update.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/manager/helm-values/update.ts b/lib/manager/helm-values/update.ts index 8c7e0199b735f5..4d4035626c8eae 100644 --- a/lib/manager/helm-values/update.ts +++ b/lib/manager/helm-values/update.ts @@ -16,9 +16,8 @@ export async function bumpPackageVersion( ); const chartFileName = getSiblingFileName(packageFile, 'Chart.yaml'); const chartYamlContent = await getSiblingChartYamlContent(packageFile); - let newChartVersion: string; try { - newChartVersion = inc(currentValue, bumpVersion as ReleaseType); + const newChartVersion = inc(currentValue, bumpVersion as ReleaseType); if (!newChartVersion) { throw new Error('semver inc failed'); } From cc855b69c783e8cb462b53afe71e9ca3b8dde070 Mon Sep 17 00:00:00 2001 From: chgl Date: Mon, 11 Jan 2021 14:30:20 +0100 Subject: [PATCH 7/7] refactor: support multiple bumpPackageFiles --- lib/manager/common.ts | 8 +- lib/manager/helm-values/update.spec.ts | 18 +++-- lib/manager/helm-values/update.ts | 2 +- .../__snapshots__/get-updated.spec.ts.snap | 48 +++++++---- lib/workers/branch/get-updated.spec.ts | 80 +++++++++++++------ lib/workers/branch/get-updated.ts | 22 ++--- 6 files changed, 116 insertions(+), 62 deletions(-) diff --git a/lib/manager/common.ts b/lib/manager/common.ts index fb628d93134443..196e8b3b347d06 100644 --- a/lib/manager/common.ts +++ b/lib/manager/common.ts @@ -229,13 +229,13 @@ export interface UpdateDependencyConfig> { export interface BumpPackageVersionResult { bumpedContent: string | null; - // describes a file that was changed instead of or in addition to the packageFile - bumpedFile?: BumpedPackageFile; + // describes files that was changed instead of or in addition to the packageFile + bumpedFiles?: BumpedPackageFile[]; } export interface BumpedPackageFile { - fileName: string | null; - newContent: string | null; + fileName: string; + newContent: string; } export interface ManagerApi { diff --git a/lib/manager/helm-values/update.spec.ts b/lib/manager/helm-values/update.spec.ts index 78da3ed33fd839..e90a73547e9f42 100644 --- a/lib/manager/helm-values/update.spec.ts +++ b/lib/manager/helm-values/update.spec.ts @@ -24,7 +24,7 @@ describe('lib/manager/helm-values/update', () => { it('increments', async () => { const { bumpedContent, - bumpedFile, + bumpedFiles, } = await helmValuesUpdater.bumpPackageVersion( helmValuesContent, '0.0.2', @@ -32,13 +32,15 @@ describe('lib/manager/helm-values/update', () => { 'values.yaml' ); expect(bumpedContent).toEqual(helmValuesContent); + expect(bumpedFiles).toHaveLength(1); + const bumpedFile = bumpedFiles[0]; expect(bumpedFile.fileName).toEqual('Chart.yaml'); expect(bumpedFile.newContent).toMatchSnapshot(); }); it('no ops', async () => { const { bumpedContent, - bumpedFile, + bumpedFiles, } = await helmValuesUpdater.bumpPackageVersion( helmValuesContent, '0.0.1', @@ -46,12 +48,14 @@ describe('lib/manager/helm-values/update', () => { 'values.yaml' ); expect(bumpedContent).toEqual(helmValuesContent); + expect(bumpedFiles).toHaveLength(1); + const bumpedFile = bumpedFiles[0]; expect(bumpedFile.newContent).toEqual(chartContent); }); it('updates', async () => { const { bumpedContent, - bumpedFile, + bumpedFiles, } = await helmValuesUpdater.bumpPackageVersion( helmValuesContent, '0.0.1', @@ -59,13 +63,15 @@ describe('lib/manager/helm-values/update', () => { 'values.yaml' ); expect(bumpedContent).toEqual(helmValuesContent); - expect(bumpedFile.newContent).toMatchSnapshot(); + expect(bumpedFiles).toHaveLength(1); + const bumpedFile = bumpedFiles[0]; expect(bumpedFile.fileName).toEqual('Chart.yaml'); + expect(bumpedFile.newContent).toMatchSnapshot(); }); it('returns content if bumping errors', async () => { const { bumpedContent, - bumpedFile, + bumpedFiles, } = await helmValuesUpdater.bumpPackageVersion( helmValuesContent, '0.0.2', @@ -73,7 +79,7 @@ describe('lib/manager/helm-values/update', () => { 'values.yaml' ); expect(bumpedContent).toEqual(helmValuesContent); - expect(bumpedFile).toBeUndefined(); + expect(bumpedFiles).toBeUndefined(); }); }); }); diff --git a/lib/manager/helm-values/update.ts b/lib/manager/helm-values/update.ts index 4d4035626c8eae..25184d07fca5fc 100644 --- a/lib/manager/helm-values/update.ts +++ b/lib/manager/helm-values/update.ts @@ -33,7 +33,7 @@ export async function bumpPackageVersion( } return { bumpedContent: content, - bumpedFile: { fileName: chartFileName, newContent: bumpedContent }, + bumpedFiles: [{ fileName: chartFileName, newContent: bumpedContent }], }; } catch (err) { logger.warn( diff --git a/lib/workers/branch/__snapshots__/get-updated.spec.ts.snap b/lib/workers/branch/__snapshots__/get-updated.spec.ts.snap index 0f501466bd6bf0..f6fdd541c1ac6b 100644 --- a/lib/workers/branch/__snapshots__/get-updated.spec.ts.snap +++ b/lib/workers/branch/__snapshots__/get-updated.spec.ts.snap @@ -1,19 +1,5 @@ // 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 [], @@ -187,7 +173,39 @@ Object { } `; -exports[`workers/branch/get-updated getUpdatedPackageFiles() bumps versions in autoReplace managers with a bumpPackageFile different from the packageFile 1`] = ` +exports[`workers/branch/get-updated getUpdatedPackageFiles() in autoReplace managers bumps versions 1`] = ` +Object { + "artifactErrors": Array [], + "reuseExistingBranch": undefined, + "updatedArtifacts": Array [], + "updatedPackageFiles": Array [ + Object { + "contents": "version: 0.0.2", + "name": "undefined", + }, + ], +} +`; + +exports[`workers/branch/get-updated getUpdatedPackageFiles() in autoReplace managers bumps versions in all files if multiple files were bumped 1`] = ` +Object { + "artifactErrors": Array [], + "reuseExistingBranch": undefined, + "updatedArtifacts": Array [], + "updatedPackageFiles": Array [ + Object { + "contents": "version: 0.0.2", + "name": "/test/Chart.yaml", + }, + Object { + "contents": "# Version 0.0.2", + "name": "/test/README.md", + }, + ], +} +`; + +exports[`workers/branch/get-updated getUpdatedPackageFiles() in autoReplace managers bumps versions with a bumpPackageFile different from the packageFile 1`] = ` Object { "artifactErrors": Array [], "reuseExistingBranch": undefined, diff --git a/lib/workers/branch/get-updated.spec.ts b/lib/workers/branch/get-updated.spec.ts index fa31c886e3cd97..a28f47fcd285bf 100644 --- a/lib/workers/branch/get-updated.spec.ts +++ b/lib/workers/branch/get-updated.spec.ts @@ -186,35 +186,63 @@ describe('workers/branch/get-updated', () => { const res = await getUpdatedPackageFiles(config); expect(res).toMatchSnapshot(); }); - it('bumps versions in autoReplace managers', async () => { - config.upgrades.push({ - branchName: undefined, - bumpVersion: 'patch', - manager: 'helmv3', + + describe('in autoReplace managers', () => { + it('bumps versions', async () => { + config.upgrades.push({ + branchName: undefined, + bumpVersion: 'patch', + manager: 'helmv3', + }); + autoReplace.doAutoReplace.mockResolvedValueOnce('version: 0.0.1'); + helmv3.bumpPackageVersion.mockReturnValue({ + bumpedContent: 'version: 0.0.2', + }); + const res = await getUpdatedPackageFiles(config); + expect(res).toMatchSnapshot(); }); - autoReplace.doAutoReplace.mockResolvedValueOnce('version: 0.0.1'); - helmv3.bumpPackageVersion.mockReturnValue({ - bumpedContent: 'version: 0.0.2', + it('bumps versions with a bumpPackageFile different from the packageFile', async () => { + config.upgrades.push({ + branchName: undefined, + bumpVersion: 'patch', + manager: 'helm-values', + }); + autoReplace.doAutoReplace.mockResolvedValueOnce('existing content'); + helmValues.bumpPackageVersion.mockResolvedValue({ + bumpedContent: 'existing content', + bumpedFiles: [ + { + fileName: '/test/Chart.yaml', + newContent: 'version: 0.0.2', + }, + ], + }); + const res = await getUpdatedPackageFiles(config); + expect(res).toMatchSnapshot(); }); - const res = await getUpdatedPackageFiles(config); - expect(res).toMatchSnapshot(); - }); - it('bumps versions in autoReplace managers with a bumpPackageFile different from the packageFile', async () => { - config.upgrades.push({ - branchName: undefined, - bumpVersion: 'patch', - manager: 'helm-values', + it('bumps versions in all files if multiple files were bumped', async () => { + config.upgrades.push({ + branchName: undefined, + bumpVersion: 'patch', + manager: 'helm-values', + }); + autoReplace.doAutoReplace.mockResolvedValueOnce('existing content'); + helmValues.bumpPackageVersion.mockResolvedValue({ + bumpedContent: 'existing content', + bumpedFiles: [ + { + fileName: '/test/Chart.yaml', + newContent: 'version: 0.0.2', + }, + { + fileName: '/test/README.md', + newContent: '# Version 0.0.2', + }, + ], + }); + const res = await getUpdatedPackageFiles(config); + expect(res).toMatchSnapshot(); }); - autoReplace.doAutoReplace.mockResolvedValueOnce('existing content'); - helmValues.bumpPackageVersion.mockResolvedValue({ - bumpedContent: 'existing content', - bumpedFile: { - fileName: '/test/Chart.yaml', - newContent: '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 b4fd810adbe75a..2bfff9d8c7898d 100644 --- a/lib/workers/branch/get-updated.ts +++ b/lib/workers/branch/get-updated.ts @@ -66,7 +66,7 @@ export async function getUpdatedPackageFiles( ); if (res) { - let bumpedPackageFile: BumpedPackageFile; + let bumpedPackageFiles: BumpedPackageFile[]; if (bumpPackageVersion && upgrade.bumpVersion) { const bumpResult = await bumpPackageVersion( res, @@ -75,7 +75,7 @@ export async function getUpdatedPackageFiles( packageFile ); res = bumpResult.bumpedContent; - bumpedPackageFile = bumpResult.bumpedFile; + bumpedPackageFiles = bumpResult.bumpedFiles; } if (res === existingContent) { logger.debug({ packageFile, depName }, 'No content changed'); @@ -87,15 +87,17 @@ export async function getUpdatedPackageFiles( logger.debug({ packageFile, depName }, 'Contents updated'); updatedFileContents[packageFile] = res; } - // indicates that the version was bumped in another file in + // indicates that the version was bumped in one or more files in // addition to or instead of the packageFile - if (bumpedPackageFile) { - logger.debug( - { bumpedPackageFile, depName }, - 'Updating bumpedPackageFile content' - ); - updatedFileContents[bumpedPackageFile.fileName] = - bumpedPackageFile.newContent; + if (bumpedPackageFiles) { + for (const bumpedPackageFile of bumpedPackageFiles) { + logger.debug( + { bumpedPackageFile, depName }, + 'Updating bumpedPackageFile content' + ); + updatedFileContents[bumpedPackageFile.fileName] = + bumpedPackageFile.newContent; + } } continue; // eslint-disable-line no-continue } else if (reuseExistingBranch) {