Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce a Gradle inspector #6782

Merged
merged 5 commits into from
Apr 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion analyzer/src/main/kotlin/PackageManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ abstract class PackageManager(
*/
fun findManagedFiles(
directory: File,
packageManagers: Collection<PackageManagerFactory> = ALL.values,
packageManagers: Collection<PackageManagerFactory> = ENABLED_BY_DEFAULT,
excludes: Excludes = Excludes.EMPTY
): ManagedProjectFiles {
require(directory.isDirectory) {
Expand Down
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ log4jApiToSlf4j = { module = "org.apache.logging.log4j:log4j-to-slf4j", version.
logbackClassic = { module = "ch.qos.logback:logback-classic", version.ref = "logback" }
mavenCompat = { module = "org.apache.maven:maven-compat", version.ref = "maven" }
mavenCore = { module = "org.apache.maven:maven-core", version.ref = "maven" }
mavenModel = { module = "org.apache.maven:maven-model", version.ref = "maven" }
mavenModelBuilder = { module = "org.apache.maven:maven-model-builder", version.ref = "maven" }
mavenResolverApi = { module = "org.apache.maven.resolver:maven-resolver-api", version.ref = "mavenResolver" }
mavenResolverConnectorBasic = { module = "org.apache.maven.resolver:maven-resolver-connector-basic", version.ref = "mavenResolver" }
mavenResolverTransportFile = { module = "org.apache.maven.resolver:maven-resolver-transport-file", version.ref = "mavenResolver" }
Expand Down
1 change: 1 addition & 0 deletions plugins/package-managers/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ dependencies {
api(project(":plugins:package-managers:cocoapods-package-manager"))
api(project(":plugins:package-managers:composer-package-manager"))
api(project(":plugins:package-managers:conan-package-manager"))
api(project(":plugins:package-managers:gradle-inspector"))
api(project(":plugins:package-managers:gradle-model"))
api(project(":plugins:package-managers:gradle-package-manager"))
api(project(":plugins:package-managers:pub-package-manager"))
Expand Down
57 changes: 57 additions & 0 deletions plugins/package-managers/gradle-inspector/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# GradleInspector

The [GradleInspector] is an alternative analyzer for projects that use the Gradle package manager. It is supposed to
fviernau marked this conversation as resolved.
Show resolved Hide resolved
address [several][] [shortcomings][] of the "legacy" [Gradle] analyzer, but in order to not interfere with it, the
mnonnenmacher marked this conversation as resolved.
Show resolved Hide resolved
[GradleInspector] is disabled by default.

## Usage

As the [GradleInspector] is disabled by default, it needs to be enabled explicitly (along with any other package
managers that should be enabled):

ort analyze -P ort.analyzer.enabledPackageManagers=GradleInspector[,...]

It is recommended to *not* also enable the "legacy" [Gradle] analyzer at the same time, as both analyzers would find the
same definition files.

## Implementation

In contrast to the "legacy" [Gradle] analyzer which is fully implemented as an [initialization script], the
[GradleInspector] only uses a minimal [init.gradle] to apply a [Gradle plugin], which in turn does nothing else than
registering the [OrtModelBuilder] for the ORT-specific [data model for Gradle projects]. The [GradleInspector] then
injects both the [init.gradle] and a fat-JAR for the [Gradle plugin] into the project to analyze.

## Limitations

The retrieval of the checksum values for remote artifacts is currently done via plain OkHttp calls, which means it will
not work out of the box for private repositories. To worka round this, crednetials need to be configured in `.netrc`
fviernau marked this conversation as resolved.
Show resolved Hide resolved
additionally to in Gradle. This is similar to how the "legacy" [Gradle] analyzer required to additionally configure
fviernau marked this conversation as resolved.
Show resolved Hide resolved
credentials in Maven.

Also, the `isModified` check which compares with artifacts of the same name in Maven Central is not implemented yet.

## Building

Due to some optimizations IntelliJ IDEA performs when building Gradle projects, it might be that bundling the fat-JAR
for the [Gradle plugin] as a resource into the [GradleInspector] does not always work reliably. In that case ensure that
IntelliJ IDEA has "Gradle" configured for the "Build and run using" and "Run tests using" settings, and / or try to
run the `:plugins:package-managers:gradle-plugin:fatJar` and `:plugins:package-managers:gradle-inspector:jar` tasks
manually once.

## Debugging

Due to this setup of the [GradleInspector], the [OrtModelBuilder] can actually be debugged. To do so, create a run
configuration in IntelliJ IDEA that runs `ort analyze` and sets the *VM options* to `-Dorg.gradle.debug=true`. Also,
create another *Remote JVm Debug* run configuration with default settings. Now, when debugging the first run
configuration, it will block execution of the Gradle plugin until the remote debugger is attached by debugging the
second run configuration, and any breakpoints in the [OrtModelBuilder] will be hit.

[GradleInspector]: ./src/main/kotlin/GradleInspector.kt
[several]: https://github.com/oss-review-toolkit/ort/issues/4694
[shortcomings]: https://github.com/oss-review-toolkit/ort/issues/5782
[Gradle]: ../gradle/src/main/kotlin/Gradle.kt
[initialization script]: https://docs.gradle.org/current/userguide/init_scripts.html
[init.gradle]: ./src/main/resources/init.gradle.template
[Gradle plugin]: ../gradle-plugin/src/main/kotlin/OrtModelPlugin.kt
[OrtModelBuilder]: ../gradle-plugin/src/main/kotlin/OrtModelBuilder.kt
[data model for Gradle projects]: ../gradle-model/src/main/kotlin/GradleModel.kt
79 changes: 79 additions & 0 deletions plugins/package-managers/gradle-inspector/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (C) 2023 The ORT Project Authors (see <https://github.com/oss-review-toolkit/ort/blob/main/NOTICE>)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* License-Filename: LICENSE
*/

import org.jetbrains.gradle.ext.settings
import org.jetbrains.gradle.ext.taskTriggers

@Suppress("DSL_SCOPE_VIOLATION") // See https://youtrack.jetbrains.com/issue/KTIJ-19369.
plugins {
// Apply core plugins.
`java-library`

// Apply third-party plugins.
alias(libs.plugins.ideaExt)
}

repositories {
exclusiveContent {
forRepository {
maven("https://repo.gradle.org/gradle/libs-releases/")
}

filter {
includeGroup("org.gradle")
}
}
}

dependencies {
api(project(":analyzer"))
api(project(":model"))

implementation(project(":downloader"))
implementation(project(":plugins:package-managers:gradle-model"))
implementation(project(":utils:common-utils"))
implementation(project(":utils:ort-utils"))
implementation(project(":utils:spdx-utils"))

// Use the latest version that is not affected by https://github.com/gradle/gradle/issues/23208.
implementation("org.gradle:gradle-tooling-api:7.4.2")

implementation(libs.log4jApi)
implementation(libs.log4jApiKotlin)

funTestImplementation(testFixtures(project(":analyzer")))
}

val processResources = tasks.named<Copy>("processResources").configure {
val gradlePluginProject = project(":plugins:package-managers:gradle-plugin")
val gradlePluginJarTask = gradlePluginProject.tasks.named<Jar>("fatJar")
val gradlePluginJarFile = gradlePluginJarTask.get().outputs.files.singleFile

// As the Copy-task simply skips non-existing files, add explicit dependencies on the Jar-tasks.
dependsOn(gradlePluginJarTask)

// Bundle the plugin JAR as a resource so the inspector can copy it at runtime to the init script's classpath.
from(gradlePluginJarFile)

// Ensure a constant file name without a version suffix.
rename(gradlePluginJarFile.name, "gradle-plugin.jar")
}

// Work around https://youtrack.jetbrains.com/issue/IDEA-173367.
rootProject.idea.project.settings.taskTriggers.beforeBuild(processResources)
Loading