From f9ba76e8516906358365d7fafa5fdb720c987f46 Mon Sep 17 00:00:00 2001 From: Ruben Sousa Date: Fri, 6 Mar 2026 00:42:46 +0100 Subject: [PATCH 1/3] Add option to attach plugin to lifecycle tasks of gradle --- .../projectguard/plugin/LifecycleTask.kt | 22 ++++++++++++++++ .../projectguard/plugin/OptionScope.kt | 25 ++++++++++++++++++ .../plugin/ProjectGuardExtension.kt | 16 +++++++++++- .../projectguard/plugin/ProjectGuardScope.kt | 6 +++++ .../plugin/internal/OptionScopeImpl.kt | 26 +++++++++++++++++++ .../plugin/internal/PluginOptions.kt | 24 +++++++++++++++++ .../plugin/internal/ProjectGuardSpec.kt | 1 + .../plugin/ProjectGuardExtensionTest.kt | 25 ++++++++++++++++++ 8 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/LifecycleTask.kt create mode 100644 projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/OptionScope.kt create mode 100644 projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/internal/OptionScopeImpl.kt create mode 100644 projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/internal/PluginOptions.kt diff --git a/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/LifecycleTask.kt b/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/LifecycleTask.kt new file mode 100644 index 0000000..0242cce --- /dev/null +++ b/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/LifecycleTask.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2026 Rúben Sousa + * + * 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 + * + * http://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. + */ + +package com.rubensousa.projectguard.plugin + +enum class LifecycleTask { + ASSEMBLE, + CHECK +} diff --git a/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/OptionScope.kt b/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/OptionScope.kt new file mode 100644 index 0000000..9f7d42e --- /dev/null +++ b/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/OptionScope.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2026 Rúben Sousa + * + * 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 + * + * http://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. + */ + +package com.rubensousa.projectguard.plugin + +interface OptionScope { + /** + * `projectGuardCheck` will be included in either [LifecycleTask.CHECK], [LifecycleTask.ASSEMBLE] + * or none if null + */ + var lifecycleTask: LifecycleTask? +} diff --git a/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/ProjectGuardExtension.kt b/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/ProjectGuardExtension.kt index bbccb21..a2ba652 100644 --- a/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/ProjectGuardExtension.kt +++ b/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/ProjectGuardExtension.kt @@ -22,6 +22,8 @@ import com.rubensousa.projectguard.plugin.internal.GuardScopeImpl import com.rubensousa.projectguard.plugin.internal.GuardSpec import com.rubensousa.projectguard.plugin.internal.ModuleRestrictionScopeImpl import com.rubensousa.projectguard.plugin.internal.ModuleRestrictionSpec +import com.rubensousa.projectguard.plugin.internal.OptionScopeImpl +import com.rubensousa.projectguard.plugin.internal.PluginOptions import com.rubensousa.projectguard.plugin.internal.ProjectGuardSpec import com.rubensousa.projectguard.plugin.internal.ReportScopeImpl import com.rubensousa.projectguard.plugin.internal.ReportSpec @@ -41,6 +43,9 @@ abstract class ProjectGuardExtension @Inject constructor( private val moduleRestrictionSpecs = objects.listProperty() private val dependencyRestrictionSpecs = objects.listProperty() private var reportSpec = ReportSpec(showLibrariesInGraph = false) + private var options = PluginOptions( + lifecycleTask = null + ) override fun restrictModule(modulePath: String, action: Action) { val scope = ModuleRestrictionScopeImpl() @@ -127,12 +132,21 @@ abstract class ProjectGuardExtension @Inject constructor( ) } + override fun options(action: Action) { + val scope = OptionScopeImpl() + action.execute(scope) + options = options.copy( + lifecycleTask = scope.lifecycleTask, + ) + } + internal fun getSpec(): ProjectGuardSpec { return ProjectGuardSpec( guardSpecs = guardSpecs.get(), moduleRestrictionSpecs = moduleRestrictionSpecs.get(), dependencyRestrictionSpecs = dependencyRestrictionSpecs.get(), - reportSpec = reportSpec + reportSpec = reportSpec, + options = options ) } diff --git a/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/ProjectGuardScope.kt b/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/ProjectGuardScope.kt index 403b55f..40a9d2e 100644 --- a/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/ProjectGuardScope.kt +++ b/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/ProjectGuardScope.kt @@ -207,4 +207,10 @@ interface ProjectGuardScope { report(ConfigureUtil.configureUsing(closure)) } + fun options(action: Action) + + fun options(closure: Closure) { + options(ConfigureUtil.configureUsing(closure)) + } + } diff --git a/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/internal/OptionScopeImpl.kt b/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/internal/OptionScopeImpl.kt new file mode 100644 index 0000000..d26c153 --- /dev/null +++ b/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/internal/OptionScopeImpl.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2026 Rúben Sousa + * + * 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 + * + * http://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. + */ + +package com.rubensousa.projectguard.plugin.internal + +import com.rubensousa.projectguard.plugin.LifecycleTask +import com.rubensousa.projectguard.plugin.OptionScope + +internal class OptionScopeImpl : OptionScope { + + override var lifecycleTask: LifecycleTask? = null + +} diff --git a/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/internal/PluginOptions.kt b/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/internal/PluginOptions.kt new file mode 100644 index 0000000..f409d5c --- /dev/null +++ b/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/internal/PluginOptions.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2026 Rúben Sousa + * + * 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 + * + * http://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. + */ + +package com.rubensousa.projectguard.plugin.internal + +import com.rubensousa.projectguard.plugin.LifecycleTask +import java.io.Serializable + +internal data class PluginOptions( + val lifecycleTask: LifecycleTask? +): Serializable diff --git a/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/internal/ProjectGuardSpec.kt b/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/internal/ProjectGuardSpec.kt index 09cb01c..5420da2 100644 --- a/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/internal/ProjectGuardSpec.kt +++ b/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/internal/ProjectGuardSpec.kt @@ -23,4 +23,5 @@ internal data class ProjectGuardSpec( val moduleRestrictionSpecs: List, val dependencyRestrictionSpecs: List, val reportSpec: ReportSpec, + val options: PluginOptions, ) : Serializable diff --git a/projectguard/src/test/kotlin/com/rubensousa/projectguard/plugin/ProjectGuardExtensionTest.kt b/projectguard/src/test/kotlin/com/rubensousa/projectguard/plugin/ProjectGuardExtensionTest.kt index 5e5a8d2..7ee47ae 100644 --- a/projectguard/src/test/kotlin/com/rubensousa/projectguard/plugin/ProjectGuardExtensionTest.kt +++ b/projectguard/src/test/kotlin/com/rubensousa/projectguard/plugin/ProjectGuardExtensionTest.kt @@ -208,6 +208,31 @@ class ProjectGuardExtensionTest { assertThat(spec.reportSpec.showLibrariesInGraph).isTrue() } + @Test + fun `lifecycle task is null by default`() { + // given + val extension = createExtension() + + // then + val spec = extension.getSpec() + assertThat(spec.options.lifecycleTask).isNull() + } + + @Test + fun `lifecycle task can be enabled`() { + // given + val extension = createExtension() + + // when + extension.options { + lifecycleTask = LifecycleTask.ASSEMBLE + } + + // then + val spec = extension.getSpec() + assertThat(spec.options.lifecycleTask).isEqualTo(LifecycleTask.ASSEMBLE) + } + private fun createExtension(): ProjectGuardExtension { val project = ProjectBuilder.builder().build() return project.extensions.create( From 8abeb2c6c3d39338374347ec506c5e0393351c89 Mon Sep 17 00:00:00 2001 From: Ruben Sousa Date: Fri, 6 Mar 2026 00:54:00 +0100 Subject: [PATCH 2/3] Attach check task to lifecycle tasks depending on configuration --- build.gradle.kts | 2 +- gradle.properties | 21 +------- gradle/libs.versions.toml | 3 +- projectguard/build.gradle.kts | 1 + .../projectguard/plugin/ProjectGuardPlugin.kt | 49 +++++++++++++++++ .../plugin/GroovyIntegrationTest.kt | 4 +- .../plugin/PluginIntegrationTest.kt | 53 +++++++++++++++++-- .../projectguard/plugin/PluginRunner.kt | 22 ++++++-- sample/build.gradle.kts | 11 +++- 9 files changed, 133 insertions(+), 33 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 591c155..2f581fb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - alias(libs.plugins.jetbrains.kotlin.jvm) apply false + alias(libs.plugins.kotlin.jvm) apply false alias(libs.plugins.kover) apply false alias(libs.plugins.maven.publish) apply false } diff --git a/gradle.properties b/gradle.properties index b6fddef..7ac32fe 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,25 +1,6 @@ -# Project-wide Gradle settings. -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. For more details, visit -# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects -# org.gradle.parallel=true -# AndroidX package structure to make it clearer which packages are bundled with the -# Android operating system, and which are packaged with your app's APK -# https://developer.android.com/topic/libraries/support-library/androidx-rn +org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8 -XX:MetaspaceSize=1g android.useAndroidX=true -# Kotlin code style for this project: "official" or "obsolete": kotlin.code.style=official -# Enables namespacing of each library's R class so that its R class includes only the -# resources declared in the library itself and none from the library's dependencies, -# thereby reducing the size of the R class for that library android.nonTransitiveRClass=true POM_NAME=ProjectGuard Plugin diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index daf611e..0685497 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -21,11 +21,12 @@ kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", versio runner = { group = "androidx.test", name = "runner", version.ref = "runner" } core = { group = "androidx.test", name = "core", version.ref = "core" } ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } +gradle-android = { group = "com.android.tools.build", name = "gradle", version.ref = "agp" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } -jetbrains-kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } +kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } maven-publish = { id = "com.vanniktech.maven.publish", version = "0.36.0" } projectguard = { id = "com.rubensousa.projectguard", version = "unspecified" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } diff --git a/projectguard/build.gradle.kts b/projectguard/build.gradle.kts index 0e87ceb..e66edcf 100644 --- a/projectguard/build.gradle.kts +++ b/projectguard/build.gradle.kts @@ -42,6 +42,7 @@ dependencies { implementation(libs.kotlin.serialization.json) implementation(libs.jackson.yaml) implementation(libs.jackson.kotlin) + implementation(libs.gradle.android) testImplementation(gradleTestKit()) testImplementation(libs.kotlin.test) testImplementation(libs.truth) diff --git a/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/ProjectGuardPlugin.kt b/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/ProjectGuardPlugin.kt index 28febf1..fe210a9 100644 --- a/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/ProjectGuardPlugin.kt +++ b/projectguard/src/main/kotlin/com/rubensousa/projectguard/plugin/ProjectGuardPlugin.kt @@ -16,6 +16,7 @@ package com.rubensousa.projectguard.plugin +import com.android.build.api.variant.AndroidComponentsExtension import com.rubensousa.projectguard.plugin.internal.DependencyGraphBuilder import com.rubensousa.projectguard.plugin.internal.task.TaskAggregateDependencyDump import com.rubensousa.projectguard.plugin.internal.task.TaskAggregateRestrictionDump @@ -53,6 +54,13 @@ class ProjectGuardPlugin : Plugin { private val dependenciesFilePath = "reports/$pluginId/dependencies.json" private val jsonReportFilePath = "reports/$pluginId/report.json" private val graphBuilder = DependencyGraphBuilder() + private val androidPluginIds = listOf( + "com.android.test", + "com.android.application", + "com.android.library", + "com.android.dynamic-feature", + "com.android.kotlin.multiplatform.library" + ) override fun apply(target: Project) { val rootProject = target.rootProject @@ -71,6 +79,8 @@ class ProjectGuardPlugin : Plugin { individualModuleTasks.add(moduleTasks) setupModuleTasks( aggregationTasks = aggregationTasks, + project = targetProject, + extension = extension, moduleTasks = moduleTasks ) } @@ -93,6 +103,8 @@ class ProjectGuardPlugin : Plugin { } private fun setupModuleTasks( + project: Project, + extension: ProjectGuardExtension, aggregationTasks: AggregationTasks, moduleTasks: ModuleTasks, ) { @@ -109,6 +121,43 @@ class ProjectGuardPlugin : Plugin { outputDir.set(project.layout.buildDirectory.dir(htmlAggregateReportFilePath)) reportFilePath.set(getProjectReportFilePath(project)) } + + project.afterEvaluate { + val options = extension.getSpec().options + options.lifecycleTask?.let { lifecycleTask -> + if (lifecycleTask == LifecycleTask.ASSEMBLE) { + attachToAndroidAssembleTasks(project, moduleTasks.check) + project.tasks.findByName("assemble")?.dependsOn(moduleTasks.check) + } else { + project.tasks.findByName("check")?.dependsOn(moduleTasks.check) + } + } + } + } + + private fun attachToAndroidAssembleTasks( + project: Project, + checkTask: TaskProvider, + ) { + androidPluginIds.forEach { pluginId -> + if (project.plugins.hasPlugin(pluginId)) { + val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java) + val variantTasks = mutableListOf() + androidComponents.onVariants { variant -> + val variantName = capitalizeVariantName(variant.name) + variantTasks.add("assemble$variantName") + } + project.afterEvaluate { + variantTasks.forEach { variantTask -> + project.tasks.findByName(variantTask)?.dependsOn(checkTask) + } + } + } + } + } + + private fun capitalizeVariantName(name: String): String { + return name.substring(0, 1).uppercase() + name.substring(1, name.length) } private fun setupAggregationTasks( diff --git a/projectguard/src/test/kotlin/com/rubensousa/projectguard/plugin/GroovyIntegrationTest.kt b/projectguard/src/test/kotlin/com/rubensousa/projectguard/plugin/GroovyIntegrationTest.kt index 666554d..14dc593 100644 --- a/projectguard/src/test/kotlin/com/rubensousa/projectguard/plugin/GroovyIntegrationTest.kt +++ b/projectguard/src/test/kotlin/com/rubensousa/projectguard/plugin/GroovyIntegrationTest.kt @@ -71,7 +71,7 @@ class GroovyIntegrationTest { pluginRunner.addDependency(from = module, to = dependency) // then - pluginRunner.assertCheckFails(module) + pluginRunner.assertProjectGuardCheckFails(module) pluginRunner.assertTaskOutputContains(reason) } @@ -96,7 +96,7 @@ class GroovyIntegrationTest { pluginRunner.addDependency(from = module, to = dependency) // then - pluginRunner.assertCheckSucceeds(module) + pluginRunner.assertProjectGuardCheckSucceeds(module) pluginRunner.assertTaskOutputContains("No fatal matches found") } diff --git a/projectguard/src/test/kotlin/com/rubensousa/projectguard/plugin/PluginIntegrationTest.kt b/projectguard/src/test/kotlin/com/rubensousa/projectguard/plugin/PluginIntegrationTest.kt index 0f403eb..10a6496 100644 --- a/projectguard/src/test/kotlin/com/rubensousa/projectguard/plugin/PluginIntegrationTest.kt +++ b/projectguard/src/test/kotlin/com/rubensousa/projectguard/plugin/PluginIntegrationTest.kt @@ -35,6 +35,7 @@ class PluginIntegrationTest { rootBuildFile = temporaryFolder.newFile("build.gradle.kts") rootBuildFile.writeText( """ + import com.rubensousa.projectguard.plugin.LifecycleTask plugins { id("com.rubensousa.projectguard") apply true } @@ -69,7 +70,7 @@ class PluginIntegrationTest { pluginRunner.addDependency(from = "libraryA", to = "libraryB") // then - pluginRunner.assertCheckFails("consumer") + pluginRunner.assertProjectGuardCheckFails("consumer") } @Test @@ -90,7 +91,7 @@ class PluginIntegrationTest { pluginRunner.addDependency(from = "consumer", to = "library") // then - pluginRunner.assertCheckFails("consumer") + pluginRunner.assertProjectGuardCheckFails("consumer") } @Test @@ -111,7 +112,53 @@ class PluginIntegrationTest { pluginRunner.addDependency(from = "consumer", to = "library") // then - pluginRunner.assertCheckSucceeds("consumer") + pluginRunner.assertProjectGuardCheckSucceeds("consumer") + } + + @Test + fun `assemble fails if there are restrictions and plugin is configured to attach to lifecycle task`() { + pluginRunner.createModule("consumer") + pluginRunner.createModule("library") + + rootBuildFile.appendText( + """ + projectGuard { + options { + lifecycleTask = LifecycleTask.ASSEMBLE + } + restrictDependency(":library") + } + """.trimIndent() + ) + + // when + pluginRunner.addDependency(from = "consumer", to = "library") + + // then + pluginRunner.assertAssembleTaskFails("consumer") + } + + @Test + fun `check fails if there are restrictions and plugin is configured to attach to lifecycle task`() { + pluginRunner.createModule("consumer") + pluginRunner.createModule("library") + + rootBuildFile.appendText( + """ + projectGuard { + options { + lifecycleTask = LifecycleTask.CHECK + } + restrictDependency(":library") + } + """.trimIndent() + ) + + // when + pluginRunner.addDependency(from = "consumer", to = "library") + + // then + pluginRunner.assertCheckTaskFails("consumer") } } diff --git a/projectguard/src/test/kotlin/com/rubensousa/projectguard/plugin/PluginRunner.kt b/projectguard/src/test/kotlin/com/rubensousa/projectguard/plugin/PluginRunner.kt index 3bd3154..c219dee 100644 --- a/projectguard/src/test/kotlin/com/rubensousa/projectguard/plugin/PluginRunner.kt +++ b/projectguard/src/test/kotlin/com/rubensousa/projectguard/plugin/PluginRunner.kt @@ -41,20 +41,32 @@ class PluginRunner( settingsFile.appendText("\ninclude(\":$name\")") } - fun assertCheckFails(module: String) { - val task = createCheckTask(module) + fun assertProjectGuardCheckFails(module: String) { + val task = getProjectGuardCheckTask(module) val result = gradleRunner.withArguments(task).buildAndFail() assertThat(result.task(task)!!.outcome).isEqualTo(TaskOutcome.FAILED) lastResult = result } - fun assertCheckSucceeds(module: String) { - val task = createCheckTask(module) + fun assertProjectGuardCheckSucceeds(module: String) { + val task = getProjectGuardCheckTask(module) val result = gradleRunner.withArguments(task).build() assertThat(result.task(task)!!.outcome).isEqualTo(TaskOutcome.SUCCESS) lastResult = result } + fun assertAssembleTaskFails(module: String) { + val result = gradleRunner.withArguments(":$module:assemble").buildAndFail() + assertThat(result.task(getProjectGuardCheckTask(module))!!.outcome).isEqualTo(TaskOutcome.FAILED) + lastResult = result + } + + fun assertCheckTaskFails(module: String) { + val result = gradleRunner.withArguments(":$module:check").buildAndFail() + assertThat(result.task(getProjectGuardCheckTask(module))!!.outcome).isEqualTo(TaskOutcome.FAILED) + lastResult = result + } + fun assertTaskOutputContains(message: String) { assertThat(lastResult!!.output).contains(message) } @@ -75,7 +87,7 @@ class PluginRunner( ) } - private fun createCheckTask(module: String): String { + private fun getProjectGuardCheckTask(module: String): String { return ":$module:projectGuardCheck" } diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts index a15ad76..5598455 100644 --- a/sample/build.gradle.kts +++ b/sample/build.gradle.kts @@ -1,8 +1,10 @@ +import com.rubensousa.projectguard.plugin.LifecycleTask + // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.kotlin.android) apply false - alias(libs.plugins.jetbrains.kotlin.jvm) apply false + alias(libs.plugins.kotlin.jvm) apply false alias(libs.plugins.maven.publish) apply false alias(libs.plugins.android.library) apply false alias(libs.plugins.projectguard) apply true @@ -12,6 +14,13 @@ plugins { } projectGuard { + /** + * Fail the project build without running the dedicated `projectGuardCheck` + */ + options { + lifecycleTask = LifecycleTask.ASSEMBLE + } + report { showLibrariesInGraph = true } From 3ff318db55b8ea1ebf50f7916d994879b51df2c0 Mon Sep 17 00:00:00 2001 From: Ruben Sousa Date: Fri, 6 Mar 2026 01:03:26 +0100 Subject: [PATCH 3/3] Update api file --- projectguard/api/projectguard.api | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/projectguard/api/projectguard.api b/projectguard/api/projectguard.api index 27b9fe7..16cc1e6 100644 --- a/projectguard/api/projectguard.api +++ b/projectguard/api/projectguard.api @@ -25,6 +25,13 @@ public abstract interface class com/rubensousa/projectguard/plugin/GuardScope { public abstract fun deny (Lorg/gradle/api/provider/Provider;Lorg/gradle/api/Action;)V } +public final class com/rubensousa/projectguard/plugin/LifecycleTask : java/lang/Enum { + public static final field ASSEMBLE Lcom/rubensousa/projectguard/plugin/LifecycleTask; + public static final field CHECK Lcom/rubensousa/projectguard/plugin/LifecycleTask; + public static fun valueOf (Ljava/lang/String;)Lcom/rubensousa/projectguard/plugin/LifecycleTask; + public static fun values ()[Lcom/rubensousa/projectguard/plugin/LifecycleTask; +} + public abstract interface class com/rubensousa/projectguard/plugin/ModuleRestrictionScope { public abstract fun allow ([Ljava/lang/String;)V public abstract fun allow ([Lorg/gradle/api/internal/catalog/DelegatingProjectDependency;)V @@ -34,10 +41,16 @@ public abstract interface class com/rubensousa/projectguard/plugin/ModuleRestric public abstract fun reason (Ljava/lang/String;)V } +public abstract interface class com/rubensousa/projectguard/plugin/OptionScope { + public abstract fun getLifecycleTask ()Lcom/rubensousa/projectguard/plugin/LifecycleTask; + public abstract fun setLifecycleTask (Lcom/rubensousa/projectguard/plugin/LifecycleTask;)V +} + public abstract class com/rubensousa/projectguard/plugin/ProjectGuardExtension : com/rubensousa/projectguard/plugin/ProjectGuardScope { public fun (Lorg/gradle/api/model/ObjectFactory;)V public fun guard (Ljava/lang/String;Lorg/gradle/api/Action;)V public fun guardRule (Lorg/gradle/api/Action;)Lcom/rubensousa/projectguard/plugin/GuardRule; + public fun options (Lorg/gradle/api/Action;)V public fun report (Lorg/gradle/api/Action;)V public fun restrictDependency (Ljava/lang/String;Lorg/gradle/api/Action;)V public fun restrictDependency (Lorg/gradle/api/provider/Provider;Lorg/gradle/api/Action;)V @@ -56,6 +69,8 @@ public abstract interface class com/rubensousa/projectguard/plugin/ProjectGuardS public abstract fun guard (Ljava/lang/String;Lorg/gradle/api/Action;)V public fun guard (Lorg/gradle/api/internal/catalog/DelegatingProjectDependency;Lorg/gradle/api/Action;)V public abstract fun guardRule (Lorg/gradle/api/Action;)Lcom/rubensousa/projectguard/plugin/GuardRule; + public fun options (Lgroovy/lang/Closure;)V + public abstract fun options (Lorg/gradle/api/Action;)V public fun report (Lgroovy/lang/Closure;)V public abstract fun report (Lorg/gradle/api/Action;)V public fun restrictDependency (Ljava/lang/String;Lgroovy/lang/Closure;)V