Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Flux package manager that can renovate HelmRelease manifests #13566

Merged
merged 14 commits into from
Jan 19, 2022
2 changes: 2 additions & 0 deletions lib/manager/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import * as depsEdn from './deps-edn';
import * as dockerCompose from './docker-compose';
import * as dockerfile from './dockerfile';
import * as droneci from './droneci';
import * as flux from './flux';
import * as gitSubmodules from './git-submodules';
import * as githubActions from './github-actions';
import * as gitlabci from './gitlabci';
Expand Down Expand Up @@ -89,6 +90,7 @@ api.set('deps-edn', depsEdn);
api.set('docker-compose', dockerCompose);
api.set('dockerfile', dockerfile);
api.set('droneci', droneci);
api.set('flux', flux);
api.set('git-submodules', gitSubmodules);
api.set('github-actions', githubActions);
api.set('gitlabci', gitlabci);
Expand Down
24 changes: 24 additions & 0 deletions lib/manager/flux/__fixtures__/multidoc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: external-dns
namespace: kube-system
spec:
releaseName: external-dns
chart:
spec:
chart: external-dns
sourceRef:
kind: HelmRepository
name: external-dns
version: "1.7.0"
interval: 1h0m0s
---
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: HelmRepository
metadata:
name: external-dns
namespace: kube-system
spec:
interval: 1h0m0s
url: https://kubernetes-sigs.github.io/external-dns/
24 changes: 24 additions & 0 deletions lib/manager/flux/__fixtures__/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: sealed-secrets
namespace: kube-system
spec:
releaseName: sealed-secrets-controller
chart:
spec:
chart: sealed-secrets
sourceRef:
kind: HelmRepository
name: sealed-secrets
namespace: kube-system
version: "2.0.2"
interval: 1h0m0s
values:
resources:
limits:
cpu: 250m
memory: 512Mi
requests:
cpu: 50m
memory: 64Mi
8 changes: 8 additions & 0 deletions lib/manager/flux/__fixtures__/source.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: HelmRepository
metadata:
name: sealed-secrets
namespace: kube-system
spec:
interval: 1h0m0s
url: https://bitnami-labs.github.io/sealed-secrets
34 changes: 34 additions & 0 deletions lib/manager/flux/__snapshots__/extract.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`manager/flux/extract extractAllPackageFiles() extracts multiple files 1`] = `
Array [
Object {
"datasource": "helm",
"deps": Array [
Object {
"currentValue": "2.0.2",
"depName": "sealed-secrets",
"registryUrls": Array [
"https://bitnami-labs.github.io/sealed-secrets",
],
},
],
"packageFile": "lib/manager/flux/__fixtures__/release.yaml",
},
]
`;

exports[`manager/flux/extract extractPackageFile() extracts multiple resources 1`] = `
Object {
"datasource": "helm",
"deps": Array [
Object {
"currentValue": "1.7.0",
"depName": "external-dns",
"registryUrls": Array [
"https://kubernetes-sigs.github.io/external-dns/",
],
},
],
}
`;
187 changes: 187 additions & 0 deletions lib/manager/flux/extract.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
import { loadFixture } from '../../../test/util';
import { GlobalConfig } from '../../config/global';
import type { RepoGlobalConfig } from '../../config/types';
import { SkipReason } from '../../types';
import type { ExtractConfig } from '../types';
import { extractAllPackageFiles, extractPackageFile } from './extract';
danports marked this conversation as resolved.
Show resolved Hide resolved

const config: ExtractConfig = {};
const adminConfig: RepoGlobalConfig = { localDir: '' };

