mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-27 07:50:47 +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>
160 lines
4.5 KiB
TypeScript
160 lines
4.5 KiB
TypeScript
import { logger } from '../../../logger/index.ts';
|
|
import { getSiblingFileName, localPathExists } from '../../../util/fs/index.ts';
|
|
import { newlineRegex, regEx } from '../../../util/regex.ts';
|
|
import { coerceString } from '../../../util/string.ts';
|
|
import { GitTagsDatasource } from '../../datasource/git-tags/index.ts';
|
|
import { GithubTagsDatasource } from '../../datasource/github-tags/index.ts';
|
|
import { GitlabTagsDatasource } from '../../datasource/gitlab-tags/index.ts';
|
|
import { PodDatasource } from '../../datasource/pod/index.ts';
|
|
import type { PackageDependency, PackageFileContent } from '../types.ts';
|
|
import type { ParsedLine } from './types.ts';
|
|
|
|
const regexMappings = [
|
|
regEx(`^\\s*pod\\s+(['"])(?<spec>[^'"/]+)(/(?<subspec>[^'"]+))?(['"])`),
|
|
regEx(
|
|
`^\\s*pod\\s+(['"])[^'"]+(['"])\\s*,\\s*(['"])(?<currentValue>[^'"]+)(['"])\\s*$`,
|
|
),
|
|
regEx(`,\\s*:git\\s*=>\\s*(['"])(?<git>[^'"]+)(['"])`),
|
|
regEx(`,\\s*:tag\\s*=>\\s*(['"])(?<tag>[^'"]+)(['"])`),
|
|
regEx(`,\\s*:path\\s*=>\\s*(['"])(?<path>[^'"]+)(['"])`),
|
|
regEx(`^\\s*source\\s*(['"])(?<source>[^'"]+)(['"])`),
|
|
];
|
|
|
|
export function parseLine(line: string): ParsedLine {
|
|
let result: ParsedLine = {};
|
|
if (!line) {
|
|
return result;
|
|
}
|
|
for (const regex of Object.values(regexMappings)) {
|
|
const match = regex.exec(line.replace(regEx(/#.*$/), ''));
|
|
if (match?.groups) {
|
|
result = { ...result, ...match.groups };
|
|
}
|
|
}
|
|
|
|
if (result.spec) {
|
|
const depName = result.subspec
|
|
? `${result.spec}/${result.subspec}`
|
|
: result.spec;
|
|
const specName = result.spec;
|
|
// v8 ignore else -- both derive from `result.spec`, already truthy above
|
|
if (depName) {
|
|
result.depName = depName;
|
|
}
|
|
// v8 ignore else -- see above
|
|
if (specName) {
|
|
result.specName = specName;
|
|
}
|
|
delete result.spec;
|
|
delete result.subspec;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
export function gitDep(parsedLine: ParsedLine): PackageDependency | null {
|
|
const { depName, git, tag } = parsedLine;
|
|
|
|
const platformMatch = regEx(
|
|
/[@/](?<platform>github|gitlab)\.com[:/](?<account>[^/]+)\/(?<repo>[^/]+)/,
|
|
).exec(coerceString(git));
|
|
|
|
if (platformMatch?.groups) {
|
|
const { account, repo, platform } = platformMatch.groups;
|
|
// v8 ignore else -- the regex only matches when both groups are present
|
|
if (account && repo) {
|
|
const datasource =
|
|
platform === 'github'
|
|
? GithubTagsDatasource.id
|
|
: GitlabTagsDatasource.id;
|
|
return {
|
|
datasource,
|
|
depName,
|
|
packageName: `${account}/${repo.replace(regEx(/\.git$/), '')}`,
|
|
currentValue: tag,
|
|
};
|
|
}
|
|
}
|
|
|
|
return {
|
|
datasource: GitTagsDatasource.id,
|
|
depName,
|
|
packageName: git,
|
|
currentValue: tag,
|
|
};
|
|
}
|
|
|
|
export async function extractPackageFile(
|
|
content: string,
|
|
packageFile: string,
|
|
): Promise<PackageFileContent | null> {
|
|
logger.trace(`cocoapods.extractPackageFile(${packageFile})`);
|
|
const deps: PackageDependency[] = [];
|
|
const lines: string[] = content.split(newlineRegex);
|
|
|
|
const registryUrls: string[] = [];
|
|
|
|
for (let lineNumber = 0; lineNumber < lines.length; lineNumber += 1) {
|
|
const line = lines[lineNumber];
|
|
const parsedLine = parseLine(line);
|
|
const {
|
|
depName,
|
|
specName,
|
|
currentValue,
|
|
git,
|
|
tag,
|
|
path,
|
|
source,
|
|
}: ParsedLine = parsedLine;
|
|
|
|
if (source) {
|
|
registryUrls.push(source.replace(regEx(/\/*$/), ''));
|
|
}
|
|
|
|
if (depName) {
|
|
const managerData = { lineNumber };
|
|
let dep: PackageDependency = {
|
|
depName,
|
|
sharedVariableName: specName,
|
|
skipReason: 'unspecified-version',
|
|
};
|
|
|
|
if (currentValue) {
|
|
dep = {
|
|
depName,
|
|
sharedVariableName: specName,
|
|
datasource: PodDatasource.id,
|
|
currentValue,
|
|
managerData,
|
|
registryUrls,
|
|
};
|
|
} else if (git) {
|
|
if (tag) {
|
|
dep = { ...gitDep(parsedLine), managerData };
|
|
} else {
|
|
dep = {
|
|
depName,
|
|
sharedVariableName: specName,
|
|
skipReason: 'git-dependency',
|
|
};
|
|
}
|
|
} else if (path) {
|
|
dep = {
|
|
depName,
|
|
sharedVariableName: specName,
|
|
skipReason: 'path-dependency',
|
|
};
|
|
}
|
|
|
|
deps.push(dep);
|
|
}
|
|
}
|
|
const res: PackageFileContent = { deps };
|
|
const lockFile = getSiblingFileName(packageFile, 'Podfile.lock');
|
|
// istanbul ignore if
|
|
if (await localPathExists(lockFile)) {
|
|
res.lockFiles = [lockFile];
|
|
}
|
|
return res;
|
|
}
|