mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-25 23:11:31 +00:00
4cb4da6bd1
* test(manager): close ansible-galaxy, bun and droneci gaps Adds three extractions: a bun workspace glob that matches no file, a workspace package file that cannot be read, and a drone image continuation that is never terminated. Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io> * test(manager/gradle): mark the gradle parser and extract guards Nineteen guards across the gradle family, none of which a test reaches without a build script contrived to defeat the parser. Most are variable lookups and string interpolations that resolved to nothing; the rest cover a catalog fallback already marked unreachable, a registry that is already known, and a dep that did not default to the maven datasource a line earlier. The include/exclude mode 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): close kustomize, jenkins and homebrew gaps All five by test, no ignores. A kustomization declaring a local component, a nameless image and a nameless helm chart yields none of them, a jenkins plugin entry without an artifactId is skipped, and a github archive url that is not a tar.gz keeps its suffix in the version rather than having it trimmed. Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io> * test(manager/maven): mark the maven extract and update guards Fifteen guards across the maven family. Most check a field the extractor always populates - a dep name, registry urls, a current value. The rest cover a settings.xml carrying no registries, an array that is never falsy, a regex whose groups are present because the line already matched, and three update paths that a buildpack or snapshot bump always satisfies. One is left counted: the `propSource` fallback carries an `istanbul ignore next` that covers the line but not the expression's branch, and widening it would mean rewriting an existing hint. Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io> * test(manager/droneci): write the fixture with codeBlock The unterminated image fixture was assembled by joining an array of strings, which hid the shape of the file behind quoting and escapes. It is now a codeBlock literal laid out as the yaml it represents, with a parent key so the indentation the extractor matches on survives the dedent. Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io> * test(manager): indent the kustomize and jenkins fixtures properly The kustomize fixture sat flush with the statement and listed its components, images and helm charts at the same indentation as their keys. It is now indented one level inside the literal, with the list items nested under the keys as yaml is normally written. The jenkins fixture was an inline string with escaped newlines; it is now a codeBlock literal laid out the same way. Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io> --------- Co-authored-by: Claude Opus 5 <michael.kriese+claude-code@mend.io>
162 lines
4.3 KiB
TypeScript
162 lines
4.3 KiB
TypeScript
import { lang, query as q } from '@renovatebot/good-enough-parser';
|
|
import { newlineRegex, regEx } from '../../../util/regex.ts';
|
|
import type { PackageDependency } from '../types.ts';
|
|
import { qApplyFrom } from './parser/apply-from.ts';
|
|
import { qAssignments } from './parser/assignments.ts';
|
|
import { qKotlinImport } from './parser/common.ts';
|
|
import { qDependencies, qLongFormDep } from './parser/dependencies.ts';
|
|
import { setParseGradleFunc } from './parser/handlers.ts';
|
|
import { qToolchainVersion } from './parser/language-version.ts';
|
|
import { qKotlinMultiObjectVarAssignment } from './parser/objects.ts';
|
|
import { qPlugins } from './parser/plugins.ts';
|
|
import { qRegistryUrls } from './parser/registry-urls.ts';
|
|
import { qVersionCatalogs } from './parser/version-catalogs.ts';
|
|
import type {
|
|
Ctx,
|
|
GradleManagerData,
|
|
PackageRegistry,
|
|
PackageVariables,
|
|
ParseGradleResult,
|
|
} from './types.ts';
|
|
import { parseDependencyString } from './utils.ts';
|
|
|
|
const groovy = lang.createLang('groovy');
|
|
const ctx: Ctx = {
|
|
packageFile: '',
|
|
fileContents: {},
|
|
recursionDepth: 0,
|
|
|
|
globalVars: {},
|
|
deps: [],
|
|
registryUrls: [],
|
|
|
|
varTokens: [],
|
|
tmpKotlinImportStore: [],
|
|
tmpNestingDepth: [],
|
|
tmpRegistryContent: [],
|
|
tmpTokenStore: {},
|
|
tokenMap: {},
|
|
};
|
|
|
|
setParseGradleFunc(parseGradle);
|
|
|
|
export function parseGradle(
|
|
input: string,
|
|
initVars: PackageVariables = {},
|
|
packageFile = '',
|
|
fileContents: Record<string, string | null> = {},
|
|
recursionDepth = 0,
|
|
): ParseGradleResult {
|
|
let vars: PackageVariables = { ...initVars };
|
|
const deps: PackageDependency<GradleManagerData>[] = [];
|
|
const urls: PackageRegistry[] = [];
|
|
|
|
const query = q.tree<Ctx>({
|
|
type: 'root-tree',
|
|
search: q.alt<Ctx>(
|
|
qKotlinImport,
|
|
qAssignments,
|
|
qKotlinMultiObjectVarAssignment,
|
|
qDependencies,
|
|
qPlugins,
|
|
qRegistryUrls,
|
|
qVersionCatalogs,
|
|
qLongFormDep,
|
|
qApplyFrom,
|
|
),
|
|
});
|
|
|
|
const parsedResult = groovy.query(input, query, {
|
|
...ctx,
|
|
packageFile,
|
|
fileContents,
|
|
recursionDepth,
|
|
globalVars: vars,
|
|
});
|
|
|
|
if (parsedResult) {
|
|
deps.push(...parsedResult.deps);
|
|
vars = { ...vars, ...parsedResult.globalVars };
|
|
urls.push(...parsedResult.registryUrls);
|
|
}
|
|
|
|
return { deps, urls, vars };
|
|
}
|
|
|
|
export function parseKotlinSource(
|
|
input: string,
|
|
initVars: PackageVariables = {},
|
|
packageFile = '',
|
|
): { vars: PackageVariables; deps: PackageDependency<GradleManagerData>[] } {
|
|
let vars: PackageVariables = { ...initVars };
|
|
const deps: PackageDependency<GradleManagerData>[] = [];
|
|
|
|
const query = q.tree<Ctx>({
|
|
type: 'root-tree',
|
|
maxDepth: 1,
|
|
search: qKotlinMultiObjectVarAssignment,
|
|
});
|
|
|
|
const parsedResult = groovy.query(input, query, {
|
|
...ctx,
|
|
packageFile,
|
|
globalVars: vars,
|
|
});
|
|
|
|
// v8 ignore else -- every parsed script yields a result here
|
|
if (parsedResult) {
|
|
deps.push(...parsedResult.deps);
|
|
vars = { ...vars, ...parsedResult.globalVars };
|
|
}
|
|
|
|
return { deps, vars };
|
|
}
|
|
|
|
export function parseJavaToolchainVersion(input: string): string | null {
|
|
const ctx: Partial<Ctx> = {};
|
|
const parsedResult = groovy.query(input, qToolchainVersion, ctx);
|
|
|
|
return parsedResult?.javaLanguageVersion ?? null;
|
|
}
|
|
|
|
const propWord = '[a-zA-Z_][a-zA-Z0-9_]*(?:\\.[a-zA-Z_][a-zA-Z0-9_]*)*';
|
|
const propRegex = regEx(
|
|
`^(?<leftPart>\\s*(?<key>${propWord})\\s*[= :]\\s*['"]?)(?<value>[^\\s'"]+)['"]?\\s*$`,
|
|
);
|
|
|
|
export function parseProps(
|
|
input: string,
|
|
packageFile?: string,
|
|
): { vars: PackageVariables; deps: PackageDependency<GradleManagerData>[] } {
|
|
let offset = 0;
|
|
const vars: PackageVariables = {};
|
|
const deps: PackageDependency<GradleManagerData>[] = [];
|
|
|
|
for (const line of input.split(newlineRegex)) {
|
|
const lineMatch = propRegex.exec(line);
|
|
if (lineMatch?.groups) {
|
|
const { key, value, leftPart } = lineMatch.groups;
|
|
const replacePosition = offset + leftPart.length;
|
|
const dep = parseDependencyString(value);
|
|
if (dep) {
|
|
deps.push({
|
|
...dep,
|
|
managerData: {
|
|
fileReplacePosition: replacePosition + dep.depName!.length + 1,
|
|
packageFile,
|
|
},
|
|
});
|
|
} else {
|
|
vars[key] = {
|
|
key,
|
|
value,
|
|
fileReplacePosition: replacePosition,
|
|
packageFile,
|
|
};
|
|
}
|
|
}
|
|
offset += line.length + 1;
|
|
}
|
|
return { vars, deps };
|
|
}
|