describe('manager/flux/extract', () => {
beforeEach(() => {
GlobalConfig.set(adminConfig);
});

afterEach(() => {
GlobalConfig.reset();
});

danports marked this conversation as resolved.
Show resolved Hide resolved
describe('extractPackageFile()', () => {
it('extracts multiple resources', () => {
const result = extractPackageFile(loadFixture('multidoc.yaml'));
expect(result).toMatchSnapshot();
danports marked this conversation as resolved.
Show resolved Hide resolved
});
it('extracts releases without repositories', () => {
const result = extractPackageFile(loadFixture('release.yaml'));
expect(result.deps[0].skipReason).toBe(SkipReason.UnknownRegistry);
});
it('ignores HelmRelease resources without an apiVersion', () => {
const result = extractPackageFile('kind: HelmRelease');
expect(result).toBeNull();
});
it('ignores HelmRepository resources without an apiVersion', () => {
const result = extractPackageFile('kind: HelmRepository');
expect(result).toBeNull();
});
it('ignores HelmRepository resources without metadata', () => {
const result = extractPackageFile(
`${loadFixture('release.yaml')}
---
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: HelmRepository
`
);
expect(result.deps[0].skipReason).toBe(SkipReason.UnknownRegistry);
});
it('ignores HelmRelease resources without a chart name', () => {
const result = extractPackageFile(
`apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: sealed-secrets
namespace: kube-system
spec:
chart:
spec:
sourceRef:
kind: HelmRepository
name: sealed-secrets
version: "2.0.2"
`
);
expect(result).toBeNull();
});
it('does not match HelmRelease resources without a namespace to HelmRepository resources without a namespace', () => {
const result = extractPackageFile(
`apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: HelmRepository
metadata:
name: sealed-secrets
spec:
url: https://bitnami-labs.github.io/sealed-secrets
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
spec:
chart:
spec:
chart: sealed-secrets
sourceRef:
kind: HelmRepository
name: sealed-secrets
version: "2.0.2"
`
);
expect(result.deps[0].skipReason).toBe(SkipReason.UnknownRegistry);
});
it('does not match HelmRelease resources without a sourceRef', () => {
const result = extractPackageFile(
`${loadFixture('source.yaml')}
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: sealed-secrets
spec:
chart:
spec:
chart: sealed-secrets
version: "2.0.2"
`
);
expect(result.deps[0].skipReason).toBe(SkipReason.UnknownRegistry);
});
it('does not match HelmRelease resources without a namespace', () => {
const result = extractPackageFile(
`${loadFixture('source.yaml')}
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
spec:
chart:
spec:
chart: sealed-secrets
sourceRef:
kind: HelmRepository
name: sealed-secrets
version: "2.0.2"
`
);
expect(result.deps[0].skipReason).toBe(SkipReason.UnknownRegistry);
});
it('ignores HelmRepository resources without a namespace', () => {
const result = extractPackageFile(
`${loadFixture('release.yaml')}
---
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: HelmRepository
metadata:
name: test
`
);
expect(result.deps[0].skipReason).toBe(SkipReason.UnknownRegistry);
});
it('ignores HelmRepository resources without a URL', () => {
const result = extractPackageFile(
`${loadFixture('release.yaml')}
---
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: HelmRepository
metadata:
name: sealed-secrets
namespace: kube-system
`
);
expect(result.deps[0].skipReason).toBe(SkipReason.UnknownRegistry);
});
it('ignores resources of an unknown kind', () => {
const result = extractPackageFile(
`kind: SomethingElse
apiVersion: helm.toolkit.fluxcd.io/v2beta1`
);
expect(result).toBeNull();
});
it('ignores resources without a kind', () => {
const result = extractPackageFile(
'apiVersion: helm.toolkit.fluxcd.io/v2beta1'
);
expect(result).toBeNull();
});
it('ignores bad manifests', () => {
const result = extractPackageFile('"bad YAML');
expect(result).toBeNull();
});
it('ignores null resources', () => {
const result = extractPackageFile('null');
expect(result).toBeNull();
});
});

describe('extractAllPackageFiles()', () => {
it('extracts multiple files', async () => {
const result = await extractAllPackageFiles(config, [
'lib/manager/flux/__fixtures__/release.yaml',
'lib/manager/flux/__fixtures__/source.yaml',
]);
expect(result).toMatchSnapshot();
danports marked this conversation as resolved.
Show resolved Hide resolved
expect(result).toHaveLength(1);
});
it('ignores files that do not exist', async () => {
const result = await extractAllPackageFiles(config, [
'lib/manager/flux/__fixtures__/bogus.yaml',
]);
expect(result).toBeNull();
});
});
});
Loading