Files
Jamie Tanna 967f480f6d fix(manager/github-actions): don't pin partial java-versions
As noted in #46249, `actions/setup-java` documents `java-version` as:

> Java version to install. Supports whole versions, semver ranges,
> early-access versions, and latest.

When the Java version is parsed using the versioning in
`workarounds:javaLTSVersions`, this leads to `11` looking older than
`11.0.32+101`, so Renovate then raises a PR to bump to a full version,
which isn't the intent.

Similar to the fix for mise in
5f5e58b822, we can use `semver-partial`
versioning for whole versions, so `11` stays `11` and only a new major
bumps it to `25`, and exempt `github-actions` from the preset rule that
would otherwise force the Java regex versioning back on.

The remaining documented forms (`21.x`, `>=21`, `21-ea`, `latest`) have
no version we could bump them to, so we skip them as
`unsupported-version` rather than mangling them.

`graalvm/setup-graalvm` reads the same datasource from its own
`java-version` input, so it gets the same treatment.

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-16 14:14:43 +01:00

159 lines
5.2 KiB
TypeScript

import { z } from 'zod/v4';
import { DockerDatasource } from '../../../datasource/docker/index.ts';
import { GithubReleasesDatasource } from '../../../datasource/github-releases/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 type { PackageDependency } from '../../types.ts';
import {
type ActionSchema,
DATASOURCE_DETERMINED_DYNAMICALLY,
type KnownActionConfig,
} from '../types.ts';
import { parseJavaVersion } from './java-version-dynamic.ts';
import { parseImageValue, parseValue } from './utils.ts';
// `helm/kind-action` can yield up to 3 dependencies from a single step: the
// `kind` binary itself, the `kindest/node` image it boots, and (optionally) a
// pinned `kubectl` binary. All 3 inputs are optional, so only emit a
// dependency for the ones a workflow actually sets.
const KindActionWith: ActionSchema = z
.object({
version: z.string().optional(),
node_image: z.string().optional(),
kubectl_version: z.string().optional(),
})
.transform(({ version, node_image, kubectl_version }) => {
const deps: PackageDependency[] = [];
if (version) {
deps.push({
packageName: 'kubernetes-sigs/kind',
...parseValue(version),
});
}
if (node_image) {
// `node_image` may be pinned by digest (e.g.
// `kindest/node:v1.31.0@sha256:...`), so reuse the same Docker
// image-reference parsing as `aws-actions/amazon-ecs-render-task-definition`
// rather than naively splitting on `:`.
deps.push({
datasource: DockerDatasource.id,
...parseImageValue(node_image),
});
}
if (kubectl_version) {
deps.push({
packageName: 'kubernetes/kubernetes',
...parseValue(kubectl_version),
});
}
return deps;
});
// `graalvm/setup-graalvm` can yield up to 2 dependencies from a single step:
// the JDK version it's built on, and the GraalVM distribution version
// itself. Both inputs are optional, so only emit a dependency for the ones
// a workflow actually sets.
//
// `graalvm/graalvm-ce-builds` has used several tag-naming conventions over
// its history (`vm-ce-`, `vm-`, `jdk-`, `graal-`), and still alternates
// between `jdk-` and `graal-` prefixes for releases after GraalVM's 2023
// unification with JDK versioning, so we match both of those current-era
// prefixes rather than either one alone.
const GraalvmSetupWith: ActionSchema = z
.object({
'java-version': z.string().optional(),
version: z.string().optional(),
})
.transform(({ 'java-version': javaVersion, version }) => {
const deps: PackageDependency[] = [];
if (javaVersion) {
deps.push({
datasource: JavaVersionDatasource.id,
packageName: 'java-jdk',
...parseJavaVersion(javaVersion),
});
}
if (version) {
deps.push({
datasource: GithubReleasesDatasource.id,
packageName: 'graalvm/graalvm-ce-builds',
extractVersion: '^(?:jdk|graal)-(?<version>.+)$',
...parseValue(version),
});
}
return deps;
});
// 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),
]);
/**
* Entries whose emitted dependencies span more than one datasource, so no
* single-datasource file (or its structural "same datasource" test) applies.
*/
export const multipleActions: Record<string, KnownActionConfig> = {
// https://github.com/graalvm/setup-graalvm
'graalvm/setup-graalvm': {
datasource: DATASOURCE_DETERMINED_DYNAMICALLY,
packageName: '', // determined per dependency: java-version, version
withSchema: GraalvmSetupWith,
},
// https://github.com/helm/kind-action
'helm/kind-action': {
datasource: GithubReleasesDatasource.id,
packageName: '', // determined per dependency: `version`, `node_image`, `kubectl_version`
withSchema: KindActionWith,
},
'pnpm/setup': {
datasource: NpmDatasource.id,
packageName: 'pnpm',
withSchema: PnpmSetupWith,
},
};