mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-12 23:16:26 +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" }
|
okio = { module = "com.squareup.okio:okio", version = "2.8.0" }
|
||||||
picasso = { group = "com.squareup.picasso", name = "picasso", version = "2.5.1" }
|
picasso = { group = "com.squareup.picasso", name = "picasso", version = "2.5.1" }
|
||||||
retrofit2-retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
|
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]
|
[plugins]
|
||||||
kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version = "1.5.21" }
|
kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version = "1.5.21" }
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { extractAllPackageFiles } from '..';
|
import { extractAllPackageFiles } from '..';
|
||||||
import { fs, loadFixture } from '../../../../test/util';
|
import { fs, loadFixture } from '../../../../test/util';
|
||||||
|
import type { ExtractConfig } from '../../types';
|
||||||
|
|
||||||
jest.mock('../../../util/fs');
|
jest.mock('../../../util/fs');
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ describe('manager/gradle/shallow/extract', () => {
|
||||||
'build.gradle': '',
|
'build.gradle': '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await extractAllPackageFiles({} as never, [
|
const res = await extractAllPackageFiles({} as ExtractConfig, [
|
||||||
'build.gradle',
|
'build.gradle',
|
||||||
'gradle.properties',
|
'gradle.properties',
|
||||||
]);
|
]);
|
||||||
|
@ -39,7 +40,7 @@ describe('manager/gradle/shallow/extract', () => {
|
||||||
'settings.gradle': null,
|
'settings.gradle': null,
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await extractAllPackageFiles({} as never, [
|
const res = await extractAllPackageFiles({} as ExtractConfig, [
|
||||||
'build.gradle',
|
'build.gradle',
|
||||||
'gradle.properties',
|
'gradle.properties',
|
||||||
'settings.gradle',
|
'settings.gradle',
|
||||||
|
@ -75,7 +76,7 @@ describe('manager/gradle/shallow/extract', () => {
|
||||||
'settings.gradle': null,
|
'settings.gradle': null,
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await extractAllPackageFiles({} as never, [
|
const res = await extractAllPackageFiles({} as ExtractConfig, [
|
||||||
'build.gradle',
|
'build.gradle',
|
||||||
'gradle.properties',
|
'gradle.properties',
|
||||||
'settings.gradle',
|
'settings.gradle',
|
||||||
|
@ -114,7 +115,7 @@ describe('manager/gradle/shallow/extract', () => {
|
||||||
'settings.gradle': null,
|
'settings.gradle': null,
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await extractAllPackageFiles({} as never, [
|
const res = await extractAllPackageFiles({} as ExtractConfig, [
|
||||||
'build.gradle',
|
'build.gradle',
|
||||||
'gradle.properties',
|
'gradle.properties',
|
||||||
'settings.gradle',
|
'settings.gradle',
|
||||||
|
@ -156,7 +157,10 @@ describe('manager/gradle/shallow/extract', () => {
|
||||||
|
|
||||||
mockFs(fsMock);
|
mockFs(fsMock);
|
||||||
|
|
||||||
const res = await extractAllPackageFiles({} as never, Object.keys(fsMock));
|
const res = await extractAllPackageFiles(
|
||||||
|
{} as ExtractConfig,
|
||||||
|
Object.keys(fsMock)
|
||||||
|
);
|
||||||
|
|
||||||
expect(res).toMatchObject([
|
expect(res).toMatchObject([
|
||||||
{ packageFile: 'gradle.properties', deps: [] },
|
{ packageFile: 'gradle.properties', deps: [] },
|
||||||
|
@ -187,7 +191,10 @@ describe('manager/gradle/shallow/extract', () => {
|
||||||
|
|
||||||
mockFs(fsMock);
|
mockFs(fsMock);
|
||||||
|
|
||||||
const res = await extractAllPackageFiles({} as never, Object.keys(fsMock));
|
const res = await extractAllPackageFiles(
|
||||||
|
{} as ExtractConfig,
|
||||||
|
Object.keys(fsMock)
|
||||||
|
);
|
||||||
|
|
||||||
expect(res).toMatchObject([
|
expect(res).toMatchObject([
|
||||||
{
|
{
|
||||||
|
@ -218,7 +225,10 @@ describe('manager/gradle/shallow/extract', () => {
|
||||||
'gradle/libs.versions.toml': tomlFile,
|
'gradle/libs.versions.toml': tomlFile,
|
||||||
};
|
};
|
||||||
mockFs(fsMock);
|
mockFs(fsMock);
|
||||||
const res = await extractAllPackageFiles({} as never, Object.keys(fsMock));
|
const res = await extractAllPackageFiles(
|
||||||
|
{} as ExtractConfig,
|
||||||
|
Object.keys(fsMock)
|
||||||
|
);
|
||||||
expect(res).toMatchObject([
|
expect(res).toMatchObject([
|
||||||
{
|
{
|
||||||
packageFile: 'gradle/libs.versions.toml',
|
packageFile: 'gradle/libs.versions.toml',
|
||||||
|
@ -302,7 +312,10 @@ describe('manager/gradle/shallow/extract', () => {
|
||||||
'gradle/libs.versions.toml': tomlFile,
|
'gradle/libs.versions.toml': tomlFile,
|
||||||
};
|
};
|
||||||
mockFs(fsMock);
|
mockFs(fsMock);
|
||||||
const res = await extractAllPackageFiles({} as never, Object.keys(fsMock));
|
const res = await extractAllPackageFiles(
|
||||||
|
{} as ExtractConfig,
|
||||||
|
Object.keys(fsMock)
|
||||||
|
);
|
||||||
expect(res).toMatchObject([
|
expect(res).toMatchObject([
|
||||||
{
|
{
|
||||||
packageFile: 'gradle/libs.versions.toml',
|
packageFile: 'gradle/libs.versions.toml',
|
||||||
|
@ -343,6 +356,27 @@ describe('manager/gradle/shallow/extract', () => {
|
||||||
packageFile: 'gradle/libs.versions.toml',
|
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',
|
depName: 'org.jetbrains.kotlin.jvm',
|
||||||
depType: 'plugin',
|
depType: 'plugin',
|
||||||
|
@ -351,7 +385,7 @@ describe('manager/gradle/shallow/extract', () => {
|
||||||
lookupName:
|
lookupName:
|
||||||
'org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin',
|
'org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin',
|
||||||
managerData: {
|
managerData: {
|
||||||
fileReplacePosition: 415,
|
fileReplacePosition: 661,
|
||||||
packageFile: 'gradle/libs.versions.toml',
|
packageFile: 'gradle/libs.versions.toml',
|
||||||
},
|
},
|
||||||
registryUrls: [
|
registryUrls: [
|
||||||
|
@ -386,7 +420,10 @@ describe('manager/gradle/shallow/extract', () => {
|
||||||
'gradle/libs.versions.toml': tomlFile,
|
'gradle/libs.versions.toml': tomlFile,
|
||||||
};
|
};
|
||||||
mockFs(fsMock);
|
mockFs(fsMock);
|
||||||
const res = await extractAllPackageFiles({} as never, Object.keys(fsMock));
|
const res = await extractAllPackageFiles(
|
||||||
|
{} as ExtractConfig,
|
||||||
|
Object.keys(fsMock)
|
||||||
|
);
|
||||||
expect(res).toBeNull();
|
expect(res).toBeNull();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -67,12 +67,8 @@ export async function extractAllPackageFiles(
|
||||||
updateVars(vars);
|
updateVars(vars);
|
||||||
extractedDeps.push(...deps);
|
extractedDeps.push(...deps);
|
||||||
} else if (isTOMLFile(packageFile)) {
|
} else if (isTOMLFile(packageFile)) {
|
||||||
try {
|
const updatesFromCatalog = parseCatalog(packageFile, content);
|
||||||
const updatesFromCatalog = parseCatalog(packageFile, content);
|
extractedDeps.push(...updatesFromCatalog);
|
||||||
extractedDeps.push(...updatesFromCatalog);
|
|
||||||
} catch (error) {
|
|
||||||
logger.warn({ error }, 'TOML parsing error');
|
|
||||||
}
|
|
||||||
} else if (isGradleFile(packageFile)) {
|
} else if (isGradleFile(packageFile)) {
|
||||||
const vars = getVars(registry, dir);
|
const vars = getVars(registry, dir);
|
||||||
const {
|
const {
|
||||||
|
@ -89,9 +85,9 @@ export async function extractAllPackageFiles(
|
||||||
updateVars(gradleVars);
|
updateVars(gradleVars);
|
||||||
extractedDeps.push(...deps);
|
extractedDeps.push(...deps);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (err) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
{ config, packageFile },
|
{ err, config, packageFile },
|
||||||
`Failed to process Gradle file: ${packageFile}`
|
`Failed to process Gradle file: ${packageFile}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,15 @@
|
||||||
import { parse } from '@iarna/toml';
|
import { parse } from '@iarna/toml';
|
||||||
import { PackageDependency } from '../../../types';
|
import deepmerge from 'deepmerge';
|
||||||
import { GradleManagerData } from '../../types';
|
import { SkipReason } from '../../../../types';
|
||||||
import type { GradleCatalog, GradleCatalogPluginDescriptor } 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(
|
function findIndexAfter(
|
||||||
content: string,
|
content: string,
|
||||||
|
@ -12,6 +20,123 @@ function findIndexAfter(
|
||||||
return slicePoint + content.slice(slicePoint).indexOf(find);
|
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(
|
export function parseCatalog(
|
||||||
packageFile: string,
|
packageFile: string,
|
||||||
content: string
|
content: string
|
||||||
|
@ -26,58 +151,46 @@ export function parseCatalog(
|
||||||
const extractedDeps: PackageDependency<GradleManagerData>[] = [];
|
const extractedDeps: PackageDependency<GradleManagerData>[] = [];
|
||||||
for (const libraryName of Object.keys(libs)) {
|
for (const libraryName of Object.keys(libs)) {
|
||||||
const libDescriptor = libs[libraryName];
|
const libDescriptor = libs[libraryName];
|
||||||
const group: string =
|
const dependency = extractDependency({
|
||||||
typeof libDescriptor === 'string'
|
descriptor: libDescriptor,
|
||||||
? libDescriptor.split(':')[0]
|
versions,
|
||||||
: libDescriptor.group || libDescriptor.module?.split(':')[0];
|
depStartIndex: libStartIndex,
|
||||||
const name: string =
|
depSubContent: libSubContent,
|
||||||
typeof libDescriptor === 'string'
|
depName: libraryName,
|
||||||
? libDescriptor.split(':')[1]
|
versionStartIndex,
|
||||||
: libDescriptor.name || libDescriptor.module?.split(':')[1];
|
versionSubContent,
|
||||||
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 },
|
|
||||||
};
|
|
||||||
extractedDeps.push(dependency);
|
extractedDeps.push(dependency);
|
||||||
}
|
}
|
||||||
|
|
||||||
const plugins = tomlContent.plugins || {};
|
const plugins = tomlContent.plugins || {};
|
||||||
const pluginsStartIndex = content.indexOf('[plugins]');
|
const pluginsStartIndex = content.indexOf('[plugins]');
|
||||||
const pluginsSubContent = content.slice(pluginsStartIndex);
|
const pluginsSubContent = content.slice(pluginsStartIndex);
|
||||||
for (const pluginName of Object.keys(plugins)) {
|
for (const pluginName of Object.keys(plugins)) {
|
||||||
const pluginDescriptor = plugins[
|
const pluginDescriptor = plugins[pluginName];
|
||||||
pluginName
|
const depName = pluginDescriptor.id;
|
||||||
] as GradleCatalogPluginDescriptor;
|
const { currentValue, fileReplacePosition } = extractVersion({
|
||||||
const pluginId = pluginDescriptor.id;
|
version: pluginDescriptor.version,
|
||||||
const version = pluginDescriptor.version;
|
versions,
|
||||||
const currentVersion: string =
|
depStartIndex: pluginsStartIndex,
|
||||||
typeof version === 'string' ? version : versions[version.ref];
|
depSubContent: pluginsSubContent,
|
||||||
const fileReplacePosition =
|
depName,
|
||||||
typeof version === 'string'
|
versionStartIndex,
|
||||||
? pluginsStartIndex +
|
versionSubContent,
|
||||||
findIndexAfter(pluginsSubContent, pluginId, currentVersion)
|
});
|
||||||
: versionStartIndex +
|
|
||||||
findIndexAfter(versionSubContent, version.ref, currentVersion);
|
|
||||||
const dependency = {
|
const dependency = {
|
||||||
depType: 'plugin',
|
depType: 'plugin',
|
||||||
depName: pluginId,
|
depName,
|
||||||
lookupName: `${pluginId}:${pluginId}.gradle.plugin`,
|
lookupName: `${depName}:${depName}.gradle.plugin`,
|
||||||
registryUrls: ['https://plugins.gradle.org/m2/'],
|
registryUrls: ['https://plugins.gradle.org/m2/'],
|
||||||
currentValue: currentVersion,
|
currentValue,
|
||||||
commitMessageTopic: `plugin ${pluginName}`,
|
commitMessageTopic: `plugin ${pluginName}`,
|
||||||
managerData: { fileReplacePosition, packageFile },
|
managerData: { fileReplacePosition },
|
||||||
};
|
};
|
||||||
extractedDeps.push(dependency);
|
extractedDeps.push(dependency);
|
||||||
}
|
}
|
||||||
return extractedDeps;
|
return extractedDeps.map((dep) =>
|
||||||
|
deepmerge(dep, { managerData: { packageFile } })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,23 +63,23 @@ export interface ParseGradleResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GradleCatalog {
|
export interface GradleCatalog {
|
||||||
versions?: Map<string, string>;
|
versions?: Record<string, string>;
|
||||||
libraries?: Map<
|
libraries?: Record<
|
||||||
string,
|
string,
|
||||||
GradleCatalogModuleDescriptor | GradleCatalogArtifactDescriptor | string
|
GradleCatalogModuleDescriptor | GradleCatalogArtifactDescriptor | string
|
||||||
>;
|
>;
|
||||||
plugins?: Map<string, GradleCatalogPluginDescriptor>;
|
plugins?: Record<string, GradleCatalogPluginDescriptor>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GradleCatalogModuleDescriptor {
|
export interface GradleCatalogModuleDescriptor {
|
||||||
module: string;
|
module: string;
|
||||||
version: string | VersionPointer;
|
version?: string | VersionPointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GradleCatalogArtifactDescriptor {
|
export interface GradleCatalogArtifactDescriptor {
|
||||||
name: string;
|
name: string;
|
||||||
group: string;
|
group: string;
|
||||||
version: string | VersionPointer;
|
version?: string | VersionPointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GradleCatalogPluginDescriptor {
|
export interface GradleCatalogPluginDescriptor {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export interface GradleManagerData {
|
export interface GradleManagerData {
|
||||||
fileReplacePosition: number;
|
fileReplacePosition?: number;
|
||||||
packageFile?: string;
|
packageFile?: string;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue