From c2fe56a1265cc946de1a50f97e6f3dfec9e1a131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikolai=20R=C3=B8ed=20Kristiansen?= <nikolai.kristiansen@remarkable.no> Date: Sun, 19 Mar 2023 09:15:15 +0100 Subject: [PATCH] feat(manager/helmfile): Support kustomize (#20782) --- .../helmfile/__fixtures__/multidoc.yaml | 23 ++++++++++++ .../__snapshots__/extract.spec.ts.snap | 10 +++++ .../manager/helmfile/artifacts.spec.ts | 23 ++++++++---- lib/modules/manager/helmfile/artifacts.ts | 37 ++++++++++++------- lib/modules/manager/helmfile/extract.spec.ts | 1 + lib/modules/manager/helmfile/extract.ts | 5 ++- lib/modules/manager/helmfile/types.ts | 5 ++- lib/modules/manager/helmfile/utils.ts | 10 +++++ lib/util/exec/containerbase.ts | 6 +++ lib/util/exec/types.ts | 1 + 10 files changed, 98 insertions(+), 23 deletions(-) create mode 100644 lib/modules/manager/helmfile/utils.ts diff --git a/lib/modules/manager/helmfile/__fixtures__/multidoc.yaml b/lib/modules/manager/helmfile/__fixtures__/multidoc.yaml index 69d3c85447..d42bd70e57 100644 --- a/lib/modules/manager/helmfile/__fixtures__/multidoc.yaml +++ b/lib/modules/manager/helmfile/__fixtures__/multidoc.yaml @@ -25,6 +25,8 @@ repositories: url: https://charts.bitnami.com/bitnami - name: prometheus-community url: https://prometheus-community.github.io/helm-charts +- name: incubator + url: https://charts.helm.sh/incubator/ templates: external-chart: &external-chart @@ -72,3 +74,24 @@ releases: {{`{{ range .Alerts }} *Alert:* {{ .Annotations.summary }} {{ end }}`}} + +- name: raw1 + chart: incubator/raw + version: 0.1.0 + values: + - resources: + - apiVersion: v1 + kind: ConfigMap + metadata: + name: raw1 + namespace: default + data: + foo: FOO + strategicMergePatches: + - apiVersion: v1 + kind: ConfigMap + metadata: + name: raw1 + namespace: default + data: + bar: BAR diff --git a/lib/modules/manager/helmfile/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/helmfile/__snapshots__/extract.spec.ts.snap index dbe1c07f50..49b560fae8 100644 --- a/lib/modules/manager/helmfile/__snapshots__/extract.spec.ts.snap +++ b/lib/modules/manager/helmfile/__snapshots__/extract.spec.ts.snap @@ -30,6 +30,16 @@ exports[`modules/manager/helmfile/extract extractPackageFile() parses multidoc y "depName": "external-dns", "skipReason": "invalid-version", }, + { + "currentValue": "0.1.0", + "depName": "raw", + "managerData": { + "needKustomize": true, + }, + "registryUrls": [ + "https://charts.helm.sh/incubator/", + ], + }, ], } `; diff --git a/lib/modules/manager/helmfile/artifacts.spec.ts b/lib/modules/manager/helmfile/artifacts.spec.ts index d2213cbb15..f4c448451a 100644 --- a/lib/modules/manager/helmfile/artifacts.spec.ts +++ b/lib/modules/manager/helmfile/artifacts.spec.ts @@ -42,8 +42,9 @@ releases: chart: oauth2-proxy/oauth2-proxy version: 6.8.0 `; + const lockFile = codeBlock` -version: 0.150.0 +version: 0.151.0 dependencies: - name: backstage repository: https://backstage.github.io/charts @@ -51,11 +52,11 @@ dependencies: - name: oauth2-proxy repository: https://oauth2-proxy.github.io/manifests version: 6.2.1 -digest: sha256:98c605fc3de51960ad1eb022f01dfae3bb0a1a06549e56fa39ec86db2a9a072d -generated: "2023-01-23T12:13:46.487247+01:00" +digest: sha256:e284706b71f37b757a536703da4cb148d67901afbf1ab431f7d60a9852ca6eef +generated: "2023-03-08T21:32:06.122276997+01:00" `; const lockFileTwo = codeBlock` -version: 0.150.0 +version: 0.151.0 dependencies: - name: backstage repository: https://backstage.github.io/charts @@ -63,8 +64,8 @@ dependencies: - name: oauth2-proxy repository: https://oauth2-proxy.github.io/manifests version: 6.8.0 -digest: sha256:8ceea14d17c0f3c108a26ba341c63380e2426db66484d2b2876ab6e636e52af4 -generated: "2023-01-23T12:16:41.881988+01:00" +digest: sha256:9d83889176d005effb86041d30c20361625561cbfb439cbd16d7243225bac17c +generated: "2023-03-08T21:30:48.273709455+01:00" `; describe('modules/manager/helmfile/artifacts', () => { @@ -171,6 +172,8 @@ describe('modules/manager/helmfile/artifacts', () => { ' && ' + 'install-tool helmfile v0.129.0' + ' && ' + + 'install-tool kustomize 5.0.0' + + ' && ' + 'helmfile deps -f helmfile.yaml' + '"', }, @@ -181,6 +184,7 @@ describe('modules/manager/helmfile/artifacts', () => { expectedCommands: [ { cmd: 'install-tool helm v3.7.2' }, { cmd: 'install-tool helmfile v0.129.0' }, + { cmd: 'install-tool kustomize 5.0.0' }, { cmd: 'helmfile deps -f helmfile.yaml' }, ], }, @@ -203,7 +207,12 @@ describe('modules/manager/helmfile/artifacts', () => { datasource.getPkgReleases.mockResolvedValueOnce({ releases: [{ version: 'v0.129.0' }], }); - const updatedDeps = [{ depName: 'dep1' }]; + datasource.getPkgReleases.mockResolvedValueOnce({ + releases: [{ version: '5.0.0' }], + }); + const updatedDeps = [ + { depName: 'dep1', managerData: { needKustomize: true } }, + ]; expect( await helmfile.updateArtifacts({ packageFileName: 'helmfile.yaml', diff --git a/lib/modules/manager/helmfile/artifacts.ts b/lib/modules/manager/helmfile/artifacts.ts index c7a9f23ae5..578372e106 100644 --- a/lib/modules/manager/helmfile/artifacts.ts +++ b/lib/modules/manager/helmfile/artifacts.ts @@ -3,7 +3,7 @@ import { quote } from 'shlex'; import { TEMPORARY_ERROR } from '../../../constants/error-messages'; import { logger } from '../../../logger'; import { exec } from '../../../util/exec'; -import type { ExecOptions } from '../../../util/exec/types'; +import type { ToolConstraint } from '../../../util/exec/types'; import { getSiblingFileName, readLocalFile, @@ -40,21 +40,30 @@ export async function updateArtifacts({ try { await writeLocalFile(packageFileName, newPackageFileContent); - const execOptions: ExecOptions = { + const toolConstraints: ToolConstraint[] = [ + { + toolName: 'helm', + constraint: config.constraints?.helm, + }, + { + toolName: 'helmfile', + constraint: config.constraints?.helmfile, + }, + ]; + const needKustomize = updatedDeps.some( + (dep) => dep.managerData?.needKustomize + ); + if (needKustomize) { + toolConstraints.push({ + toolName: 'kustomize', + constraint: config.constraints?.kustomize, + }); + } + await exec(`helmfile deps -f ${quote(packageFileName)}`, { docker: {}, extraEnv: {}, - toolConstraints: [ - { - toolName: 'helm', - constraint: config.constraints?.helm, - }, - { - toolName: 'helmfile', - constraint: config.constraints?.helmfile, - }, - ], - }; - await exec(`helmfile deps -f ${quote(packageFileName)}`, execOptions); + toolConstraints, + }); const newHelmLockContent = await readLocalFile(lockFileName, 'utf8'); if (existingLockFileContent === newHelmLockContent) { diff --git a/lib/modules/manager/helmfile/extract.spec.ts b/lib/modules/manager/helmfile/extract.spec.ts index f3f535df14..6b312da7b7 100644 --- a/lib/modules/manager/helmfile/extract.spec.ts +++ b/lib/modules/manager/helmfile/extract.spec.ts @@ -199,6 +199,7 @@ describe('modules/manager/helmfile/extract', () => { { depName: 'kube-prometheus-stack', currentValue: '13.7' }, { depName: 'invalid', skipReason: 'invalid-name' }, { depName: 'external-dns', skipReason: 'invalid-version' }, + { depName: 'raw', managerData: { needKustomize: true } }, ], }); }); diff --git a/lib/modules/manager/helmfile/extract.ts b/lib/modules/manager/helmfile/extract.ts index 5477a52dc4..70b79c7200 100644 --- a/lib/modules/manager/helmfile/extract.ts +++ b/lib/modules/manager/helmfile/extract.ts @@ -10,6 +10,7 @@ import type { PackageFileContent, } from '../types'; import type { Doc } from './types'; +import { areKustomizationsUsed } from './utils'; const isValidChartName = (name: string | undefined): boolean => !!name && !regEx(/[!@#$%^&*(),.?":{}/|<>A-Z]/).test(name); @@ -92,7 +93,9 @@ export function extractPackageFile( .concat([config.registryAliases?.[repoName]] as string[]) .filter(is.string), }; - + if (areKustomizationsUsed(dep)) { + res.managerData = { needKustomize: true }; + } // in case of OCI repository, we need a PackageDependency with a DockerDatasource and a packageName const repository = doc.repositories?.find( (repo) => repo.name === repoName diff --git a/lib/modules/manager/helmfile/types.ts b/lib/modules/manager/helmfile/types.ts index f2a9593e7c..d38263d102 100644 --- a/lib/modules/manager/helmfile/types.ts +++ b/lib/modules/manager/helmfile/types.ts @@ -1,7 +1,10 @@ -interface Release { +export interface Release { name: string; chart: string; version: string; + strategicMergePatches?: unknown; + jsonPatches?: unknown; + transformers?: unknown; } interface Repository { diff --git a/lib/modules/manager/helmfile/utils.ts b/lib/modules/manager/helmfile/utils.ts new file mode 100644 index 0000000000..415925b9d1 --- /dev/null +++ b/lib/modules/manager/helmfile/utils.ts @@ -0,0 +1,10 @@ +import type { Release } from './types'; + +/** Returns true if kustomize specific keys exist in a helmfile release */ +export function areKustomizationsUsed(release: Release): boolean { + return ( + release.strategicMergePatches !== undefined || + release.jsonPatches !== undefined || + release.transformers !== undefined + ); +} diff --git a/lib/util/exec/containerbase.ts b/lib/util/exec/containerbase.ts index 3c3f5c1909..ed55be68f8 100644 --- a/lib/util/exec/containerbase.ts +++ b/lib/util/exec/containerbase.ts @@ -80,6 +80,12 @@ const allToolConfig: Record<string, ToolConfig> = { packageName: 'jsonnet-bundler/jsonnet-bundler', versioning: semverVersioningId, }, + kustomize: { + datasource: 'github-releases', + packageName: 'kubernetes-sigs/kustomize', + extractVersion: '^kustomize/v(?<version>.*)$', + versioning: semverVersioningId, + }, lerna: { datasource: 'npm', packageName: 'lerna', diff --git a/lib/util/exec/types.ts b/lib/util/exec/types.ts index ffe7949910..80cedbe66d 100644 --- a/lib/util/exec/types.ts +++ b/lib/util/exec/types.ts @@ -7,6 +7,7 @@ export interface ToolConstraint { export interface ToolConfig { datasource: string; + extractVersion?: string; packageName: string; hash?: boolean; versioning: string; -- GitLab