mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-13 15:36:25 +00:00
feat(manager/helmfile): Support kustomize (#20782)
This commit is contained in:
parent
eac9ef6079
commit
c2fe56a126
10 changed files with 98 additions and 23 deletions
|
@ -25,6 +25,8 @@ repositories:
|
||||||
url: https://charts.bitnami.com/bitnami
|
url: https://charts.bitnami.com/bitnami
|
||||||
- name: prometheus-community
|
- name: prometheus-community
|
||||||
url: https://prometheus-community.github.io/helm-charts
|
url: https://prometheus-community.github.io/helm-charts
|
||||||
|
- name: incubator
|
||||||
|
url: https://charts.helm.sh/incubator/
|
||||||
|
|
||||||
templates:
|
templates:
|
||||||
external-chart: &external-chart
|
external-chart: &external-chart
|
||||||
|
@ -72,3 +74,24 @@ releases:
|
||||||
{{`{{ range .Alerts }}
|
{{`{{ range .Alerts }}
|
||||||
*Alert:* {{ .Annotations.summary }}
|
*Alert:* {{ .Annotations.summary }}
|
||||||
{{ end }}`}}
|
{{ 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
|
||||||
|
|
|
@ -30,6 +30,16 @@ exports[`modules/manager/helmfile/extract extractPackageFile() parses multidoc y
|
||||||
"depName": "external-dns",
|
"depName": "external-dns",
|
||||||
"skipReason": "invalid-version",
|
"skipReason": "invalid-version",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"currentValue": "0.1.0",
|
||||||
|
"depName": "raw",
|
||||||
|
"managerData": {
|
||||||
|
"needKustomize": true,
|
||||||
|
},
|
||||||
|
"registryUrls": [
|
||||||
|
"https://charts.helm.sh/incubator/",
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -42,8 +42,9 @@ releases:
|
||||||
chart: oauth2-proxy/oauth2-proxy
|
chart: oauth2-proxy/oauth2-proxy
|
||||||
version: 6.8.0
|
version: 6.8.0
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const lockFile = codeBlock`
|
const lockFile = codeBlock`
|
||||||
version: 0.150.0
|
version: 0.151.0
|
||||||
dependencies:
|
dependencies:
|
||||||
- name: backstage
|
- name: backstage
|
||||||
repository: https://backstage.github.io/charts
|
repository: https://backstage.github.io/charts
|
||||||
|
@ -51,11 +52,11 @@ dependencies:
|
||||||
- name: oauth2-proxy
|
- name: oauth2-proxy
|
||||||
repository: https://oauth2-proxy.github.io/manifests
|
repository: https://oauth2-proxy.github.io/manifests
|
||||||
version: 6.2.1
|
version: 6.2.1
|
||||||
digest: sha256:98c605fc3de51960ad1eb022f01dfae3bb0a1a06549e56fa39ec86db2a9a072d
|
digest: sha256:e284706b71f37b757a536703da4cb148d67901afbf1ab431f7d60a9852ca6eef
|
||||||
generated: "2023-01-23T12:13:46.487247+01:00"
|
generated: "2023-03-08T21:32:06.122276997+01:00"
|
||||||
`;
|
`;
|
||||||
const lockFileTwo = codeBlock`
|
const lockFileTwo = codeBlock`
|
||||||
version: 0.150.0
|
version: 0.151.0
|
||||||
dependencies:
|
dependencies:
|
||||||
- name: backstage
|
- name: backstage
|
||||||
repository: https://backstage.github.io/charts
|
repository: https://backstage.github.io/charts
|
||||||
|
@ -63,8 +64,8 @@ dependencies:
|
||||||
- name: oauth2-proxy
|
- name: oauth2-proxy
|
||||||
repository: https://oauth2-proxy.github.io/manifests
|
repository: https://oauth2-proxy.github.io/manifests
|
||||||
version: 6.8.0
|
version: 6.8.0
|
||||||
digest: sha256:8ceea14d17c0f3c108a26ba341c63380e2426db66484d2b2876ab6e636e52af4
|
digest: sha256:9d83889176d005effb86041d30c20361625561cbfb439cbd16d7243225bac17c
|
||||||
generated: "2023-01-23T12:16:41.881988+01:00"
|
generated: "2023-03-08T21:30:48.273709455+01:00"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
describe('modules/manager/helmfile/artifacts', () => {
|
describe('modules/manager/helmfile/artifacts', () => {
|
||||||
|
@ -171,6 +172,8 @@ describe('modules/manager/helmfile/artifacts', () => {
|
||||||
' && ' +
|
' && ' +
|
||||||
'install-tool helmfile v0.129.0' +
|
'install-tool helmfile v0.129.0' +
|
||||||
' && ' +
|
' && ' +
|
||||||
|
'install-tool kustomize 5.0.0' +
|
||||||
|
' && ' +
|
||||||
'helmfile deps -f helmfile.yaml' +
|
'helmfile deps -f helmfile.yaml' +
|
||||||
'"',
|
'"',
|
||||||
},
|
},
|
||||||
|
@ -181,6 +184,7 @@ describe('modules/manager/helmfile/artifacts', () => {
|
||||||
expectedCommands: [
|
expectedCommands: [
|
||||||
{ cmd: 'install-tool helm v3.7.2' },
|
{ cmd: 'install-tool helm v3.7.2' },
|
||||||
{ cmd: 'install-tool helmfile v0.129.0' },
|
{ cmd: 'install-tool helmfile v0.129.0' },
|
||||||
|
{ cmd: 'install-tool kustomize 5.0.0' },
|
||||||
{ cmd: 'helmfile deps -f helmfile.yaml' },
|
{ cmd: 'helmfile deps -f helmfile.yaml' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -203,7 +207,12 @@ describe('modules/manager/helmfile/artifacts', () => {
|
||||||
datasource.getPkgReleases.mockResolvedValueOnce({
|
datasource.getPkgReleases.mockResolvedValueOnce({
|
||||||
releases: [{ version: 'v0.129.0' }],
|
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(
|
expect(
|
||||||
await helmfile.updateArtifacts({
|
await helmfile.updateArtifacts({
|
||||||
packageFileName: 'helmfile.yaml',
|
packageFileName: 'helmfile.yaml',
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { quote } from 'shlex';
|
||||||
import { TEMPORARY_ERROR } from '../../../constants/error-messages';
|
import { TEMPORARY_ERROR } from '../../../constants/error-messages';
|
||||||
import { logger } from '../../../logger';
|
import { logger } from '../../../logger';
|
||||||
import { exec } from '../../../util/exec';
|
import { exec } from '../../../util/exec';
|
||||||
import type { ExecOptions } from '../../../util/exec/types';
|
import type { ToolConstraint } from '../../../util/exec/types';
|
||||||
import {
|
import {
|
||||||
getSiblingFileName,
|
getSiblingFileName,
|
||||||
readLocalFile,
|
readLocalFile,
|
||||||
|
@ -40,21 +40,30 @@ export async function updateArtifacts({
|
||||||
try {
|
try {
|
||||||
await writeLocalFile(packageFileName, newPackageFileContent);
|
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: {},
|
docker: {},
|
||||||
extraEnv: {},
|
extraEnv: {},
|
||||||
toolConstraints: [
|
toolConstraints,
|
||||||
{
|
});
|
||||||
toolName: 'helm',
|
|
||||||
constraint: config.constraints?.helm,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
toolName: 'helmfile',
|
|
||||||
constraint: config.constraints?.helmfile,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
await exec(`helmfile deps -f ${quote(packageFileName)}`, execOptions);
|
|
||||||
|
|
||||||
const newHelmLockContent = await readLocalFile(lockFileName, 'utf8');
|
const newHelmLockContent = await readLocalFile(lockFileName, 'utf8');
|
||||||
if (existingLockFileContent === newHelmLockContent) {
|
if (existingLockFileContent === newHelmLockContent) {
|
||||||
|
|
|
@ -199,6 +199,7 @@ describe('modules/manager/helmfile/extract', () => {
|
||||||
{ depName: 'kube-prometheus-stack', currentValue: '13.7' },
|
{ depName: 'kube-prometheus-stack', currentValue: '13.7' },
|
||||||
{ depName: 'invalid', skipReason: 'invalid-name' },
|
{ depName: 'invalid', skipReason: 'invalid-name' },
|
||||||
{ depName: 'external-dns', skipReason: 'invalid-version' },
|
{ depName: 'external-dns', skipReason: 'invalid-version' },
|
||||||
|
{ depName: 'raw', managerData: { needKustomize: true } },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,6 +10,7 @@ import type {
|
||||||
PackageFileContent,
|
PackageFileContent,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import type { Doc } from './types';
|
import type { Doc } from './types';
|
||||||
|
import { areKustomizationsUsed } from './utils';
|
||||||
|
|
||||||
const isValidChartName = (name: string | undefined): boolean =>
|
const isValidChartName = (name: string | undefined): boolean =>
|
||||||
!!name && !regEx(/[!@#$%^&*(),.?":{}/|<>A-Z]/).test(name);
|
!!name && !regEx(/[!@#$%^&*(),.?":{}/|<>A-Z]/).test(name);
|
||||||
|
@ -92,7 +93,9 @@ export function extractPackageFile(
|
||||||
.concat([config.registryAliases?.[repoName]] as string[])
|
.concat([config.registryAliases?.[repoName]] as string[])
|
||||||
.filter(is.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
|
// in case of OCI repository, we need a PackageDependency with a DockerDatasource and a packageName
|
||||||
const repository = doc.repositories?.find(
|
const repository = doc.repositories?.find(
|
||||||
(repo) => repo.name === repoName
|
(repo) => repo.name === repoName
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
interface Release {
|
export interface Release {
|
||||||
name: string;
|
name: string;
|
||||||
chart: string;
|
chart: string;
|
||||||
version: string;
|
version: string;
|
||||||
|
strategicMergePatches?: unknown;
|
||||||
|
jsonPatches?: unknown;
|
||||||
|
transformers?: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Repository {
|
interface Repository {
|
||||||
|
|
10
lib/modules/manager/helmfile/utils.ts
Normal file
10
lib/modules/manager/helmfile/utils.ts
Normal file
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
|
@ -80,6 +80,12 @@ const allToolConfig: Record<string, ToolConfig> = {
|
||||||
packageName: 'jsonnet-bundler/jsonnet-bundler',
|
packageName: 'jsonnet-bundler/jsonnet-bundler',
|
||||||
versioning: semverVersioningId,
|
versioning: semverVersioningId,
|
||||||
},
|
},
|
||||||
|
kustomize: {
|
||||||
|
datasource: 'github-releases',
|
||||||
|
packageName: 'kubernetes-sigs/kustomize',
|
||||||
|
extractVersion: '^kustomize/v(?<version>.*)$',
|
||||||
|
versioning: semverVersioningId,
|
||||||
|
},
|
||||||
lerna: {
|
lerna: {
|
||||||
datasource: 'npm',
|
datasource: 'npm',
|
||||||
packageName: 'lerna',
|
packageName: 'lerna',
|
||||||
|
|
|
@ -7,6 +7,7 @@ export interface ToolConstraint {
|
||||||
|
|
||||||
export interface ToolConfig {
|
export interface ToolConfig {
|
||||||
datasource: string;
|
datasource: string;
|
||||||
|
extractVersion?: string;
|
||||||
packageName: string;
|
packageName: string;
|
||||||
hash?: boolean;
|
hash?: boolean;
|
||||||
versioning: string;
|
versioning: string;
|
||||||
|
|
Loading…
Reference in a new issue