mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-25 23:11:31 +00:00
55a7341be2
* test(manager): close azure-pipelines, bundler and cocoapods gaps Adds a pipeline whose step task is not versioned, so nothing is extracted, and a gem lock line carrying no version, which is skipped. Marks four guards that cannot be false: `extractContainer()` always returns a dep, `getLockFilePath()` always returns a path, and the cocoapods dep name, spec name and git account all derive from values their enclosing check already proved present. Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io> * test(manager): close cargo, composer and cpanfile gaps Adds a composer repository map that disables something other than packagist, which is dropped rather than recorded. Marks five guards: the cargo warning only fires for a crate dep and its retry only runs when a dep was already current, a gitlab rule without a token never passes the auth check, and both cpanfile handlers run only once their match produced a value. Two implicit elses stay counted, in the cargo version resolver and the composer repository mapper, since a coverage-ignore hint does not attach to an `else if`. Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io> * test(manager): close deps-edn, docker-compose and dockerfile gaps Adds three extractions: a deps.edn alias whose value is not a map, a compose extension carrying no image, and a dockerfile escape directive naming a character other than a backtick, which leaves the default in place. Marks the deps-edn repository name check, since object keys are always strings, and notes the repository spec chain, where a coverage-ignore hint does not attach to an `else if`. Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io> * test(manager/flux): close the flux coverage gaps Adds two GitRepository resources whose url is ssh rather than http, one pinned to a tag and one to a commit. Neither yields a source url, since only http urls can be turned into one. Marks the Kustomization image guard: the schema rejects an image without a name, so `extractImage()` cannot return null there. Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io> * test(manager): mark github-actions, gitlabci and glasskube guards None of these six needs a test. A parsed action ref is either a docker or a repository ref, `getDep()` always returns a dep for a job container and a service, and the remaining three need a listed file that cannot be read, a listed file that yields no deps, or a manifest whose repositories match no name. The glasskube resource kind chain stays counted, since a coverage-ignore hint does not attach to an `else if`. Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io> * test(manager): mark gomod and gradle-wrapper guards Four guards that need setups no test provides: a removed dep that is not added back, a go.mod the replace massaging leaves unchanged, and a daemon-jvm file carrying no toolchain version. A parsed go directive always yields a version. The additional-dependency count chain stays counted, since a coverage-ignore hint does not attach to an `else if`. Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io> --------- Co-authored-by: Claude Opus 5 <michael.kriese+claude-code@mend.io>
166 lines
5.0 KiB
TypeScript
166 lines
5.0 KiB
TypeScript
import os from 'node:os';
|
|
import upath from 'upath';
|
|
import { GlobalConfig } from '../../../config/global.ts';
|
|
import { logger } from '../../../logger/index.ts';
|
|
import {
|
|
chmodLocalFile,
|
|
localPathExists,
|
|
readLocalFile,
|
|
statLocalFile,
|
|
} from '../../../util/fs/index.ts';
|
|
import { regEx } from '../../../util/regex.ts';
|
|
import gradleVersioning from '../../versioning/gradle/index.ts';
|
|
import { parseJavaToolchainVersion } from '../gradle/parser.ts';
|
|
import type { GradleVersionExtract } from './types.ts';
|
|
|
|
export const extraEnv = {
|
|
GRADLE_OPTS:
|
|
'-Dorg.gradle.parallel=true -Dorg.gradle.configureondemand=true -Dorg.gradle.daemon=false -Dorg.gradle.caching=false',
|
|
};
|
|
|
|
export function gradleWrapperFileName(): string {
|
|
if (
|
|
os.platform() === 'win32' &&
|
|
GlobalConfig.get('binarySource') !== 'docker'
|
|
) {
|
|
return 'gradlew.bat';
|
|
}
|
|
return './gradlew';
|
|
}
|
|
|
|
export async function prepareGradleCommand(
|
|
gradlewFile: string,
|
|
): Promise<string | null> {
|
|
const gradlewStat = await statLocalFile(gradlewFile);
|
|
if (gradlewStat?.isFile() === true) {
|
|
// if the file is not executable by others
|
|
if (os.platform() !== 'win32' && (gradlewStat.mode & 0o1) === 0) {
|
|
logger.debug('Gradle wrapper is missing the executable bit');
|
|
// add the execution permission to the owner, group and others
|
|
await chmodLocalFile(gradlewFile, gradlewStat.mode | 0o111);
|
|
}
|
|
return gradleWrapperFileName();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Find compatible java version for gradle.
|
|
* see https://docs.gradle.org/current/userguide/compatibility.html
|
|
* @param gradleVersion current gradle version
|
|
* @param gradlewFile path to gradle wrapper
|
|
* @returns A Java semver range
|
|
*/
|
|
export async function getJavaConstraint(
|
|
gradleVersion: string | null | undefined,
|
|
gradlewFile: string,
|
|
): Promise<string> {
|
|
const major = gradleVersion ? gradleVersioning.getMajor(gradleVersion) : null;
|
|
const minor = gradleVersion ? gradleVersioning.getMinor(gradleVersion) : null;
|
|
|
|
if (major) {
|
|
// https://docs.gradle.org/8.8/release-notes.html#daemon-toolchains
|
|
if (major > 8 || (major === 8 && minor && minor >= 8)) {
|
|
const toolChainVersion = await getJvmConfiguration(gradlewFile);
|
|
if (toolChainVersion) {
|
|
return `^${toolChainVersion}.0.0`;
|
|
}
|
|
}
|
|
// https://docs.gradle.org/6.7/release-notes.html#new-jvm-ecosystem-features
|
|
if (major > 6 || (major === 6 && minor && minor >= 7)) {
|
|
const languageVersion = await getJavaLanguageVersion(gradlewFile);
|
|
if (languageVersion) {
|
|
return `^${languageVersion}.0.0`;
|
|
}
|
|
}
|
|
if (major > 9 || (major === 9 && minor && minor >= 1)) {
|
|
return '^25.0.0';
|
|
}
|
|
if (major > 8 || (major === 8 && minor && minor >= 5)) {
|
|
return '^21.0.0';
|
|
}
|
|
if (major > 7 || (major === 7 && minor && minor >= 3)) {
|
|
return '^17.0.0';
|
|
}
|
|
if (major === 7) {
|
|
return '^16.0.0';
|
|
}
|
|
// first public gradle version was 2.0
|
|
if (major > 0 && major < 5) {
|
|
return '^8.0.0';
|
|
}
|
|
}
|
|
|
|
return '^11.0.0';
|
|
}
|
|
|
|
/**
|
|
* https://docs.gradle.org/current/userguide/gradle_daemon.html#sec:daemon_jvm_criteria
|
|
*/
|
|
export async function getJvmConfiguration(
|
|
gradlewFile: string,
|
|
): Promise<string | null> {
|
|
const daemonJvmFile = upath.join(
|
|
upath.dirname(gradlewFile),
|
|
'gradle/gradle-daemon-jvm.properties',
|
|
);
|
|
const daemonJvm = await readLocalFile(daemonJvmFile, 'utf8');
|
|
if (daemonJvm) {
|
|
const TOOLCHAIN_VERSION_REGEX = regEx(
|
|
'^(?:toolchainVersion\\s*=\\s*)(?<version>\\d+)$',
|
|
'm',
|
|
);
|
|
const toolChainMatch = TOOLCHAIN_VERSION_REGEX.exec(daemonJvm);
|
|
// v8 ignore else -- needs a daemon-jvm file without a toolchain version
|
|
if (toolChainMatch?.groups) {
|
|
return toolChainMatch.groups.version;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* https://docs.gradle.org/current/userguide/toolchains.html#sec:consuming
|
|
*/
|
|
export async function getJavaLanguageVersion(
|
|
gradlewFile: string,
|
|
): Promise<string | null> {
|
|
const localGradleDir = upath.dirname(gradlewFile);
|
|
let buildFileName = upath.join(localGradleDir, 'build.gradle');
|
|
if (!(await localPathExists(buildFileName))) {
|
|
buildFileName = upath.join(localGradleDir, 'build.gradle.kts');
|
|
}
|
|
|
|
const buildFileContent = await readLocalFile(buildFileName, 'utf8');
|
|
if (!buildFileContent) {
|
|
logger.debug('build.gradle or build.gradle.kts not found');
|
|
return null;
|
|
}
|
|
|
|
return parseJavaToolchainVersion(buildFileContent);
|
|
}
|
|
|
|
// https://regex101.com/r/IcOs7P/1
|
|
const DISTRIBUTION_URL_REGEX = regEx(
|
|
'^(?:distributionUrl\\s*=\\s*)(?<url>\\S*-(?<version>\\d+\\.\\d+(?:\\.\\d+)?(?:-\\w+)*)-(?<type>bin|all)\\.zip)\\s*$',
|
|
'm',
|
|
);
|
|
|
|
export function extractGradleVersion(
|
|
fileContent: string,
|
|
): GradleVersionExtract | null {
|
|
const distributionUrlMatch = DISTRIBUTION_URL_REGEX.exec(fileContent);
|
|
if (distributionUrlMatch?.groups) {
|
|
return {
|
|
url: distributionUrlMatch.groups.url,
|
|
version: distributionUrlMatch.groups.version,
|
|
};
|
|
}
|
|
logger.debug(
|
|
'Gradle wrapper version and url could not be extracted from properties - skipping update',
|
|
);
|
|
|
|
return null;
|
|
}
|