From 9c51ff6733a54b469eab32edaedf3af7cda0d8e3 Mon Sep 17 00:00:00 2001 From: Sergei Zharinov <zharinov@users.noreply.github.com> Date: Fri, 24 Jun 2022 11:07:34 +0300 Subject: [PATCH] feat(manager/helm): make change log url retrieval more flexible (#16210) * feat(helm): improve fallback on sourceUrl selection * fix(helm): use home and source from latest release instead of the first. Otherwise those fields can't be ever changed. * test(helm): test charts with no home metadata * test(helm): test releases semver sorting * fix(helm): select last release by semver * Apply suggestions from code review Co-authored-by: Michael Kriese <michael.kriese@visualon.de> * fix(type): make homeMatch keys optional * Fixes Co-authored-by: Stefano Zaninetta <stefano.zaninetta@nagra.com> Co-authored-by: Michael Kriese <michael.kriese@visualon.de> --- .../datasource/helm/__fixtures__/index.yaml | 70 +++++++++++++++++++ .../datasource/helm/__fixtures__/sample.yaml | 17 +++++ lib/modules/datasource/helm/common.spec.ts | 12 ++-- lib/modules/datasource/helm/common.ts | 47 +++++++++---- lib/modules/datasource/helm/index.spec.ts | 18 +++++ lib/modules/datasource/helm/index.ts | 8 ++- 6 files changed, 151 insertions(+), 21 deletions(-) diff --git a/lib/modules/datasource/helm/__fixtures__/index.yaml b/lib/modules/datasource/helm/__fixtures__/index.yaml index 870b7b419e..6f8c60e890 100644 --- a/lib/modules/datasource/helm/__fixtures__/index.yaml +++ b/lib/modules/datasource/helm/__fixtures__/index.yaml @@ -1872,3 +1872,73 @@ entries: urls: - https://charts.helm.sh/stable/packages/ambassador-1.0.0.tgz version: 1.0.0 + cluster-autoscaler: + - apiVersion: v2 + appVersion: 1.21.1 + created: "2021-12-14T18:07:21.619018562Z" + description: Scales Kubernetes worker nodes within autoscaling groups. + digest: 5685825bce34653919c9d23ca833b99f2ba359aad6dc89afacdf32208c4d0e16 + home: https://www.autoscaler.io/9.10.9 + icon: https://github.com/kubernetes/kubernetes/raw/master/logo/logo.png + maintainers: + - email: e.bailey@sportradar.com + name: yurrriq + - email: mgoodness@gmail.com + name: mgoodness + - email: guyjtempleton@googlemail.com + name: gjtempleton + - email: scott.crooks@gmail.com + name: sc250024 + name: cluster-autoscaler + sources: + - https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler#9.10.9 + type: application + urls: + - cluster-autoscaler-9.10.9.tgz + version: 9.10.9 + - apiVersion: v2 + appVersion: 1.21.1 + created: "2021-12-22T11:20:10.489588334Z" + description: Scales Kubernetes worker nodes within autoscaling groups. + digest: 0da701c485890b77ec45853aa3b5ad8644ff7c71d6cd2d5ee65ee54d118ca99b + home: https://www.autoscaler.io/9.11.0 + icon: https://github.com/kubernetes/kubernetes/raw/master/logo/logo.png + maintainers: + - email: e.bailey@sportradar.com + name: yurrriq + - email: mgoodness@gmail.com + name: mgoodness + - email: guyjtempleton@googlemail.com + name: gjtempleton + - email: scott.crooks@gmail.com + name: sc250024 + name: cluster-autoscaler + sources: + - https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler#9.11.0 + type: application + urls: + - cluster-autoscaler-9.11.0.tgz + version: 9.11.0 + - apiVersion: v2 + appVersion: 1.21.1 + created: "2021-11-01T22:54:28.760738726Z" + description: Scales Kubernetes worker nodes within autoscaling groups. + digest: 446efc118d134bb3dbc2d30ff10a07bbcaa33726bdabc60ebf2a5fd8b1871392 + home: https://www.autoscaler.io/9.10.8 + icon: https://github.com/kubernetes/kubernetes/raw/master/logo/logo.png + maintainers: + - email: e.bailey@sportradar.com + name: yurrriq + - email: mgoodness@gmail.com + name: mgoodness + - email: guyjtempleton@googlemail.com + name: gjtempleton + - email: scott.crooks@gmail.com + name: sc250024 + name: cluster-autoscaler + sources: + - https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler#9.10.8 + type: application + urls: + - cluster-autoscaler-9.10.8.tgz + version: 9.10.8 diff --git a/lib/modules/datasource/helm/__fixtures__/sample.yaml b/lib/modules/datasource/helm/__fixtures__/sample.yaml index 9e3c6d97bb..9e2afe89d9 100644 --- a/lib/modules/datasource/helm/__fixtures__/sample.yaml +++ b/lib/modules/datasource/helm/__fixtures__/sample.yaml @@ -93,3 +93,20 @@ entries: - home: urls: - some.tgz + dummy-no-home: + - description: dummy chart without home metadata + name: dummy-no-home + sources: + - https://github.com/dummyorg/dummymonorepo/tree/main/charts/dummy-no-home + version: 0.0.42 + urls: + - some.tgz + dummy-no-chart-repo: + - description: dummy chart without a valid chart repo URL + name: dummy-no-chart-repo + home: https://github.com/dummyorg/dummymonorepo/tree/main/charts/dummy-no-chart-repo + sources: + - https://some.test + version: 0.0.42 + urls: + - some.tgz diff --git a/lib/modules/datasource/helm/common.spec.ts b/lib/modules/datasource/helm/common.spec.ts index 48d4d0906d..d0f33613d6 100644 --- a/lib/modules/datasource/helm/common.spec.ts +++ b/lib/modules/datasource/helm/common.spec.ts @@ -11,11 +11,13 @@ const repo = load(loadFixture('sample.yaml'), { describe('modules/datasource/helm/common', () => { describe('findSourceUrl', () => { test.each` - input | output - ${'airflow'} | ${{ sourceUrl: 'https://github.com/bitnami/charts', sourceDirectory: 'bitnami/airflow' }} - ${'coredns'} | ${{ sourceUrl: 'https://github.com/coredns/helm', sourceDirectory: undefined }} - ${'pgadmin4'} | ${{ sourceUrl: 'https://github.com/rowanruseler/helm-charts', sourceDirectory: undefined }} - ${'dummy'} | ${{}} + input | output + ${'airflow'} | ${{ sourceUrl: 'https://github.com/bitnami/charts', sourceDirectory: 'bitnami/airflow' }} + ${'coredns'} | ${{ sourceUrl: 'https://github.com/coredns/helm', sourceDirectory: undefined }} + ${'pgadmin4'} | ${{ sourceUrl: 'https://github.com/rowanruseler/helm-charts', sourceDirectory: undefined }} + ${'dummy-no-home'} | ${{ sourceUrl: 'https://github.com/dummyorg/dummymonorepo', sourceDirectory: 'charts/dummy-no-home' }} + ${'dummy-no-chart-repo'} | ${{ sourceUrl: 'https://github.com/dummyorg/dummymonorepo', sourceDirectory: 'charts/dummy-no-chart-repo' }} + ${'dummy'} | ${{}} `( '$input -> $output', ({ input, output }: { input: string; output: string }) => { diff --git a/lib/modules/datasource/helm/common.ts b/lib/modules/datasource/helm/common.ts index 4dfc00984b..0a82fd9988 100644 --- a/lib/modules/datasource/helm/common.ts +++ b/lib/modules/datasource/helm/common.ts @@ -16,13 +16,11 @@ export function findSourceUrl(release: HelmRelease): RepoSource { return { sourceUrl: releaseMatch[1] }; } - if (release.home) { - const githubUrlMatch = githubUrl.exec(release.home); - if (githubUrlMatch?.groups && chartRepo.test(githubUrlMatch?.groups.repo)) { - return { - sourceUrl: githubUrlMatch.groups.url, - sourceDirectory: githubUrlMatch.groups.path, - }; + const homeMatchGroups = release.home && githubUrl.exec(release.home)?.groups; + if (homeMatchGroups) { + const { url: sourceUrl, path: sourceDirectory, repo } = homeMatchGroups; + if (chartRepo.test(repo)) { + return { sourceUrl, sourceDirectory }; } } @@ -31,15 +29,36 @@ export function findSourceUrl(release: HelmRelease): RepoSource { } for (const url of release.sources) { - const githubUrlMatch = githubUrl.exec(url); - if (githubUrlMatch?.groups && chartRepo.test(githubUrlMatch?.groups.repo)) { - return { - sourceUrl: githubUrlMatch.groups.url, - sourceDirectory: githubUrlMatch.groups.path, - }; + const githubUrlMatchGroups = githubUrl.exec(url)?.groups; + if (githubUrlMatchGroups) { + const { + url: sourceUrl, + path: sourceDirectory, + repo, + } = githubUrlMatchGroups; + if (chartRepo.test(repo)) { + return { sourceUrl, sourceDirectory }; + } + } + } + + // fallback: if neither home nor sources are a chart repo URL, use githubUrl (if present) + if (homeMatchGroups) { + const { url: sourceUrl, path: sourceDirectory } = homeMatchGroups; + if (sourceUrl && sourceDirectory) { + return { sourceUrl, sourceDirectory }; + } + } + + for (const source of release.sources) { + const firstSourceMatch = githubUrl.exec(source)?.groups; + if (firstSourceMatch) { + const { url: sourceUrl, path: sourceDirectory } = firstSourceMatch; + if (sourceUrl && sourceDirectory) { + return { sourceUrl, sourceDirectory }; + } } } - // fallback return { sourceUrl: release.sources[0] }; } diff --git a/lib/modules/datasource/helm/index.spec.ts b/lib/modules/datasource/helm/index.spec.ts index 54ea10e119..3d03c3b992 100644 --- a/lib/modules/datasource/helm/index.spec.ts +++ b/lib/modules/datasource/helm/index.spec.ts @@ -189,5 +189,23 @@ describe('modules/datasource/helm/index', () => { releases: expect.toBeArrayOfSize(27), }); }); + + it('returns home and source metadata of the most recent version', async () => { + httpMock + .scope('https://example-repository.com') + .get('/index.yaml') + .reply(200, indexYaml); + const releases = await getPkgReleases({ + datasource: HelmDatasource.id, + depName: 'cluster-autoscaler', + registryUrls: ['https://example-repository.com'], + }); + expect(releases).not.toBeNull(); + expect(releases).toMatchObject({ + homepage: 'https://www.autoscaler.io/9.11.0', + sourceDirectory: 'cluster-autoscaler#9.11.0', + sourceUrl: 'https://github.com/kubernetes/autoscaler', + }); + }); }); }); diff --git a/lib/modules/datasource/helm/index.ts b/lib/modules/datasource/helm/index.ts index 6b0018f698..2d719d5ebd 100644 --- a/lib/modules/datasource/helm/index.ts +++ b/lib/modules/datasource/helm/index.ts @@ -1,5 +1,6 @@ import is from '@sindresorhus/is'; import { load } from 'js-yaml'; +import { gt } from 'semver'; import { logger } from '../../../logger'; import { cache } from '../../../util/cache/package/decorator'; import { ensureTrailingSlash } from '../../../util/url'; @@ -62,9 +63,12 @@ export class HelmDatasource extends Datasource { } const result: HelmRepositoryData = {}; for (const [name, releases] of Object.entries(doc.entries)) { - const { sourceUrl, sourceDirectory } = findSourceUrl(releases[0]); + const latestRelease = releases.sort((r0, r1) => + gt(r0.version, r1.version) ? -1 : 1 + )[0]; + const { sourceUrl, sourceDirectory } = findSourceUrl(latestRelease); result[name] = { - homepage: releases[0].home, + homepage: latestRelease.home, sourceUrl, sourceDirectory, releases: releases.map((release) => ({ -- GitLab