From 9e92712b7fd0e0c5db09254fb96bd4bed6ddfed7 Mon Sep 17 00:00:00 2001 From: Sebastian Poxhofer <secustor@users.noreply.github.com> Date: Thu, 20 Jan 2022 10:31:16 +0100 Subject: [PATCH] fix(helmv3): adapt to new OCI format and allow aliases for OCI (#13603) * feat(helmv3): adapt to new OCI format and refactor * add whitespace to tests and null return value of `resolveAlias` * docs(helmv3): use JSDocs for function documentation Co-authored-by: Rhys Arkins <rhys@arkins.net> --- .../helmv3/__snapshots__/extract.spec.ts.snap | 16 +++--- lib/manager/helmv3/extract.spec.ts | 6 ++- lib/manager/helmv3/extract.ts | 53 ++++++------------ lib/manager/helmv3/utils.spec.ts | 43 +++++++++++++++ lib/manager/helmv3/utils.ts | 54 +++++++++++++++++++ 5 files changed, 123 insertions(+), 49 deletions(-) create mode 100644 lib/manager/helmv3/utils.spec.ts create mode 100644 lib/manager/helmv3/utils.ts diff --git a/lib/manager/helmv3/__snapshots__/extract.spec.ts.snap b/lib/manager/helmv3/__snapshots__/extract.spec.ts.snap index 547524fa8d..0d6b4683f0 100644 --- a/lib/manager/helmv3/__snapshots__/extract.spec.ts.snap +++ b/lib/manager/helmv3/__snapshots__/extract.spec.ts.snap @@ -9,7 +9,6 @@ Object { "datasource": "docker", "depName": "library", "lookupName": "ghcr.io/ankitabhopatkar13/library", - "registryUrls": Array [], }, Object { "currentValue": "0.8.1", @@ -64,6 +63,12 @@ Object { "https://registry.example.com/", ], }, + Object { + "currentValue": "2.2.0", + "datasource": "docker", + "depName": "oci-example", + "lookupName": "quay.example.com/organization/oci-example", + }, ], "packageFileVersion": "0.1.0", } @@ -76,17 +81,11 @@ Object { Object { "currentValue": "0.9.0", "depName": "redis", - "registryUrls": Array [ - "@placeholder", - ], "skipReason": "placeholder-url", }, Object { "currentValue": "0.8.1", "depName": "postgresql", - "registryUrls": Array [ - "nope", - ], "skipReason": "invalid-url", }, Object { @@ -113,9 +112,6 @@ Object { Object { "currentValue": "0.8.1", "depName": "postgresql", - "registryUrls": Array [ - "file:///some/local/path/", - ], "skipReason": "local-dependency", }, ], diff --git a/lib/manager/helmv3/extract.spec.ts b/lib/manager/helmv3/extract.spec.ts index fdee21c756..1261309886 100644 --- a/lib/manager/helmv3/extract.spec.ts +++ b/lib/manager/helmv3/extract.spec.ts @@ -79,7 +79,7 @@ describe('manager/helmv3/extract', () => { dependencies: - name: library version: 0.1.0 - repository: oci://ghcr.io/ankitabhopatkar13/library + repository: oci://ghcr.io/ankitabhopatkar13 import-values: - defaults - name: postgresql @@ -119,12 +119,16 @@ describe('manager/helmv3/extract', () => { - name: example version: 1.0.0 repository: alias:longalias + - name: oci-example + version: 2.2.0 + repository: alias:ociRegistry `; const fileName = 'Chart.yaml'; const result = await extractPackageFile(content, fileName, { aliases: { placeholder: 'https://my-registry.gcr.io/', longalias: 'https://registry.example.com/', + ociRegistry: 'oci://quay.example.com/organization', }, }); expect(result).not.toBeNull(); diff --git a/lib/manager/helmv3/extract.ts b/lib/manager/helmv3/extract.ts index bc0266ca3b..fc385c93ae 100644 --- a/lib/manager/helmv3/extract.ts +++ b/lib/manager/helmv3/extract.ts @@ -1,11 +1,11 @@ import is from '@sindresorhus/is'; import { load } from 'js-yaml'; -import * as datasourceDocker from '../../datasource/docker'; import { HelmDatasource } from '../../datasource/helm'; import { logger } from '../../logger'; import { SkipReason } from '../../types'; import { getSiblingFileName, localPathExists } from '../../util/fs'; import type { ExtractConfig, PackageDependency, PackageFile } from '../types'; +import { parseRepository, resolveAlias } from './utils'; export async function extractPackageFile( content: string, @@ -57,45 +57,22 @@ export async function extractPackageFile( depName: dep.name, currentValue: dep.version, }; - if (dep.repository) { - res.registryUrls = [dep.repository]; - if ( - dep.repository.startsWith('@') || - dep.repository.startsWith('alias:') - ) { - const repoWithPrefixRemoved = dep.repository.slice( - dep.repository[0] === '@' ? 1 : 6 - ); - const alias = config.aliases[repoWithPrefixRemoved]; - if (alias) { - res.registryUrls = [alias]; - return res; - } - - res.skipReason = SkipReason.PlaceholderUrl; - } else { - try { - const url = new URL(dep.repository); - switch (url.protocol) { - case 'oci:': - res.datasource = datasourceDocker.id; - res.lookupName = dep.repository.replace('oci://', ''); - res.registryUrls = []; - break; - case 'file:': - res.skipReason = SkipReason.LocalDependency; - break; - default: - } - } catch (err) { - logger.debug({ err }, 'Error parsing url'); - res.skipReason = SkipReason.InvalidUrl; - } - } - } else { + if (!dep.repository) { res.skipReason = SkipReason.NoRepository; + return res; + } + + const repository = resolveAlias(dep.repository, config.aliases); + if (!repository) { + res.skipReason = SkipReason.PlaceholderUrl; + return res; } - return res; + + const result: PackageDependency = { + ...res, + ...parseRepository(dep.name, repository), + }; + return result; }); const res: PackageFile = { deps, diff --git a/lib/manager/helmv3/utils.spec.ts b/lib/manager/helmv3/utils.spec.ts new file mode 100644 index 0000000000..5dc2a8aaf9 --- /dev/null +++ b/lib/manager/helmv3/utils.spec.ts @@ -0,0 +1,43 @@ +import { resolveAlias } from './utils'; + +describe('manager/helmv3/utils', () => { + describe('.resolveAlias()', () => { + it('return alias with "alias:"', () => { + const repoUrl = 'https://charts.helm.sh/stable'; + const repository = resolveAlias('alias:testRepo', { + testRepo: repoUrl, + }); + expect(repository).toBe(repoUrl); + }); + + it('return alias with "@"', () => { + const repoUrl = 'https://charts.helm.sh/stable'; + const repository = resolveAlias('@testRepo', { + testRepo: repoUrl, + }); + expect(repository).toBe(repoUrl); + }); + + it('return null if alias repo is not defined', () => { + const repository = resolveAlias('alias:testRepo', { + anotherRepository: 'https://charts.helm.sh/stable', + }); + expect(repository).toBeNull(); + }); + + it('return resolved repository on OCI registries', () => { + const repository = resolveAlias('alias:artifactory', { + artifactory: 'oci://artifactory.example.com', + }); + expect(repository).toBe('oci://artifactory.example.com'); + }); + + it('return repository parameter if it is not an alias', () => { + const repoUrl = 'https://registry.example.com'; + const repository = resolveAlias(repoUrl, { + anotherRepository: 'https://charts.helm.sh/stable', + }); + expect(repository).toBe(repoUrl); + }); + }); +}); diff --git a/lib/manager/helmv3/utils.ts b/lib/manager/helmv3/utils.ts new file mode 100644 index 0000000000..729faca436 --- /dev/null +++ b/lib/manager/helmv3/utils.ts @@ -0,0 +1,54 @@ +import * as datasourceDocker from '../../datasource/docker'; +import { logger } from '../../logger'; +import { SkipReason } from '../../types'; +import type { PackageDependency } from '../types'; + +export function parseRepository( + depName: string, + repositoryURL: string +): PackageDependency { + const res: PackageDependency = {}; + + try { + const url = new URL(repositoryURL); + switch (url.protocol) { + case 'oci:': + res.datasource = datasourceDocker.id; + res.lookupName = `${repositoryURL.replace('oci://', '')}/${depName}`; + break; + case 'file:': + res.skipReason = SkipReason.LocalDependency; + break; + default: + res.registryUrls = [repositoryURL]; + } + } catch (err) { + logger.debug({ err }, 'Error parsing url'); + res.skipReason = SkipReason.InvalidUrl; + } + return res; +} + +/** + * Resolves alias in repository string. + * + * @param repository to be resolved string + * @param aliases Records containing aliases as key and to be resolved URLs as values + * + * @returns resolved alias. If repository does not contain an alias the repository string will be returned. Should it contain an alias which can not be resolved using `aliases`, null will be returned + */ +export function resolveAlias( + repository: string, + aliases: Record<string, string> +): string | null { + if (!(repository.startsWith('@') || repository.startsWith('alias:'))) { + return repository; + } + + const repoWithPrefixRemoved = repository.slice(repository[0] === '@' ? 1 : 6); + const alias = aliases[repoWithPrefixRemoved]; + if (alias) { + return alias; + } + return null; +} -- GitLab