mirror of https://github.com/renovatebot/renovate
1189 lines
35 KiB
TypeScript
1189 lines
35 KiB
TypeScript
import { codeBlock, stripIndent } from 'common-tags';
|
|
import { Fixtures } from '../../../../test/fixtures';
|
|
import { fs, logger, partial } from '../../../../test/util';
|
|
import type { ExtractConfig } from '../types';
|
|
import * as parser from './parser';
|
|
import { extractAllPackageFiles } from '.';
|
|
|
|
jest.mock('../../../util/fs');
|
|
|
|
function mockFs(files: Record<string, string>): void {
|
|
// TODO: fix types, jest is using wrong overload (#22198)
|
|
fs.getLocalFiles.mockImplementation((fileNames: string[]): Promise<any> => {
|
|
const fileContentMap: Record<string, string | null> = {};
|
|
for (const fileName of fileNames) {
|
|
fileContentMap[fileName] = files?.[fileName];
|
|
}
|
|
|
|
return Promise.resolve(fileContentMap);
|
|
});
|
|
|
|
fs.getSiblingFileName.mockImplementation(
|
|
(existingFileNameWithPath: string, otherFileName: string) => {
|
|
return existingFileNameWithPath
|
|
.slice(0, existingFileNameWithPath.lastIndexOf('/') + 1)
|
|
.concat(otherFileName);
|
|
},
|
|
);
|
|
}
|
|
|
|
describe('modules/manager/gradle/extract', () => {
|
|
beforeEach(() => {
|
|
jest.restoreAllMocks();
|
|
});
|
|
|
|
it('returns null', async () => {
|
|
const fsMock = {
|
|
'gradle.properties': '',
|
|
'build.gradle': '',
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
expect(
|
|
await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
),
|
|
).toBeNull();
|
|
});
|
|
|
|
it('logs a warning in case parseGradle throws an exception', async () => {
|
|
const filename = 'build.gradle';
|
|
const err = new Error('unknown');
|
|
const fsMock = {
|
|
'build.gradle': '',
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
jest.spyOn(parser, 'parseGradle').mockImplementationOnce(() => {
|
|
throw err;
|
|
});
|
|
await extractAllPackageFiles(partial<ExtractConfig>(), [filename]);
|
|
|
|
expect(logger.logger.debug).toHaveBeenCalledWith(
|
|
{ err, config: {}, packageFile: filename },
|
|
`Failed to process Gradle file`,
|
|
);
|
|
});
|
|
|
|
it('skips versions composed from multiple variables', async () => {
|
|
const fsMock = {
|
|
'build.gradle':
|
|
'foo = "1"; bar = "2"; baz = "3"; "foo:bar:$foo.$bar.$baz"',
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
const res = await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
);
|
|
|
|
expect(res).toMatchObject([
|
|
{
|
|
packageFile: 'build.gradle',
|
|
deps: [
|
|
{
|
|
depName: 'foo:bar',
|
|
currentValue: '1.2.3',
|
|
skipReason: 'contains-variable',
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
});
|
|
|
|
it('extracts from cross-referenced files', async () => {
|
|
const fsMock = {
|
|
'gradle.properties': 'baz=1.2.3',
|
|
'build.gradle':
|
|
'repositories { maven { url "https://example.com" } }; "foo:bar:$baz@zip"',
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
const res = await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
);
|
|
|
|
expect(res).toMatchObject([
|
|
{
|
|
packageFile: 'gradle.properties',
|
|
deps: [
|
|
{
|
|
depName: 'foo:bar',
|
|
currentValue: '1.2.3',
|
|
registryUrls: ['https://example.com'],
|
|
},
|
|
],
|
|
},
|
|
{ packageFile: 'build.gradle', deps: [] },
|
|
]);
|
|
});
|
|
|
|
it('resolves cross-file Kotlin objects', async () => {
|
|
const fsMock = {
|
|
'buildSrc/src/main/kotlin/Deps.kt': codeBlock`
|
|
object Libraries {
|
|
const val jacksonAnnotations = "com.fasterxml.jackson.core:jackson-annotations:\${Versions.jackson}"
|
|
const val rxjava: String = "io.reactivex.rxjava2:rxjava:" + Versions.rxjava
|
|
const val jCache = "javax.cache:cache-api:1.1.0"
|
|
private const val shadowVersion = "7.1.2"
|
|
|
|
object Kotlin {
|
|
const val version = GradleDeps.Kotlin.version
|
|
const val stdlibJdk = "org.jetbrains.kotlin:kotlin-stdlib:$version"
|
|
}
|
|
|
|
object Android {
|
|
object Tools {
|
|
private const val version = "4.1.2"
|
|
const val buildGradle = "com.android.tools.build:gradle:$version"
|
|
}
|
|
}
|
|
|
|
val modulePlugins = mapOf(
|
|
"shadow" to shadowVersion
|
|
)
|
|
|
|
object Test {
|
|
private const val version = "1.3.0-rc01"
|
|
const val core = "androidx.test:core:\${Test.version}"
|
|
|
|
object Espresso {
|
|
private const val version = "3.3.0-rc01"
|
|
const val espressoCore = "androidx.test.espresso:espresso-core:$version"
|
|
}
|
|
|
|
object Androidx {
|
|
const val coreKtx = "androidx.test:core-ktx:$version"
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
'buildSrc/src/main/kotlin/GradleDeps.kt': codeBlock`
|
|
object GradleDeps {
|
|
object Kotlin {
|
|
const val version = "1.8.10"
|
|
}
|
|
}
|
|
`,
|
|
'buildSrc/src/main/kotlin/Versions.kt': codeBlock`
|
|
object Versions {
|
|
const val jackson = "2.9.10"
|
|
const val rxjava: String = "1.2.3"
|
|
}
|
|
`,
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
const res = await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
);
|
|
|
|
expect(res).toMatchObject([
|
|
{
|
|
packageFile: 'buildSrc/src/main/kotlin/Deps.kt',
|
|
deps: [
|
|
{
|
|
depName: 'javax.cache:cache-api',
|
|
currentValue: '1.1.0',
|
|
groupName: 'Libraries.jCache',
|
|
},
|
|
{
|
|
depName: 'com.android.tools.build:gradle',
|
|
currentValue: '4.1.2',
|
|
groupName: 'Libraries.Android.Tools.version',
|
|
},
|
|
{
|
|
depName: 'androidx.test:core',
|
|
currentValue: '1.3.0-rc01',
|
|
groupName: 'Libraries.Test.version',
|
|
},
|
|
{
|
|
depName: 'androidx.test.espresso:espresso-core',
|
|
currentValue: '3.3.0-rc01',
|
|
groupName: 'Libraries.Test.Espresso.version',
|
|
},
|
|
{
|
|
depName: 'androidx.test:core-ktx',
|
|
currentValue: '1.3.0-rc01',
|
|
groupName: 'Libraries.Test.version',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
packageFile: 'buildSrc/src/main/kotlin/GradleDeps.kt',
|
|
deps: [
|
|
{
|
|
depName: 'org.jetbrains.kotlin:kotlin-stdlib',
|
|
currentValue: '1.8.10',
|
|
groupName: 'GradleDeps.Kotlin.version',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
packageFile: 'buildSrc/src/main/kotlin/Versions.kt',
|
|
deps: [
|
|
{
|
|
depName: 'com.fasterxml.jackson.core:jackson-annotations',
|
|
currentValue: '2.9.10',
|
|
groupName: 'Versions.jackson',
|
|
},
|
|
{
|
|
depName: 'io.reactivex.rxjava2:rxjava',
|
|
currentValue: '1.2.3',
|
|
groupName: 'Versions.rxjava',
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
});
|
|
|
|
it('inherits gradle variables', async () => {
|
|
const fsMock = {
|
|
'gradle.properties': 'foo=1.0.0',
|
|
'build.gradle': 'foo = "1.0.1"',
|
|
'aaa/gradle.properties': 'bar = "2.0.0"',
|
|
'aaa/build.gradle': 'bar = "2.0.1"',
|
|
'aaa/bbb/build.gradle': '"foo:foo:$foo"; "bar:bar:$bar"',
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
const res = await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
);
|
|
|
|
expect(res).toMatchObject([
|
|
{ packageFile: 'gradle.properties', deps: [] },
|
|
{
|
|
packageFile: 'build.gradle',
|
|
deps: [{ depName: 'foo:foo', currentValue: '1.0.1' }],
|
|
},
|
|
{ packageFile: 'aaa/gradle.properties', deps: [] },
|
|
{
|
|
packageFile: 'aaa/build.gradle',
|
|
deps: [{ depName: 'bar:bar', currentValue: '2.0.1' }],
|
|
},
|
|
{ packageFile: 'aaa/bbb/build.gradle', deps: [] },
|
|
]);
|
|
});
|
|
|
|
it('filters duplicate dependency findings', async () => {
|
|
const buildFile = codeBlock`
|
|
apply from: 'test.gradle'
|
|
|
|
repositories {
|
|
mavenCentral()
|
|
}
|
|
|
|
dependencies {
|
|
implementation "io.jsonwebtoken:jjwt-api:$\{jjwtVersion}"
|
|
runtimeOnly "io.jsonwebtoken:jjwt-impl:$\{jjwtVersion}"
|
|
}
|
|
`;
|
|
|
|
const testFile = codeBlock`
|
|
ext.jjwtVersion = '0.11.2'
|
|
|
|
ext {
|
|
jjwtApi = "io.jsonwebtoken:jjwt-api:$jjwtVersion"
|
|
}
|
|
`;
|
|
const fsMock = {
|
|
'build.gradle': buildFile,
|
|
'test.gradle': testFile,
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
const res = await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
);
|
|
|
|
expect(res).toMatchObject([
|
|
{
|
|
packageFile: 'test.gradle',
|
|
deps: [
|
|
{ depName: 'io.jsonwebtoken:jjwt-api' },
|
|
{ depName: 'io.jsonwebtoken:jjwt-impl' },
|
|
],
|
|
},
|
|
{ packageFile: 'build.gradle' },
|
|
]);
|
|
});
|
|
|
|
it('ensures depType is assigned', async () => {
|
|
const fsMock = {
|
|
'build.gradle':
|
|
"id 'org.sonarqube' version '3.1.1'\n\"io.jsonwebtoken:jjwt-api:0.11.2\"",
|
|
'buildSrc/build.gradle': '"com.google.protobuf:protobuf-java:3.18.2"',
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
const res = await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
);
|
|
|
|
expect(res).toMatchObject([
|
|
{
|
|
packageFile: 'build.gradle',
|
|
deps: [
|
|
{ depName: 'org.sonarqube', depType: 'plugin' },
|
|
{ depName: 'io.jsonwebtoken:jjwt-api', depType: 'dependencies' },
|
|
],
|
|
},
|
|
{
|
|
packageFile: 'buildSrc/build.gradle',
|
|
deps: [{ depType: 'devDependencies' }],
|
|
},
|
|
]);
|
|
});
|
|
|
|
describe('registry URLs', () => {
|
|
it('deduplicates registry urls', async () => {
|
|
const fsMock = {
|
|
'build.gradle': codeBlock`
|
|
repositories { maven { url "https://repo.maven.apache.org/maven2" } }
|
|
repositories { maven { url "https://repo.maven.apache.org/maven2" } }
|
|
repositories { maven { url "https://example.com" } }
|
|
repositories { maven { url "https://example.com" } }
|
|
plugins { id "foo.bar" version "1.2.3" }
|
|
dependencies { classpath "foo:bar:1.2.3" }
|
|
`,
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
const res = await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
);
|
|
|
|
expect(res).toMatchObject([
|
|
{
|
|
packageFile: 'build.gradle',
|
|
deps: [
|
|
{
|
|
depType: 'plugin',
|
|
registryUrls: ['https://plugins.gradle.org/m2/'],
|
|
},
|
|
{
|
|
registryUrls: [
|
|
'https://repo.maven.apache.org/maven2',
|
|
'https://example.com',
|
|
],
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
});
|
|
|
|
it('interpolates registry URLs', async () => {
|
|
const buildFile = codeBlock`
|
|
repositories {
|
|
mavenCentral()
|
|
maven {
|
|
url = "\${repositoryBaseURL}/repository-build"
|
|
}
|
|
maven {
|
|
name = "baz"
|
|
url = "\${repositoryBaseURL}/\${name}"
|
|
}
|
|
}
|
|
|
|
dependencies {
|
|
implementation "com.google.protobuf:protobuf-java:2.17.0"
|
|
}
|
|
`;
|
|
|
|
const fsMock = {
|
|
'build.gradle': buildFile,
|
|
'gradle.properties': 'repositoryBaseURL: https\\://dummy.org/whatever',
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
const res = await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
);
|
|
|
|
expect(res).toMatchObject([
|
|
{
|
|
packageFile: 'gradle.properties',
|
|
deps: [],
|
|
},
|
|
{
|
|
packageFile: 'build.gradle',
|
|
deps: [
|
|
{
|
|
depName: 'com.google.protobuf:protobuf-java',
|
|
currentValue: '2.17.0',
|
|
managerData: {
|
|
fileReplacePosition: 262,
|
|
packageFile: 'build.gradle',
|
|
},
|
|
fileReplacePosition: 262,
|
|
registryUrls: [
|
|
'https://repo.maven.apache.org/maven2',
|
|
'https://dummy.org/whatever/repository-build',
|
|
'https://dummy.org/whatever/baz',
|
|
],
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
});
|
|
|
|
it('supports separate registry URLs for plugins', async () => {
|
|
const settingsFile = codeBlock`
|
|
pluginManagement {
|
|
repositories {
|
|
mavenLocal()
|
|
maven { url = "https://foo.bar/plugins" }
|
|
}
|
|
}
|
|
`;
|
|
|
|
const buildFile = codeBlock`
|
|
plugins {
|
|
id "foo.bar" version "1.2.3"
|
|
}
|
|
repositories {
|
|
maven { url = "https://foo.bar/deps" }
|
|
mavenCentral()
|
|
}
|
|
dependencies {
|
|
classpath "io.jsonwebtoken:jjwt-api:0.11.2"
|
|
}
|
|
`;
|
|
|
|
const fsMock = {
|
|
'build.gradle': buildFile,
|
|
'settings.gradle': settingsFile,
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
const res = await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
);
|
|
|
|
expect(res).toMatchObject([
|
|
{
|
|
packageFile: 'settings.gradle',
|
|
deps: [],
|
|
},
|
|
{
|
|
packageFile: 'build.gradle',
|
|
deps: [
|
|
{
|
|
depName: 'foo.bar',
|
|
depType: 'plugin',
|
|
registryUrls: ['https://foo.bar/plugins'],
|
|
},
|
|
{
|
|
depName: 'io.jsonwebtoken:jjwt-api',
|
|
registryUrls: [
|
|
'https://foo.bar/deps',
|
|
'https://repo.maven.apache.org/maven2',
|
|
],
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe('version catalogs', () => {
|
|
it('works with dependency catalogs', async () => {
|
|
const fsMock = {
|
|
'gradle/libs.versions.toml': Fixtures.get('1/libs.versions.toml'),
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
const res = await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
);
|
|
expect(res).toMatchObject([
|
|
{
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
deps: [
|
|
{
|
|
depName: 'io.gitlab.arturbosch.detekt:detekt-formatting',
|
|
groupName: 'detekt',
|
|
currentValue: '1.17.0',
|
|
managerData: {
|
|
fileReplacePosition: 21,
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
},
|
|
{
|
|
depName: 'io.kotest:kotest-assertions-core-jvm',
|
|
groupName: 'kotest',
|
|
currentValue: '4.6.0',
|
|
managerData: {
|
|
fileReplacePosition: 51,
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
},
|
|
{
|
|
depName: 'io.kotest:kotest-runner-junit5',
|
|
groupName: 'kotest',
|
|
currentValue: '4.6.0',
|
|
managerData: {
|
|
fileReplacePosition: 51,
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
},
|
|
{
|
|
depName: 'org.mockito:mockito-core',
|
|
currentValue: '3.10.0',
|
|
managerData: {
|
|
fileReplacePosition: 474,
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
},
|
|
{
|
|
depName: 'com.github.siom79.japicmp:japicmp',
|
|
currentValue: '0.15.+',
|
|
managerData: {
|
|
fileReplacePosition: 561,
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
},
|
|
{
|
|
depName: 'guava',
|
|
skipReason: 'multiple-constraint-dep',
|
|
managerData: {
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
},
|
|
{
|
|
depName: 'gson',
|
|
skipReason: 'unsupported-version',
|
|
managerData: {
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
},
|
|
{
|
|
depName: 'io.gitlab.arturbosch.detekt',
|
|
depType: 'plugin',
|
|
currentValue: '1.17.0',
|
|
packageName:
|
|
'io.gitlab.arturbosch.detekt:io.gitlab.arturbosch.detekt.gradle.plugin',
|
|
managerData: {
|
|
fileReplacePosition: 21,
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
registryUrls: ['https://plugins.gradle.org/m2/'],
|
|
},
|
|
{
|
|
depName: 'org.danilopianini.publish-on-central',
|
|
depType: 'plugin',
|
|
currentValue: '0.5.0',
|
|
packageName:
|
|
'org.danilopianini.publish-on-central:org.danilopianini.publish-on-central.gradle.plugin',
|
|
managerData: {
|
|
fileReplacePosition: 82,
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
registryUrls: ['https://plugins.gradle.org/m2/'],
|
|
},
|
|
{
|
|
depName: 'org.ajoberstar.grgit',
|
|
depType: 'plugin',
|
|
commitMessageTopic: 'plugin grgit',
|
|
packageName:
|
|
'org.ajoberstar.grgit:org.ajoberstar.grgit.gradle.plugin',
|
|
managerData: {
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
registryUrls: ['https://plugins.gradle.org/m2/'],
|
|
skipReason: 'unspecified-version',
|
|
},
|
|
{
|
|
depName: 'org.ajoberstar.grgit2',
|
|
depType: 'plugin',
|
|
skipReason: 'unspecified-version',
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
});
|
|
|
|
it('supports versions declared as single string', async () => {
|
|
const fsMock = {
|
|
'gradle/libs.versions.toml': Fixtures.get('2/libs.versions.toml'),
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
const res = await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
);
|
|
|
|
expect(res).toMatchObject([
|
|
{
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
deps: [
|
|
{
|
|
depName: 'com.squareup.okhttp3:okhttp',
|
|
currentValue: '4.9.0',
|
|
managerData: {
|
|
fileReplacePosition: 100,
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
},
|
|
{
|
|
depName: 'com.squareup.okio:okio',
|
|
currentValue: '2.8.0',
|
|
managerData: {
|
|
fileReplacePosition: 162,
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
},
|
|
{
|
|
depName: 'com.squareup.picasso:picasso',
|
|
currentValue: '2.5.1',
|
|
managerData: {
|
|
fileReplacePosition: 244,
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
},
|
|
{
|
|
depName: 'com.squareup.retrofit2:retrofit',
|
|
groupName: 'retro.fit',
|
|
currentValue: '2.8.2',
|
|
managerData: {
|
|
fileReplacePosition: 42,
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
},
|
|
{
|
|
depName: 'google-firebase-analytics',
|
|
managerData: {
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
skipReason: 'unspecified-version',
|
|
},
|
|
{
|
|
depName: 'google-firebase-crashlytics',
|
|
managerData: {
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
skipReason: 'unspecified-version',
|
|
},
|
|
{
|
|
depName: 'google-firebase-messaging',
|
|
managerData: {
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
skipReason: 'unspecified-version',
|
|
},
|
|
{
|
|
depName: 'org.jetbrains.kotlin.jvm',
|
|
depType: 'plugin',
|
|
currentValue: '1.5.21',
|
|
commitMessageTopic: 'plugin kotlinJvm',
|
|
packageName:
|
|
'org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin',
|
|
managerData: {
|
|
fileReplacePosition: 663,
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
registryUrls: ['https://plugins.gradle.org/m2/'],
|
|
},
|
|
{
|
|
depName: 'org.jetbrains.kotlin.plugin.serialization',
|
|
depType: 'plugin',
|
|
currentValue: '1.5.21',
|
|
packageName:
|
|
'org.jetbrains.kotlin.plugin.serialization:org.jetbrains.kotlin.plugin.serialization.gradle.plugin',
|
|
managerData: {
|
|
fileReplacePosition: 21,
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
registryUrls: ['https://plugins.gradle.org/m2/'],
|
|
},
|
|
{
|
|
depName: 'org.danilopianini.multi-jvm-test-plugin',
|
|
depType: 'plugin',
|
|
currentValue: '0.3.0',
|
|
commitMessageTopic: 'plugin multiJvm',
|
|
packageName:
|
|
'org.danilopianini.multi-jvm-test-plugin:org.danilopianini.multi-jvm-test-plugin.gradle.plugin',
|
|
managerData: {
|
|
fileReplacePosition: 824,
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
registryUrls: ['https://plugins.gradle.org/m2/'],
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
});
|
|
|
|
it('ignores empty TOML file', async () => {
|
|
const fsMock = {
|
|
'gradle/libs.versions.toml': '',
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
expect(
|
|
await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
),
|
|
).toBeNull();
|
|
});
|
|
|
|
it('deletes commit message for plugins with version reference', async () => {
|
|
const fsMock = {
|
|
'gradle/libs.versions.toml': stripIndent`
|
|
[versions]
|
|
detekt = "1.18.1"
|
|
|
|
[plugins]
|
|
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
|
|
|
|
[libraries]
|
|
detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" }
|
|
`,
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
const res = await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
);
|
|
expect(res).toMatchObject([
|
|
{
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
deps: [
|
|
{
|
|
depName: 'io.gitlab.arturbosch.detekt:detekt-formatting',
|
|
groupName: 'detekt',
|
|
currentValue: '1.18.1',
|
|
managerData: {
|
|
fileReplacePosition: 21,
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
fileReplacePosition: 21,
|
|
},
|
|
{
|
|
depType: 'plugin',
|
|
depName: 'io.gitlab.arturbosch.detekt',
|
|
packageName:
|
|
'io.gitlab.arturbosch.detekt:io.gitlab.arturbosch.detekt.gradle.plugin',
|
|
registryUrls: ['https://plugins.gradle.org/m2/'],
|
|
currentValue: '1.18.1',
|
|
managerData: {
|
|
fileReplacePosition: 21,
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
groupName: 'detekt',
|
|
fileReplacePosition: 21,
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
});
|
|
|
|
it('changes the dependency version, not the comment version', async () => {
|
|
const fsMock = {
|
|
'gradle/libs.versions.toml': Fixtures.get('3/libs.versions.toml'),
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
const res = await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
);
|
|
expect(res).toMatchObject([
|
|
{
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
deps: [
|
|
{
|
|
depName: 'junit:junit',
|
|
groupName: 'junit',
|
|
currentValue: '1.4.9',
|
|
managerData: {
|
|
fileReplacePosition: 124,
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
fileReplacePosition: 124,
|
|
},
|
|
{
|
|
depName: 'mocha-junit:mocha-junit',
|
|
groupName: 'mocha.junit.reporter',
|
|
currentValue: '2.0.2',
|
|
managerData: {
|
|
fileReplacePosition: 82,
|
|
packageFile: 'gradle/libs.versions.toml',
|
|
},
|
|
fileReplacePosition: 82,
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe('apply from', () => {
|
|
it('loads further scripts using apply from statements', async () => {
|
|
const buildFile = codeBlock`
|
|
buildscript {
|
|
repositories {
|
|
mavenCentral()
|
|
}
|
|
|
|
apply from: "\${someDir}/libs1.gradle"
|
|
apply from: file("gradle/libs2.gradle")
|
|
apply from: "gradle/libs3.gradle"
|
|
apply from: new File(someDir, "\${someDir}/libs4.gradle")
|
|
apply from: file("gradle/non-existing.gradle")
|
|
|
|
dependencies {
|
|
classpath "com.google.protobuf:protobuf-java:\${protoBufVersion}"
|
|
classpath "com.google.guava:guava:\${guavaVersion}"
|
|
classpath "io.jsonwebtoken:jjwt-api:0.11.2"
|
|
|
|
classpath "org.junit.jupiter:junit-jupiter-api:\${junitVersion}"
|
|
classpath "org.junit.jupiter:junit-jupiter-engine:\${junitVersion}"
|
|
classpath "org.slf4j:slf4j-api:\${slf4jVersion}"
|
|
}
|
|
}
|
|
`;
|
|
|
|
const fsMock = {
|
|
'gradleX/libs1.gradle': "ext.junitVersion = '5.5.2'",
|
|
'gradle/libs2.gradle': "ext.protoBufVersion = '3.18.2'",
|
|
'gradle/libs3.gradle': "ext.guavaVersion = '30.1-jre'",
|
|
'gradleX/gradleX/libs4.gradle': "ext.slf4jVersion = '1.7.30'",
|
|
'build.gradle': buildFile,
|
|
'gradle.properties': 'someDir=gradleX',
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
const res = await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
);
|
|
|
|
expect(res).toMatchObject([
|
|
{ packageFile: 'gradle.properties' },
|
|
{
|
|
packageFile: 'build.gradle',
|
|
deps: [{ depName: 'io.jsonwebtoken:jjwt-api' }],
|
|
},
|
|
{
|
|
packageFile: 'gradle/libs2.gradle',
|
|
deps: [
|
|
{
|
|
depName: 'com.google.protobuf:protobuf-java',
|
|
currentValue: '3.18.2',
|
|
managerData: { packageFile: 'gradle/libs2.gradle' },
|
|
},
|
|
],
|
|
},
|
|
{
|
|
packageFile: 'gradle/libs3.gradle',
|
|
deps: [
|
|
{
|
|
depName: 'com.google.guava:guava',
|
|
currentValue: '30.1-jre',
|
|
managerData: { packageFile: 'gradle/libs3.gradle' },
|
|
},
|
|
],
|
|
},
|
|
{
|
|
packageFile: 'gradleX/libs1.gradle',
|
|
deps: [
|
|
{
|
|
depName: 'org.junit.jupiter:junit-jupiter-api',
|
|
currentValue: '5.5.2',
|
|
managerData: { packageFile: 'gradleX/libs1.gradle' },
|
|
},
|
|
{
|
|
depName: 'org.junit.jupiter:junit-jupiter-engine',
|
|
currentValue: '5.5.2',
|
|
managerData: { packageFile: 'gradleX/libs1.gradle' },
|
|
},
|
|
],
|
|
},
|
|
{
|
|
packageFile: 'gradleX/gradleX/libs4.gradle',
|
|
deps: [
|
|
{
|
|
depName: 'org.slf4j:slf4j-api',
|
|
currentValue: '1.7.30',
|
|
managerData: { packageFile: 'gradleX/gradleX/libs4.gradle' },
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
});
|
|
|
|
it('works with files in sub-directories', async () => {
|
|
const buildFile = `
|
|
buildscript {
|
|
repositories {
|
|
mavenCentral()
|
|
}
|
|
|
|
apply from: "gradle/libs4.gradle"
|
|
|
|
dependencies {
|
|
classpath "com.google.protobuf:protobuf-java:\${protoBufVersion}"
|
|
}
|
|
}
|
|
`;
|
|
|
|
const fsMock = {
|
|
'somesubdir/gradle/libs4.gradle': "ext.protoBufVersion = '3.18.2'",
|
|
'somesubdir/build.gradle': buildFile,
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
const res = await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
);
|
|
|
|
expect(res).toMatchObject([
|
|
{ packageFile: 'somesubdir/build.gradle' },
|
|
{
|
|
packageFile: 'somesubdir/gradle/libs4.gradle',
|
|
deps: [{ depName: 'com.google.protobuf:protobuf-java' }],
|
|
},
|
|
]);
|
|
});
|
|
|
|
it('prevents recursive apply from calls', async () => {
|
|
const fsMock = {
|
|
'build.gradle': "apply from: 'test.gradle'",
|
|
'test.gradle': "apply from: 'build.gradle'",
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
expect(
|
|
await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
),
|
|
).toBeNull();
|
|
});
|
|
|
|
it('prevents inclusion of non-Gradle files', async () => {
|
|
const fsMock = {
|
|
'build.gradle': "apply from: '../../test.non-gradle'",
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
expect(
|
|
await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
),
|
|
).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('gradle-consistent-versions plugin', () => {
|
|
it('parses versions files', async () => {
|
|
const fsMock = {
|
|
'versions.props': `org.apache.lucene:* = 1.2.3`,
|
|
'versions.lock': stripIndent`
|
|
# Run ./gradlew --write-locks to regenerate this file
|
|
org.apache.lucene:lucene-core:1.2.3 (10 constraints: 95be0c15)
|
|
org.apache.lucene:lucene-codecs:1.2.3 (5 constraints: 1231231)
|
|
`,
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
const res = await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
);
|
|
|
|
expect(res).toMatchObject([
|
|
{
|
|
packageFile: 'versions.lock',
|
|
},
|
|
{
|
|
packageFile: 'versions.props',
|
|
deps: [
|
|
{
|
|
depName: 'org.apache.lucene:lucene-core',
|
|
depType: 'dependencies',
|
|
fileReplacePosition: 22,
|
|
groupName: 'org.apache.lucene:*',
|
|
lockedVersion: '1.2.3',
|
|
managerData: {
|
|
fileReplacePosition: 22,
|
|
packageFile: 'versions.props',
|
|
},
|
|
},
|
|
{
|
|
depName: 'org.apache.lucene:lucene-codecs',
|
|
depType: 'dependencies',
|
|
fileReplacePosition: 22,
|
|
groupName: 'org.apache.lucene:*',
|
|
lockedVersion: '1.2.3',
|
|
managerData: {
|
|
fileReplacePosition: 22,
|
|
packageFile: 'versions.props',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
});
|
|
|
|
it('plugin not used due to lockfile not a GCV lockfile', async () => {
|
|
const fsMock = {
|
|
'versions.props': `org.apache.lucene:* = 1.2.3`,
|
|
'versions.lock': stripIndent`
|
|
This is NOT a lock file
|
|
`,
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
const res = await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
);
|
|
expect(res).toBeNull();
|
|
});
|
|
|
|
it('plugin not used due to lockfile missing', async () => {
|
|
const fsMock = {
|
|
'build.gradle': '(this file contains) com.palantir.consistent-versions',
|
|
'versions.props': `org.apache.lucene:* = 1.2.3`,
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
const res = await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
);
|
|
expect(res).toBeNull();
|
|
});
|
|
|
|
it('supports multiple levels of glob', async () => {
|
|
const fsMock = {
|
|
'versions.props': stripIndent`
|
|
org.apache.* = 4
|
|
org.apache.lucene:* = 3
|
|
org.apache.lucene:a.* = 2
|
|
org.apache.lucene:a.b = 1
|
|
org.apache.foo*:* = 5
|
|
`,
|
|
'versions.lock': stripIndent`
|
|
# Run ./gradlew --write-locks to regenerate this file
|
|
org.apache.solr:x.y:1 (10 constraints: 95be0c15)
|
|
org.apache.lucene:a.b:1 (10 constraints: 95be0c15)
|
|
org.apache.lucene:a.c:1 (10 constraints: 95be0c15)
|
|
org.apache.lucene:a.d:1 (10 constraints: 95be0c15)
|
|
org.apache.lucene:d:1 (10 constraints: 95be0c15)
|
|
org.apache.lucene:e.f:1 (10 constraints: 95be0c15)
|
|
org.apache.foo-bar:a:1 (10 constraints: 95be0c15)
|
|
`,
|
|
};
|
|
mockFs(fsMock);
|
|
|
|
const res = await extractAllPackageFiles(
|
|
partial<ExtractConfig>(),
|
|
Object.keys(fsMock),
|
|
);
|
|
|
|
// Each lock dep is only present once, with highest prio for exact prop match, then globs from longest to shortest
|
|
expect(res).toMatchObject([
|
|
{
|
|
packageFile: 'versions.lock',
|
|
deps: [],
|
|
},
|
|
{
|
|
packageFile: 'versions.props',
|
|
deps: [
|
|
{
|
|
managerData: {
|
|
packageFile: 'versions.props',
|
|
fileReplacePosition: 91,
|
|
},
|
|
depName: 'org.apache.lucene:a.b',
|
|
currentValue: '1',
|
|
lockedVersion: '1',
|
|
fileReplacePosition: 91,
|
|
depType: 'dependencies',
|
|
},
|
|
{
|
|
managerData: {
|
|
packageFile: 'versions.props',
|
|
fileReplacePosition: 65,
|
|
},
|
|
depName: 'org.apache.lucene:a.c',
|
|
currentValue: '2',
|
|
lockedVersion: '1',
|
|
groupName: 'org.apache.lucene:a.*',
|
|
fileReplacePosition: 65,
|
|
depType: 'dependencies',
|
|
},
|
|
{
|
|
managerData: {
|
|
packageFile: 'versions.props',
|
|
fileReplacePosition: 65,
|
|
},
|
|
depName: 'org.apache.lucene:a.d',
|
|
currentValue: '2',
|
|
lockedVersion: '1',
|
|
groupName: 'org.apache.lucene:a.*',
|
|
fileReplacePosition: 65,
|
|
depType: 'dependencies',
|
|
},
|
|
{
|
|
managerData: {
|
|
packageFile: 'versions.props',
|
|
fileReplacePosition: 39,
|
|
},
|
|
depName: 'org.apache.lucene:d',
|
|
currentValue: '3',
|
|
lockedVersion: '1',
|
|
groupName: 'org.apache.lucene:*',
|
|
fileReplacePosition: 39,
|
|
depType: 'dependencies',
|
|
},
|
|
{
|
|
managerData: {
|
|
packageFile: 'versions.props',
|
|
fileReplacePosition: 39,
|
|
},
|
|
depName: 'org.apache.lucene:e.f',
|
|
currentValue: '3',
|
|
lockedVersion: '1',
|
|
groupName: 'org.apache.lucene:*',
|
|
fileReplacePosition: 39,
|
|
depType: 'dependencies',
|
|
},
|
|
{
|
|
managerData: {
|
|
fileReplacePosition: 113,
|
|
packageFile: 'versions.props',
|
|
},
|
|
depName: 'org.apache.foo-bar:a',
|
|
currentValue: '5',
|
|
lockedVersion: '1',
|
|
groupName: 'org.apache.foo*:*',
|
|
fileReplacePosition: 113,
|
|
depType: 'dependencies',
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
});
|