mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-27 07:50:47 +00:00
7b8ac17c36
Co-Authored-By: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
539 lines
17 KiB
TypeScript
539 lines
17 KiB
TypeScript
import { z } from 'zod/v4';
|
|
|
|
import { regEx } from '../../../util/regex.ts';
|
|
import { DockerDatasource } from '../../datasource/docker/index.ts';
|
|
import { DotnetVersionDatasource } from '../../datasource/dotnet-version/index.ts';
|
|
import { GithubReleaseAttachmentsDatasource } from '../../datasource/github-release-attachments/index.ts';
|
|
import { GithubReleasesDatasource } from '../../datasource/github-releases/index.ts';
|
|
import { GradleVersionDatasource } from '../../datasource/gradle-version/index.ts';
|
|
import { JavaVersionDatasource } from '../../datasource/java-version/index.ts';
|
|
import { NodeVersionDatasource } from '../../datasource/node-version/index.ts';
|
|
import { NpmDatasource } from '../../datasource/npm/index.ts';
|
|
import { PypiDatasource } from '../../datasource/pypi/index.ts';
|
|
import { RubyVersionDatasource } from '../../datasource/ruby-version/index.ts';
|
|
import { RustVersionDatasource } from '../../datasource/rust-version/index.ts';
|
|
import * as condaVersioning from '../../versioning/conda/index.ts';
|
|
import * as gradleVersioning from '../../versioning/gradle/index.ts';
|
|
import * as nodeVersioning from '../../versioning/node/index.ts';
|
|
import * as npmVersioning from '../../versioning/npm/index.ts';
|
|
import { splitImageParts } from '../dockerfile/extract.ts';
|
|
import type { PackageDependency } from '../types.ts';
|
|
import type { ActionSchema, KnownActionConfig } from './types.ts';
|
|
|
|
export function actionSchema(
|
|
name: string,
|
|
{ withSchema, ...cfg }: KnownActionConfig,
|
|
): ActionSchema {
|
|
return z
|
|
.object({
|
|
uses: matchAction(name),
|
|
with: withSchema ?? VersionVal,
|
|
})
|
|
.transform(({ with: deps }) =>
|
|
deps.map((dep) => {
|
|
const merged = { ...cfg, ...dep };
|
|
merged.depName ??= merged.packageName;
|
|
return merged;
|
|
}),
|
|
);
|
|
}
|
|
|
|
function matchAction(action: string): z.ZodString {
|
|
return z
|
|
.string()
|
|
.regex(regEx(`(?:https?://[^/]+/)?${RegExp.escape(action)}(?:@.+)?$`));
|
|
}
|
|
|
|
function parseValue(
|
|
currentValue: string | undefined,
|
|
isInvalid?: (val: string) => boolean,
|
|
): PackageDependency {
|
|
if (!currentValue) {
|
|
return {
|
|
skipStage: 'extract',
|
|
skipReason: 'unspecified-version',
|
|
depType: 'uses-with',
|
|
};
|
|
}
|
|
if (isInvalid?.(currentValue) === true) {
|
|
return {
|
|
skipStage: 'extract',
|
|
skipReason: 'invalid-version',
|
|
depType: 'uses-with',
|
|
currentValue,
|
|
};
|
|
}
|
|
return { currentValue, depType: 'uses-with' };
|
|
}
|
|
|
|
/**
|
|
* A single dependency, versioned by the given `with:` input.
|
|
*
|
|
* @param isInvalid should return `true` if the version is invalid and should be skipped
|
|
*/
|
|
function valSchema(
|
|
key: string,
|
|
isInvalid?: (val: string) => boolean,
|
|
): ActionSchema {
|
|
return z
|
|
.object({ [key]: z.string().optional() })
|
|
.transform((val) => [parseValue(val[key], isInvalid)]);
|
|
}
|
|
|
|
const VersionVal = valSchema('version');
|
|
|
|
// Shared by the `actions/setup-{go,node,python}` entries below, whose
|
|
// releases are published as `actions/{go,node,python}-versions` GitHub
|
|
// releases, tagged like `20.11.0` or `20.11.0-1` (a build number suffix).
|
|
const actionsVersionsExtractVersion =
|
|
'^(?<version>\\d+\\.\\d+\\.\\d+)(-\\d+)?$';
|
|
|
|
const InstallBinaryWith: ActionSchema = z
|
|
.object({ repo: z.string(), tag: z.string() })
|
|
.transform(({ repo, tag }) => [{ packageName: repo, ...parseValue(tag) }]);
|
|
|
|
function parseImageValue(image: string | undefined): PackageDependency {
|
|
if (!image) {
|
|
return {
|
|
depType: 'uses-with',
|
|
skipStage: 'extract',
|
|
skipReason: 'unspecified-version',
|
|
};
|
|
}
|
|
|
|
const dep = splitImageParts(image);
|
|
return {
|
|
depType: 'uses-with',
|
|
...dep,
|
|
...(dep.skipReason ? { skipStage: 'extract' } : {}),
|
|
};
|
|
}
|
|
|
|
const EcsRenderTaskDefinitionWith: ActionSchema = z
|
|
.object({ image: z.string().optional() })
|
|
.transform(({ image }) => [parseImageValue(image)]);
|
|
|
|
const sha256Regex = regEx(/^[a-f0-9]{64}$/);
|
|
const MiseWith: ActionSchema = z
|
|
.object({
|
|
version: z.string().optional(),
|
|
sha256: z.string().optional(),
|
|
})
|
|
.transform(({ version, sha256 }) => [
|
|
{
|
|
...parseValue(version),
|
|
...(sha256 && sha256Regex.test(sha256) ? { currentDigest: sha256 } : {}),
|
|
},
|
|
]);
|
|
|
|
// Runtimes installable by `pnpm/setup`, keyed by the name used in its
|
|
// `runtime:` input. `bun` and `deno` reuse the datasources of their respective
|
|
// `setup-*` actions below.
|
|
const pnpmRuntimes: Record<string, PackageDependency | undefined> = {
|
|
node: { datasource: NodeVersionDatasource.id, packageName: 'node' },
|
|
bun: { datasource: NpmDatasource.id, packageName: 'bun' },
|
|
deno: { datasource: NpmDatasource.id, packageName: 'deno' },
|
|
};
|
|
|
|
function parsePnpmRuntime(runtime: string | undefined): PackageDependency[] {
|
|
if (!runtime) {
|
|
return [];
|
|
}
|
|
|
|
// `<name>` or `<name>@<version>`, matching pnpm's `packageManager` field syntax
|
|
const [name, version] = runtime.split('@');
|
|
const cfg = pnpmRuntimes[name];
|
|
if (!cfg) {
|
|
return [
|
|
{
|
|
packageName: name || runtime,
|
|
depType: 'uses-with',
|
|
skipStage: 'extract',
|
|
skipReason: 'invalid-name',
|
|
},
|
|
];
|
|
}
|
|
|
|
return [{ ...cfg, ...parseValue(version) }];
|
|
}
|
|
|
|
const PnpmSetupWith: ActionSchema = z
|
|
.object({
|
|
version: z.string().optional(),
|
|
runtime: z.string().optional(),
|
|
})
|
|
.transform(({ version, runtime }) => [
|
|
parseValue(version),
|
|
...parsePnpmRuntime(runtime),
|
|
]);
|
|
|
|
// Distributions whose version numbering we can reliably track via the
|
|
// java-version datasource (which sources releases from Adoptium/Eclipse
|
|
// Temurin). Other distributions may not follow the same release cadence
|
|
// or versioning, so we don't attempt to track them.
|
|
const supportedJavaDistributions = new Set(['temurin', 'adopt']);
|
|
|
|
const SetupJavaWith: ActionSchema = z
|
|
.object({
|
|
distribution: z.string().optional(),
|
|
'java-version': z.string().optional(),
|
|
'java-package': z.string().optional(),
|
|
})
|
|
.transform(
|
|
({
|
|
distribution,
|
|
'java-version': version,
|
|
'java-package': javaPackage,
|
|
}) => {
|
|
const packageName = javaPackage?.startsWith('jre')
|
|
? 'java-jre'
|
|
: 'java-jdk';
|
|
|
|
if (
|
|
!distribution ||
|
|
!supportedJavaDistributions.has(distribution.toLowerCase())
|
|
) {
|
|
return [
|
|
{
|
|
packageName,
|
|
depType: 'uses-with',
|
|
skipStage: 'extract',
|
|
skipReason: 'unsupported',
|
|
},
|
|
];
|
|
}
|
|
|
|
return [{ packageName, ...parseValue(version) }];
|
|
},
|
|
);
|
|
|
|
// `'latest'` is a valid, documented value for `tflint_version` (it's also the
|
|
// action's own default), but it isn't a version we can pin/bump, so treat it
|
|
// as present-but-unsupported rather than as an invalid value.
|
|
const TflintWith: ActionSchema = z
|
|
.object({ tflint_version: z.string().optional() })
|
|
.transform(({ tflint_version: version }) => {
|
|
if (version === 'latest') {
|
|
return [
|
|
{
|
|
currentValue: version,
|
|
depType: 'uses-with',
|
|
skipStage: 'extract',
|
|
skipReason: 'unsupported-version',
|
|
},
|
|
];
|
|
}
|
|
return [parseValue(version)];
|
|
});
|
|
|
|
const renovateGithubActionDefaultImage = 'ghcr.io/renovatebot/renovate';
|
|
const RenovateGithubActionWith: ActionSchema = z
|
|
.object({
|
|
'renovate-version': z.string().optional(),
|
|
'renovate-image': z.string().optional(),
|
|
})
|
|
.transform(({ 'renovate-version': version, 'renovate-image': image }) => {
|
|
const [packageName, currentDigest] = (
|
|
image ?? renovateGithubActionDefaultImage
|
|
).split('@');
|
|
return [
|
|
{
|
|
packageName,
|
|
...(currentDigest ? { currentDigest } : {}),
|
|
...parseValue(version),
|
|
},
|
|
];
|
|
});
|
|
|
|
/**
|
|
* Community-maintained and first-party (GitHub's own `actions/*`) Actions
|
|
* with known version input schemas.
|
|
*/
|
|
export const knownActions: Record<string, KnownActionConfig> = {
|
|
// https://github.com/actions/setup-dotnet
|
|
'actions/setup-dotnet': {
|
|
datasource: DotnetVersionDatasource.id,
|
|
packageName: 'dotnet-sdk',
|
|
withSchema: valSchema('dotnet-version', (val) => val.includes('\n')),
|
|
},
|
|
// https://github.com/actions/setup-go
|
|
'actions/setup-go': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
depName: 'go',
|
|
packageName: 'actions/go-versions',
|
|
versioning: npmVersioning.id,
|
|
extractVersion: actionsVersionsExtractVersion,
|
|
withSchema: valSchema('go-version'),
|
|
},
|
|
// https://github.com/actions/setup-java
|
|
'actions/setup-java': {
|
|
datasource: JavaVersionDatasource.id,
|
|
packageName: '', // determined from `distribution`/`java-package` inputs
|
|
withSchema: SetupJavaWith,
|
|
},
|
|
// https://github.com/actions/setup-node
|
|
'actions/setup-node': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
depName: 'node',
|
|
packageName: 'actions/node-versions',
|
|
versioning: nodeVersioning.id,
|
|
extractVersion: actionsVersionsExtractVersion,
|
|
withSchema: valSchema('node-version'),
|
|
},
|
|
// https://github.com/actions/setup-python
|
|
'actions/setup-python': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
depName: 'python',
|
|
packageName: 'actions/python-versions',
|
|
versioning: npmVersioning.id,
|
|
extractVersion: actionsVersionsExtractVersion,
|
|
withSchema: valSchema('python-version'),
|
|
},
|
|
// https://github.com/aquaproj/aqua-installer
|
|
'aquaproj/aqua-installer': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
depName: 'aqua',
|
|
packageName: 'aquaproj/aqua',
|
|
withSchema: valSchema('aqua_version'),
|
|
},
|
|
// https://github.com/aquasecurity/setup-trivy
|
|
'aquasecurity/setup-trivy': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
packageName: 'aquasecurity/trivy',
|
|
},
|
|
// https://github.com/aquasecurity/trivy-action
|
|
'aquasecurity/trivy-action': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
packageName: 'aquasecurity/trivy',
|
|
},
|
|
// https://github.com/astral-sh/setup-uv
|
|
'astral-sh/setup-uv': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
versioning: npmVersioning.id,
|
|
packageName: 'astral-sh/uv',
|
|
},
|
|
// https://github.com/aws-actions/amazon-ecs-render-task-definition
|
|
'aws-actions/amazon-ecs-render-task-definition': {
|
|
datasource: DockerDatasource.id,
|
|
packageName: '', // determined from `image` input
|
|
withSchema: EcsRenderTaskDefinitionWith,
|
|
},
|
|
'azure/setup-helm': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
depName: 'helm',
|
|
packageName: 'helm/helm',
|
|
},
|
|
// https://github.com/azure/setup-kubectl
|
|
'azure/setup-kubectl': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
depName: 'kubectl',
|
|
packageName: 'kubernetes/kubernetes',
|
|
},
|
|
// https://github.com/cloudflare/wrangler-action
|
|
'cloudflare/wrangler-action': {
|
|
datasource: NpmDatasource.id,
|
|
packageName: 'wrangler',
|
|
withSchema: valSchema('wranglerVersion'),
|
|
},
|
|
// https://github.com/cycjimmy/semantic-release-action
|
|
'cycjimmy/semantic-release-action': {
|
|
datasource: NpmDatasource.id,
|
|
packageName: 'semantic-release',
|
|
// the action's docs describe `semantic_version` as a version range, not
|
|
// a pinned exact version
|
|
versioning: npmVersioning.id,
|
|
withSchema: valSchema('semantic_version'),
|
|
},
|
|
// https://github.com/azure/setup-helm
|
|
'denoland/setup-deno': {
|
|
datasource: NpmDatasource.id,
|
|
packageName: 'deno',
|
|
withSchema: valSchema('deno-version'),
|
|
},
|
|
// https://github.com/docker/setup-buildx-action
|
|
'docker/setup-buildx-action': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
depName: 'buildx',
|
|
packageName: 'docker/buildx',
|
|
},
|
|
// https://github.com/docker/setup-compose-action
|
|
'docker/setup-compose-action': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
packageName: 'docker/compose',
|
|
},
|
|
// https://github.com/docker/setup-docker-action
|
|
'docker/setup-docker-action': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
depName: 'docker',
|
|
packageName: 'moby/moby',
|
|
extractVersion: '^docker-(?<version>.+)$',
|
|
},
|
|
// https://github.com/dtolnay/rust-toolchain
|
|
'dtolnay/rust-toolchain': {
|
|
datasource: RustVersionDatasource.id,
|
|
packageName: 'rust',
|
|
withSchema: valSchema('toolchain'),
|
|
},
|
|
// https://github.com/expo/expo-github-action
|
|
'expo/expo-github-action': {
|
|
datasource: NpmDatasource.id,
|
|
packageName: 'eas-cli',
|
|
withSchema: valSchema('eas-version'),
|
|
},
|
|
// https://github.com/extractions/setup-just
|
|
'extractions/setup-just': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
depName: 'just',
|
|
packageName: 'casey/just',
|
|
withSchema: valSchema('just-version'),
|
|
},
|
|
// https://github.com/GitTools/actions (there is no root-level Action, only
|
|
// subpaths are usable; the sibling `GitTools/actions/gitreleasemanager/setup`
|
|
// is a separate, unrelated Action)
|
|
'GitTools/actions/gitversion/setup': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
depName: 'gitversion',
|
|
packageName: 'GitTools/GitVersion',
|
|
withSchema: valSchema('versionSpec'),
|
|
},
|
|
'golangci/golangci-lint-action': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
packageName: 'golangci/golangci-lint',
|
|
},
|
|
// https://github.com/gradle/actions (there is no root-level Action, only
|
|
// subpaths such as `setup-gradle` are usable)
|
|
'gradle/actions/setup-gradle': {
|
|
datasource: GradleVersionDatasource.id,
|
|
depName: 'gradle',
|
|
packageName: 'gradle/gradle',
|
|
versioning: gradleVersioning.id,
|
|
withSchema: valSchema('gradle-version'),
|
|
},
|
|
// https://github.com/hashicorp/setup-terraform
|
|
'hashicorp/setup-terraform': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
depName: 'terraform',
|
|
packageName: 'hashicorp/terraform',
|
|
withSchema: valSchema('terraform_version'),
|
|
},
|
|
// https://github.com/helm/chart-releaser-action
|
|
'helm/chart-releaser-action': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
depName: 'chart-releaser',
|
|
packageName: 'helm/chart-releaser',
|
|
},
|
|
// https://github.com/helm/chart-testing-action
|
|
'helm/chart-testing-action': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
depName: 'chart-testing',
|
|
packageName: 'helm/chart-testing',
|
|
},
|
|
'jakebailey/pyright-action': {
|
|
datasource: NpmDatasource.id,
|
|
packageName: 'pyright',
|
|
withSchema: valSchema('version', (val) => val === 'PATH'),
|
|
},
|
|
'jaxxstorm/action-install-gh-release': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
packageName: '', // determined from `repo` input
|
|
withSchema: InstallBinaryWith,
|
|
},
|
|
'jdx/mise-action': {
|
|
datasource: GithubReleaseAttachmentsDatasource.id,
|
|
packageName: 'jdx/mise',
|
|
withSchema: MiseWith,
|
|
},
|
|
// https://github.com/jfrog/setup-jfrog-cli
|
|
'jfrog/setup-jfrog-cli': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
depName: 'jfrog-cli',
|
|
packageName: 'jfrog/jfrog-cli',
|
|
},
|
|
'oven-sh/setup-bun': {
|
|
datasource: NpmDatasource.id,
|
|
packageName: 'bun',
|
|
withSchema: valSchema('bun-version'),
|
|
},
|
|
'pdm-project/setup-pdm': {
|
|
datasource: PypiDatasource.id,
|
|
packageName: 'pdm',
|
|
},
|
|
// https://github.com/peaceiris/actions-hugo
|
|
'peaceiris/actions-hugo': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
depName: 'hugo',
|
|
packageName: 'gohugoio/hugo',
|
|
withSchema: valSchema('hugo-version'),
|
|
},
|
|
'pnpm/action-setup': {
|
|
datasource: NpmDatasource.id,
|
|
packageName: 'pnpm',
|
|
},
|
|
'pnpm/setup': {
|
|
datasource: NpmDatasource.id,
|
|
packageName: 'pnpm',
|
|
withSchema: PnpmSetupWith,
|
|
},
|
|
'prefix-dev/setup-pixi': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
versioning: condaVersioning.id,
|
|
packageName: 'prefix-dev/pixi',
|
|
withSchema: valSchema('pixi-version'),
|
|
},
|
|
// https://github.com/pypa/hatch/tree/install
|
|
'pypa/hatch': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
packageName: 'pypa/hatch',
|
|
// Strip hatch- prefix from release tags
|
|
extractVersion: '^hatch-(?<version>.+)$',
|
|
},
|
|
// https://github.com/renovatebot/github-action
|
|
'renovatebot/github-action': {
|
|
datasource: DockerDatasource.id,
|
|
packageName: '', // determined from `renovate-image` input, if set
|
|
withSchema: RenovateGithubActionWith,
|
|
},
|
|
'ruby/setup-ruby': {
|
|
datasource: RubyVersionDatasource.id,
|
|
packageName: 'ruby',
|
|
withSchema: valSchema('ruby-version'),
|
|
},
|
|
'sigoden/install-binary': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
packageName: '', // determined from `repo` input
|
|
withSchema: InstallBinaryWith,
|
|
},
|
|
'sigstore/cosign-installer': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
packageName: 'sigstore/cosign',
|
|
withSchema: valSchema('cosign-release'),
|
|
},
|
|
// https://github.com/snok/install-poetry
|
|
'snok/install-poetry': {
|
|
datasource: PypiDatasource.id,
|
|
packageName: 'poetry',
|
|
},
|
|
// https://github.com/subosito/flutter-action
|
|
'subosito/flutter-action': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
depName: 'flutter',
|
|
packageName: 'flutter/flutter',
|
|
withSchema: valSchema('flutter-version'),
|
|
},
|
|
// https://github.com/terraform-linters/setup-tflint
|
|
'terraform-linters/setup-tflint': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
depName: 'tflint',
|
|
packageName: 'terraform-linters/tflint',
|
|
withSchema: TflintWith,
|
|
},
|
|
'UpCloudLtd/upcloud-cli-action': {
|
|
datasource: GithubReleasesDatasource.id,
|
|
packageName: 'UpCloudLtd/upcloud-cli',
|
|
},
|
|
'zizmorcore/zizmor-action': {
|
|
datasource: DockerDatasource.id,
|
|
packageName: 'ghcr.io/zizmorcore/zizmor',
|
|
},
|
|
};
|