mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-12 15:06:27 +00:00
fix(manager/gradle): ignore catalog deps without version (#11621)
* fix(manager/gradle): support catalog modules without version * fix: more ignorable deps * chore: fix type Co-authored-by: Rhys Arkins <rhys@arkins.net>
This commit is contained in:
parent
1150b8dc3f
commit
87d26472a4
6 changed files with 217 additions and 68 deletions
|
@ -7,6 +7,9 @@ okHttp = "com.squareup.okhttp3:okhttp:4.9.0"
|
|||
okio = { module = "com.squareup.okio:okio", version = "2.8.0" }
|
||||
picasso = { group = "com.squareup.picasso", name = "picasso", version = "2.5.1" }
|
||||
retrofit2-retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
|
||||
google-firebase-analytics = { module = "com.google.firebase:firebase-analytics" }
|
||||
google-firebase-crashlytics = { group = "com.google.firebase", name = "firebase-crashlytics" }
|
||||
google-firebase-messaging = "com.google.firebase:firebase-messaging"
|
||||
|
||||
[plugins]
|
||||
kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version = "1.5.21" }
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { extractAllPackageFiles } from '..';
|
||||
import { fs, loadFixture } from '../../../../test/util';
|
||||
import type { ExtractConfig } from '../../types';
|
||||
|
||||
jest.mock('../../../util/fs');
|
||||
|
||||
|
@ -24,7 +25,7 @@ describe('manager/gradle/shallow/extract', () => {
|
|||
'build.gradle': '',
|
||||
});
|
||||
|
||||
const res = await extractAllPackageFiles({} as never, [
|
||||
const res = await extractAllPackageFiles({} as ExtractConfig, [
|
||||
'build.gradle',
|
||||
'gradle.properties',
|
||||
]);
|
||||
|
@ -39,7 +40,7 @@ describe('manager/gradle/shallow/extract', () => {
|
|||
'settings.gradle': null,
|
||||
});
|
||||
|
||||
const res = await extractAllPackageFiles({} as never, [
|
||||
const res = await extractAllPackageFiles({} as ExtractConfig, [
|
||||
'build.gradle',
|
||||
'gradle.properties',
|
||||
'settings.gradle',
|
||||
|
@ -75,7 +76,7 @@ describe('manager/gradle/shallow/extract', () => {
|
|||
'settings.gradle': null,
|
||||
});
|
||||
|
||||
const res = await extractAllPackageFiles({} as never, [
|
||||
const res = await extractAllPackageFiles({} as ExtractConfig, [
|
||||
'build.gradle',
|
||||
'gradle.properties',
|
||||
'settings.gradle',
|
||||
|
@ -114,7 +115,7 @@ describe('manager/gradle/shallow/extract', () => {
|
|||
'settings.gradle': null,
|
||||
});
|
||||
|
||||
const res = await extractAllPackageFiles({} as never, [
|
||||
const res = await extractAllPackageFiles({} as ExtractConfig, [
|
||||
'build.gradle',
|
||||
'gradle.properties',
|
||||
'settings.gradle',
|
||||
|
@ -156,7 +157,10 @@ describe('manager/gradle/shallow/extract', () => {
|
|||
|
||||
mockFs(fsMock);
|
||||
|
||||
const res = await extractAllPackageFiles({} as never, Object.keys(fsMock));
|
||||
const res = await extractAllPackageFiles(
|
||||
{} as ExtractConfig,
|
||||
Object.keys(fsMock)
|
||||
);
|
||||
|
||||
expect(res).toMatchObject([
|
||||
{ packageFile: 'gradle.properties', deps: [] },
|
||||
|
@ -187,7 +191,10 @@ describe('manager/gradle/shallow/extract', () => {
|
|||
|
||||
mockFs(fsMock);
|
||||
|
||||
const res = await extractAllPackageFiles({} as never, Object.keys(fsMock));
|
||||
const res = await extractAllPackageFiles(
|
||||
{} as ExtractConfig,
|
||||
Object.keys(fsMock)
|
||||
);
|
||||
|
||||
expect(res).toMatchObject([
|
||||
{
|
||||
|
@ -218,7 +225,10 @@ describe('manager/gradle/shallow/extract', () => {
|
|||
'gradle/libs.versions.toml': tomlFile,
|
||||
};
|
||||
mockFs(fsMock);
|
||||
const res = await extractAllPackageFiles({} as never, Object.keys(fsMock));
|
||||
const res = await extractAllPackageFiles(
|
||||
{} as ExtractConfig,
|
||||
Object.keys(fsMock)
|
||||
);
|
||||
expect(res).toMatchObject([
|
||||
{
|
||||
packageFile: 'gradle/libs.versions.toml',
|
||||
|
@ -302,7 +312,10 @@ describe('manager/gradle/shallow/extract', () => {
|
|||
'gradle/libs.versions.toml': tomlFile,
|
||||
};
|
||||
mockFs(fsMock);
|
||||
const res = await extractAllPackageFiles({} as never, Object.keys(fsMock));
|
||||
const res = await extractAllPackageFiles(
|
||||
{} as ExtractConfig,
|
||||
Object.keys(fsMock)
|
||||
);
|
||||
expect(res).toMatchObject([
|
||||
{
|
||||
packageFile: 'gradle/libs.versions.toml',
|
||||
|
@ -343,6 +356,27 @@ describe('manager/gradle/shallow/extract', () => {
|
|||
packageFile: 'gradle/libs.versions.toml',
|
||||
},
|
||||
},
|
||||
{
|
||||
depName: 'google-firebase-analytics',
|
||||
managerData: {
|
||||
packageFile: 'gradle/libs.versions.toml',
|
||||
},
|
||||
skipReason: 'no-version',
|
||||
},
|
||||
{
|
||||
depName: 'google-firebase-crashlytics',
|
||||
managerData: {
|
||||
packageFile: 'gradle/libs.versions.toml',
|
||||
},
|
||||
skipReason: 'no-version',
|
||||
},
|
||||
{
|
||||
depName: 'google-firebase-messaging',
|
||||
managerData: {
|
||||
packageFile: 'gradle/libs.versions.toml',
|
||||
},
|
||||
skipReason: 'no-version',
|
||||
},
|
||||
{
|
||||
depName: 'org.jetbrains.kotlin.jvm',
|
||||
depType: 'plugin',
|
||||
|
@ -351,7 +385,7 @@ describe('manager/gradle/shallow/extract', () => {
|
|||
lookupName:
|
||||
'org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin',
|
||||
managerData: {
|
||||
fileReplacePosition: 415,
|
||||
fileReplacePosition: 661,
|
||||
packageFile: 'gradle/libs.versions.toml',
|
||||
},
|
||||
registryUrls: [
|
||||
|
@ -386,7 +420,10 @@ describe('manager/gradle/shallow/extract', () => {
|
|||
'gradle/libs.versions.toml': tomlFile,
|
||||
};
|
||||
mockFs(fsMock);
|
||||
const res = await extractAllPackageFiles({} as never, Object.keys(fsMock));
|
||||
const res = await extractAllPackageFiles(
|
||||
{} as ExtractConfig,
|
||||
Object.keys(fsMock)
|
||||
);
|
||||
expect(res).toBeNull();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -67,12 +67,8 @@ export async function extractAllPackageFiles(
|
|||
updateVars(vars);
|
||||
extractedDeps.push(...deps);
|
||||
} else if (isTOMLFile(packageFile)) {
|
||||
try {
|
||||
const updatesFromCatalog = parseCatalog(packageFile, content);
|
||||
extractedDeps.push(...updatesFromCatalog);
|
||||
} catch (error) {
|
||||
logger.warn({ error }, 'TOML parsing error');
|
||||
}
|
||||
const updatesFromCatalog = parseCatalog(packageFile, content);
|
||||
extractedDeps.push(...updatesFromCatalog);
|
||||
} else if (isGradleFile(packageFile)) {
|
||||
const vars = getVars(registry, dir);
|
||||
const {
|
||||
|
@ -89,9 +85,9 @@ export async function extractAllPackageFiles(
|
|||
updateVars(gradleVars);
|
||||
extractedDeps.push(...deps);
|
||||
}
|
||||
} catch (e) {
|
||||
} catch (err) {
|
||||
logger.warn(
|
||||
{ config, packageFile },
|
||||
{ err, config, packageFile },
|
||||
`Failed to process Gradle file: ${packageFile}`
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,15 @@
|
|||
import { parse } from '@iarna/toml';
|
||||
import { PackageDependency } from '../../../types';
|
||||
import { GradleManagerData } from '../../types';
|
||||
import type { GradleCatalog, GradleCatalogPluginDescriptor } from '../types';
|
||||
import deepmerge from 'deepmerge';
|
||||
import { SkipReason } from '../../../../types';
|
||||
import { hasKey } from '../../../../util/object';
|
||||
import type { PackageDependency } from '../../../types';
|
||||
import type { GradleManagerData } from '../../types';
|
||||
import type {
|
||||
GradleCatalog,
|
||||
GradleCatalogArtifactDescriptor,
|
||||
GradleCatalogModuleDescriptor,
|
||||
VersionPointer,
|
||||
} from '../types';
|
||||
|
||||
function findIndexAfter(
|
||||
content: string,
|
||||
|
@ -12,6 +20,123 @@ function findIndexAfter(
|
|||
return slicePoint + content.slice(slicePoint).indexOf(find);
|
||||
}
|
||||
|
||||
function isArtifactDescriptor(
|
||||
obj: GradleCatalogArtifactDescriptor | GradleCatalogModuleDescriptor
|
||||
): obj is GradleCatalogArtifactDescriptor {
|
||||
return hasKey('group', obj);
|
||||
}
|
||||
|
||||
interface VersionExtract {
|
||||
currentValue?: string;
|
||||
fileReplacePosition?: number;
|
||||
}
|
||||
|
||||
function extractVersion({
|
||||
version,
|
||||
versions,
|
||||
depStartIndex,
|
||||
depSubContent,
|
||||
depName,
|
||||
versionStartIndex,
|
||||
versionSubContent,
|
||||
}: {
|
||||
version: string | VersionPointer;
|
||||
versions: Record<string, string>;
|
||||
depStartIndex: number;
|
||||
depSubContent: string;
|
||||
depName: string;
|
||||
versionStartIndex: number;
|
||||
versionSubContent: string;
|
||||
}): VersionExtract {
|
||||
if (!version) {
|
||||
return {};
|
||||
}
|
||||
const currentValue =
|
||||
typeof version === 'string' ? version : versions[version.ref];
|
||||
|
||||
const fileReplacePosition =
|
||||
typeof version === 'string'
|
||||
? depStartIndex + findIndexAfter(depSubContent, depName, currentValue)
|
||||
: versionStartIndex +
|
||||
findIndexAfter(versionSubContent, version.ref, currentValue);
|
||||
return { currentValue, fileReplacePosition };
|
||||
}
|
||||
|
||||
function extractDependency({
|
||||
descriptor,
|
||||
versions,
|
||||
depStartIndex,
|
||||
depSubContent,
|
||||
depName,
|
||||
versionStartIndex,
|
||||
versionSubContent,
|
||||
}: {
|
||||
descriptor:
|
||||
| string
|
||||
| GradleCatalogModuleDescriptor
|
||||
| GradleCatalogArtifactDescriptor;
|
||||
versions: Record<string, string>;
|
||||
depStartIndex: number;
|
||||
depSubContent: string;
|
||||
depName: string;
|
||||
versionStartIndex: number;
|
||||
versionSubContent: string;
|
||||
}): PackageDependency<GradleManagerData> {
|
||||
if (typeof descriptor === 'string') {
|
||||
const [groupName, name, currentValue] = descriptor.split(':');
|
||||
if (!currentValue) {
|
||||
return {
|
||||
depName,
|
||||
skipReason: SkipReason.NoVersion,
|
||||
};
|
||||
}
|
||||
return {
|
||||
depName: `${groupName}:${name}`,
|
||||
groupName,
|
||||
currentValue,
|
||||
managerData: {
|
||||
fileReplacePosition:
|
||||
depStartIndex + findIndexAfter(depSubContent, depName, currentValue),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const { currentValue, fileReplacePosition } = extractVersion({
|
||||
version: descriptor.version,
|
||||
versions,
|
||||
depStartIndex,
|
||||
depSubContent,
|
||||
depName,
|
||||
versionStartIndex,
|
||||
versionSubContent,
|
||||
});
|
||||
|
||||
if (!currentValue) {
|
||||
return {
|
||||
depName,
|
||||
skipReason: SkipReason.NoVersion,
|
||||
};
|
||||
}
|
||||
|
||||
if (isArtifactDescriptor(descriptor)) {
|
||||
const { group: groupName, name } = descriptor;
|
||||
return {
|
||||
depName: `${groupName}:${name}`,
|
||||
groupName,
|
||||
currentValue,
|
||||
managerData: { fileReplacePosition },
|
||||
};
|
||||
}
|
||||
const [groupName, name] = descriptor.module.split(':');
|
||||
const dependency = {
|
||||
depName: `${groupName}:${name}`,
|
||||
groupName,
|
||||
currentValue,
|
||||
managerData: { fileReplacePosition },
|
||||
};
|
||||
return dependency;
|
||||
}
|
||||
|
||||
export function parseCatalog(
|
||||
packageFile: string,
|
||||
content: string
|
||||
|
@ -26,58 +151,46 @@ export function parseCatalog(
|
|||
const extractedDeps: PackageDependency<GradleManagerData>[] = [];
|
||||
for (const libraryName of Object.keys(libs)) {
|
||||
const libDescriptor = libs[libraryName];
|
||||
const group: string =
|
||||
typeof libDescriptor === 'string'
|
||||
? libDescriptor.split(':')[0]
|
||||
: libDescriptor.group || libDescriptor.module?.split(':')[0];
|
||||
const name: string =
|
||||
typeof libDescriptor === 'string'
|
||||
? libDescriptor.split(':')[1]
|
||||
: libDescriptor.name || libDescriptor.module?.split(':')[1];
|
||||
const version = libDescriptor.version || libDescriptor.split(':')[2];
|
||||
const currentVersion =
|
||||
typeof version === 'string' ? version : versions[version.ref];
|
||||
const fileReplacePosition =
|
||||
typeof version === 'string'
|
||||
? libStartIndex +
|
||||
findIndexAfter(libSubContent, libraryName, currentVersion)
|
||||
: versionStartIndex +
|
||||
findIndexAfter(versionSubContent, version.ref, currentVersion);
|
||||
const dependency = {
|
||||
depName: `${group}:${name}`,
|
||||
groupName: group,
|
||||
currentValue: currentVersion,
|
||||
managerData: { fileReplacePosition, packageFile },
|
||||
};
|
||||
const dependency = extractDependency({
|
||||
descriptor: libDescriptor,
|
||||
versions,
|
||||
depStartIndex: libStartIndex,
|
||||
depSubContent: libSubContent,
|
||||
depName: libraryName,
|
||||
versionStartIndex,
|
||||
versionSubContent,
|
||||
});
|
||||
extractedDeps.push(dependency);
|
||||
}
|
||||
|
||||
const plugins = tomlContent.plugins || {};
|
||||
const pluginsStartIndex = content.indexOf('[plugins]');
|
||||
const pluginsSubContent = content.slice(pluginsStartIndex);
|
||||
for (const pluginName of Object.keys(plugins)) {
|
||||
const pluginDescriptor = plugins[
|
||||
pluginName
|
||||
] as GradleCatalogPluginDescriptor;
|
||||
const pluginId = pluginDescriptor.id;
|
||||
const version = pluginDescriptor.version;
|
||||
const currentVersion: string =
|
||||
typeof version === 'string' ? version : versions[version.ref];
|
||||
const fileReplacePosition =
|
||||
typeof version === 'string'
|
||||
? pluginsStartIndex +
|
||||
findIndexAfter(pluginsSubContent, pluginId, currentVersion)
|
||||
: versionStartIndex +
|
||||
findIndexAfter(versionSubContent, version.ref, currentVersion);
|
||||
const pluginDescriptor = plugins[pluginName];
|
||||
const depName = pluginDescriptor.id;
|
||||
const { currentValue, fileReplacePosition } = extractVersion({
|
||||
version: pluginDescriptor.version,
|
||||
versions,
|
||||
depStartIndex: pluginsStartIndex,
|
||||
depSubContent: pluginsSubContent,
|
||||
depName,
|
||||
versionStartIndex,
|
||||
versionSubContent,
|
||||
});
|
||||
|
||||
const dependency = {
|
||||
depType: 'plugin',
|
||||
depName: pluginId,
|
||||
lookupName: `${pluginId}:${pluginId}.gradle.plugin`,
|
||||
depName,
|
||||
lookupName: `${depName}:${depName}.gradle.plugin`,
|
||||
registryUrls: ['https://plugins.gradle.org/m2/'],
|
||||
currentValue: currentVersion,
|
||||
currentValue,
|
||||
commitMessageTopic: `plugin ${pluginName}`,
|
||||
managerData: { fileReplacePosition, packageFile },
|
||||
managerData: { fileReplacePosition },
|
||||
};
|
||||
extractedDeps.push(dependency);
|
||||
}
|
||||
return extractedDeps;
|
||||
return extractedDeps.map((dep) =>
|
||||
deepmerge(dep, { managerData: { packageFile } })
|
||||
);
|
||||
}
|
||||
|
|
|
@ -63,23 +63,23 @@ export interface ParseGradleResult {
|
|||
}
|
||||
|
||||
export interface GradleCatalog {
|
||||
versions?: Map<string, string>;
|
||||
libraries?: Map<
|
||||
versions?: Record<string, string>;
|
||||
libraries?: Record<
|
||||
string,
|
||||
GradleCatalogModuleDescriptor | GradleCatalogArtifactDescriptor | string
|
||||
>;
|
||||
plugins?: Map<string, GradleCatalogPluginDescriptor>;
|
||||
plugins?: Record<string, GradleCatalogPluginDescriptor>;
|
||||
}
|
||||
|
||||
export interface GradleCatalogModuleDescriptor {
|
||||
module: string;
|
||||
version: string | VersionPointer;
|
||||
version?: string | VersionPointer;
|
||||
}
|
||||
|
||||
export interface GradleCatalogArtifactDescriptor {
|
||||
name: string;
|
||||
group: string;
|
||||
version: string | VersionPointer;
|
||||
version?: string | VersionPointer;
|
||||
}
|
||||
|
||||
export interface GradleCatalogPluginDescriptor {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export interface GradleManagerData {
|
||||
fileReplacePosition: number;
|
||||
fileReplacePosition?: number;
|
||||
packageFile?: string;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue