Skip to content
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
12 changes: 12 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,18 @@ gradlePlugin {
}
}
}
create("com.netflix.nebula.locks") {
id = "com.netflix.nebula.locks"
displayName = "Nebula Dependency Locks Plugin"
description = "opinionated dependency locking for nebula projects"
implementationClass = "com.netflix.nebula.convention.DependencyLockingPlugin"
tags.set(listOf("nebula"))
compatibility {
features {
configurationCache = true
}
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import javax.inject.Inject
@NullMarked
class NebulaLibraryPlugin implements Plugin<Project> {
static final NEBULA_PLUGIN_IDS = ['com.netflix.nebula.contacts',
'com.netflix.nebula.dependency-lock',
'com.netflix.nebula.info',
'com.netflix.nebula.javadoc-jar',
'com.netflix.nebula.maven-apache-license',
Expand Down
20 changes: 18 additions & 2 deletions src/main/groovy/nebula/plugin/plugin/NebulaPluginPlugin.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,16 @@ import nebula.plugin.publishing.NebulaOssPublishingExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.problems.Problem
import org.gradle.api.problems.ProblemId
import org.gradle.api.problems.Problems
import org.gradle.api.problems.Severity
import org.gradle.api.provider.Provider
import org.gradle.api.provider.ProviderFactory
import org.gradle.api.publish.maven.tasks.PublishToMavenRepository
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.testing.Test
import org.gradle.internal.deprecation.DeprecationLogger
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.jvm.toolchain.JavaToolchainService
import org.gradle.jvm.toolchain.JavaToolchainSpec
Expand All @@ -46,7 +51,6 @@ class NebulaPluginPlugin implements Plugin<Project> {
'java-gradle-plugin']

static final NEBULA_PLUGIN_IDS = ['com.netflix.nebula.contacts',
'com.netflix.nebula.dependency-lock',
'com.netflix.nebula.info',
'com.netflix.nebula.javadoc-jar',
'com.netflix.nebula.maven-apache-license',
Expand All @@ -61,17 +65,29 @@ class NebulaPluginPlugin implements Plugin<Project> {
static final PLUGIN_IDS = GRADLE_PLUGIN_IDS + NEBULA_PLUGIN_IDS

private final ProviderFactory providers
private final Problems problems
private boolean isPluginPublishingValidation

@Inject
NebulaPluginPlugin(ProviderFactory providerFactory) {
NebulaPluginPlugin(ProviderFactory providerFactory,Problems problems) {
this.providers = providerFactory
this.problems = problems
}

@Override
void apply(Project project) {
project.group = 'com.netflix.nebula'

project.afterEvaluate {
if(!project.pluginManager.hasPlugin("com.netflix.nebula.locks")){
Problem problem = problems.reporter.create(NebulaProblems.OSS_SETTINGS) {
it.details("locking convention is not found. using com.netflix.nebula.plugin-plugin without the oss.settings plugin is deprecated")
it.solution("apply the 'com.netflix.nebula.oss.settings' plugin in settings.gradle.kts")
}
problems.reporter.report(problem)
project.pluginManager.apply("com.netflix.nebula.dependency-lock")
}
}
this.isPluginPublishingValidation = project.gradle.startParameter.taskNames.contains('--validate-only')
project.plugins.withId("com.netflix.nebula.oss-publishing") {
NebulaOssPublishingExtension ossPublishingExt = project.rootProject.extensions.findByType(NebulaOssPublishingExtension)
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/nebula/plugin/plugin/NebulaProblems.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package nebula.plugin.plugin;

import org.gradle.api.problems.ProblemGroup;
import org.gradle.api.problems.ProblemId;

/**
* Constants for Problem reporting
*/
public class NebulaProblems {
public static final ProblemGroup NEBULA_GROUP =

Check warning on line 10 in src/main/java/nebula/plugin/plugin/NebulaProblems.java

View workflow job for this annotation

GitHub Actions / Gradle Build without Publish (17)

no comment

Check warning on line 10 in src/main/java/nebula/plugin/plugin/NebulaProblems.java

View workflow job for this annotation

GitHub Actions / Gradle Build without Publish (21)

no comment

Check warning on line 10 in src/main/java/nebula/plugin/plugin/NebulaProblems.java

View workflow job for this annotation

GitHub Actions / Gradle Build without Publish (25)

no comment
ProblemGroup.create("com.netflix.nebula", "Nebula Plugins");

public static final ProblemId OSS_SETTINGS = ProblemId.create(

Check warning on line 13 in src/main/java/nebula/plugin/plugin/NebulaProblems.java

View workflow job for this annotation

GitHub Actions / Gradle Build without Publish (17)

no comment

Check warning on line 13 in src/main/java/nebula/plugin/plugin/NebulaProblems.java

View workflow job for this annotation

GitHub Actions / Gradle Build without Publish (21)

no comment

Check warning on line 13 in src/main/java/nebula/plugin/plugin/NebulaProblems.java

View workflow job for this annotation

GitHub Actions / Gradle Build without Publish (25)

no comment
"com.netflix.nebula.oss.settings not found",
"using a nebula convention plugin without com.netflix.nebula.oss.settings is deprecated",
NEBULA_GROUP);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.netflix.nebula.convention

import org.gradle.api.Plugin
import org.gradle.api.Project

/**
* Highly opinionated lockign setup for nebula projects.
* Used over the "com.netflix.nebula.dependency-lock" plugin since we don't need its extra options,
* and that plugin adds significant configuration time
*/
class DependencyLockingPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.dependencyLocking {
lockAllConfigurations()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class NebulaSettingsPlugin : Plugin<Settings> {
}
settings.gradle.allprojects {
pluginManager.apply("com.netflix.nebula.resolve")
pluginManager.apply("com.netflix.nebula.locks")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.netflix.nebula.convention

import com.netflix.nebula.SupportedGradleVersion
import nebula.test.dsl.*
import nebula.test.dsl.TestKitAssertions.assertThat
import org.gradle.testkit.runner.TaskOutcome
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.EnumSource
import java.io.File

class DependencyLockingPluginTest {
@TempDir
lateinit var projectDir: File

@ParameterizedTest
@EnumSource(SupportedGradleVersion::class)
fun `test multiproject no root`(gradle: SupportedGradleVersion) {
val runner = testProject(projectDir) {
properties {
buildCache(true)
configurationCache(true)
}
subProject("sub1") {
plugins {
java()
id("com.netflix.nebula.locks")
}
repositories{
mavenCentral()
}
dependencies("""implementation("org.slf4j:slf4j-api:2.0.18")""")
}
}
val result = runner.run(":sub1:dependencies", "--write-locks"){
withGradle(gradle.version)
}
assertThat(result)
.hasNoProblemsReport()
.hasNoMutableStateWarnings()
.hasNoDeprecationWarnings()
val lockFile = projectDir.resolve("sub1/gradle.lockfile")
assertThat(lockFile)
.exists()
.content()
.contains("org.slf4j:slf4j-api")
.contains("compileClasspath")
.contains("runtimeClasspath")
.contains("testCompileClasspath")
.contains("testRuntimeClasspath")
.contains("empty=annotationProcessor,testAnnotationProcessor")
}

@Test
fun `test archrules integration`() {
val runner = testProject(projectDir) {
properties {
buildCache(true)
configurationCache(true)
}
subProject("sub1") {
plugins {
java()
id("com.netflix.nebula.archrules.runner")
id("com.netflix.nebula.locks")
}
repositories{
mavenCentral()
}
dependencies(
"""implementation("org.slf4j:slf4j-api:2.0.18")""",
"""archRules("com.netflix.nebula:archrules-deprecation:1.0.2")"""
)
}
}
val result = runner.run(":sub1:dependencies", "--write-locks")
assertThat(result)
.hasNoProblemsReport()
.hasNoMutableStateWarnings()
.hasNoDeprecationWarnings()
val lockFile = projectDir.resolve("sub1/gradle.lockfile")
assertThat(lockFile)
.exists()
.content()
.contains("org.slf4j:slf4j-api")
.contains("mainArchRulesRuntime")
.contains("testArchRulesRuntime")
.contains("com.netflix.nebula:archrules-deprecation:1.0.2=archRules,mainArchRulesRuntime,testArchRulesRuntime")
.contains("empty=annotationProcessor,testAnnotationProcessor")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,45 @@ class NebulaSettingsPluginTest {
assertThat(result.task(":sub2:dependencies")).hasOutcome(TaskOutcome.SUCCESS)
assertThat(result.task(":resolve")).hasOutcome(TaskOutcome.SUCCESS)
}

@ParameterizedTest
@EnumSource(SupportedGradleVersion::class)
fun `test locking multiproject`(gradle: SupportedGradleVersion) {
val runner = testProject(projectDir) {
properties {
buildCache(true)
configurationCache(true)
}
settings {
plugins {
id("com.netflix.nebula.oss.settings")
}
}
subProject("sub1"){
plugins {
java()
}
}
subProject("sub2"){
plugins {
java()
}
}
}
val result = runner.run("resolve", "--write-locks") {
withGradle(gradle.version)
}
assertThat(result)
.hasNoProblemsReport()
.hasNoMutableStateWarnings()
.hasNoDeprecationWarnings()
assertThat(projectDir.resolve("sub1/gradle.lockfile"))
.exists()
.content()
.contains("empty=annotationProcessor,compileClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath")
assertThat(projectDir.resolve("sub2/gradle.lockfile"))
.exists()
.content()
.contains("empty=annotationProcessor,compileClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath")
}
}
58 changes: 52 additions & 6 deletions src/test/kotlin/nebula/plugin/plugin/NebulaPluginPluginTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,13 @@ internal class NebulaPluginPluginTest {
artifactory.stop()
}

private fun TestProjectBuilder.sampleSinglePluginSetup() {
private fun TestProjectBuilder.sampleSinglePluginSetup(config: ProjectBuilder.() -> Unit = {
src {
main {
java("example/MyPlugin.java", SAMPLE_JAVA_PLUGIN)
}
}
}) {
properties {
configurationCache(true)
buildCache(true)
Expand Down Expand Up @@ -73,11 +79,7 @@ gradlePlugin {
}
"""
)
src {
main {
java("example/MyPlugin.java", SAMPLE_JAVA_PLUGIN)
}
}
config()
}
}

Expand All @@ -93,6 +95,29 @@ gradlePlugin {
.`as`("integTest facet enabled by default")
.hasOutcome(TaskOutcome.NO_SOURCE)

assertThat(result)
.hasNoDeprecationWarnings()
.hasNoMutableStateWarnings()

assertThat(result.output)
.contains("Problem found: using a nebula convention plugin without com.netflix.nebula.oss.settings is deprecated")
.contains("Problems report is available at:")
}

@Test
fun `test archrules integration`() {
val runner = testProject(projectDir) {
sampleSinglePluginSetup{
src {
main {
java("example/MyPlugin.java", SAMPLE_JAVA_PLUGIN_WITH_ARCHRULES_FAILURE)
}
}
}
}

val result = runner.run("check", "--stacktrace")

assertThat(result)
.hasNoDeprecationWarnings()
.hasNoMutableStateWarnings()
Expand All @@ -102,6 +127,27 @@ gradlePlugin {
.hasOutcome(TaskOutcome.SUCCESS)
assertThat(result.output)
.contains("Rule: ")
assertThat(result.output)
.contains("Problem found:")
.contains("Problems report is available at:")
}

@Test
fun `test setup with settings plugin`() {
val runner = testProject(projectDir) {
settings{
plugins {
id("com.netflix.nebula.oss.settings")
}
}
sampleSinglePluginSetup()
}

val result = runner.run("check", "--stacktrace")
assertThat(result)
.hasNoProblemsReport()
.hasNoDeprecationWarnings()
.hasNoMutableStateWarnings()
}

@Test
Expand Down
21 changes: 20 additions & 1 deletion src/test/kotlin/nebula/plugin/plugin/SampleCode.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package nebula.plugin.plugin

//language=java
const val SAMPLE_JAVA_PLUGIN: String = """
const val SAMPLE_JAVA_PLUGIN_WITH_ARCHRULES_FAILURE: String = """
package example;

import org.gradle.api.Plugin;
Expand All @@ -18,6 +18,25 @@ public class MyPlugin implements Plugin<@NonNull Project> {
}
"""

//language=java
const val SAMPLE_JAVA_PLUGIN: String = """
package example;

import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.jspecify.annotations.NullMarked;

/**
*
*/
@NullMarked
public class MyPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
}
}
"""

//language=java
const val SAMPLE_JAVA_MAIN_CLASS: String = """
package example;
Expand Down