Files
renovate/lib/modules/manager/vendir/extract.ts
Sebastian Poxhofer be13c9f5f7 feat(manager): share OCI Helm chart resolution across managers (#45760)
* feat(manager): share OCI Helm chart resolution across managers

Add getOciChartDep() to helmv3/oci.ts and use it in argocd, fleet, flux,
helmfile, helmsman, helmv3, kustomize, sveltos, terraform and vendir.

- set pinDigests: false for OCI charts in all of them
- apply registryAliases to OCI charts in argocd, helmfile and helmsman
- keep the registry port in terraform helm_release repositories
- skip fleet OCI charts without a version instead of using 'undefined'

* docs(manager/helmv3): correct the OCI chart pinDigests rationale

* refactor(manager/helmfile): drop redundant OCI repository url guard

The repository schema already requires url to be a string, so the falsy
branch could not be reached by parsed input and left the patch partially
covered.
2026-09-09 13:51:30 +00:00

129 lines
3.4 KiB
TypeScript

import { logger } from '../../../logger/index.ts';
import { getHttpUrl } from '../../../util/git/url.ts';
import { parseSingleYaml } from '../../../util/yaml.ts';
import { GitRefsDatasource } from '../../datasource/git-refs/index.ts';
import { GithubReleasesDatasource } from '../../datasource/github-releases/index.ts';
import { HelmDatasource } from '../../datasource/helm/index.ts';
import { getOciChartDep, isOCIRegistry } from '../helmv3/oci.ts';
import type {
ExtractConfig,
PackageDependency,
PackageFileContent,
} from '../types.ts';
import type {
GitRef,
GithubRelease,
HelmChart,
HttpRelease,
} from './schema.ts';
import { Vendir } from './schema.ts';
export function extractHelmChart(
helmChart: HelmChart,
aliases?: Record<string, string>,
): PackageDependency {
if (isOCIRegistry(helmChart.repository.url)) {
return {
...getOciChartDep(helmChart.repository.url, helmChart.name, aliases),
depName: helmChart.name,
depType: 'HelmChart',
currentValue: helmChart.version,
};
}
return {
depName: helmChart.name,
currentValue: helmChart.version,
depType: 'HelmChart',
registryUrls: [helmChart.repository.url],
datasource: HelmDatasource.id,
};
}
export function extractGitSource(gitSource: GitRef): PackageDependency {
const httpUrl = getHttpUrl(gitSource.url);
return {
depName: httpUrl,
depType: 'GitSource',
currentValue: gitSource.ref,
datasource: GitRefsDatasource.id,
};
}
export function extractGithubReleaseSource(
githubRelease: GithubRelease,
): PackageDependency {
return {
depName: githubRelease.slug,
packageName: githubRelease.slug,
depType: 'GithubRelease',
currentValue: githubRelease.tag,
datasource: GithubReleasesDatasource.id,
};
}
export function extractHttpReleaseSource(
httpRelease: HttpRelease,
): PackageDependency {
return {
packageName: httpRelease.url,
currentValue: 'latest',
depType: 'HttpSource',
skipReason: 'unsupported-datasource',
};
}
export function parseVendir(
content: string,
packageFile?: string,
): Vendir | null {
try {
return parseSingleYaml(content, {
customSchema: Vendir,
removeTemplates: true,
});
} catch {
logger.debug({ packageFile }, 'Error parsing vendir.yml file');
return null;
}
}
export function extractPackageFile(
content: string,
packageFile: string,
config: ExtractConfig,
): PackageFileContent | null {
logger.trace(`vendir.extractPackageFile(${packageFile})`);
const deps: PackageDependency[] = [];
const pkg = parseVendir(content, packageFile);
if (!pkg) {
return null;
}
// grab the helm charts
const contents = pkg.directories.flatMap((directory) => directory.contents);
for (const content of contents) {
// v8 ignore else -- hard to test
if ('helmChart' in content && content.helmChart) {
const dep = extractHelmChart(content.helmChart, config.registryAliases);
deps.push(dep);
} else if ('git' in content && content.git) {
const dep = extractGitSource(content.git);
deps.push(dep);
} else if ('githubRelease' in content && content.githubRelease) {
const dep = extractGithubReleaseSource(content.githubRelease);
deps.push(dep);
}
// v8 ignore else -- hard to test
else if ('http' in content && content.http) {
const dep = extractHttpReleaseSource(content.http);
deps.push(dep);
}
}
if (!deps.length) {
return null;
}
return { deps };
}