outputs = new HashSet<>();
@@ -193,12 +192,12 @@ public Builder insertAfterTask(TaskName target) {
* If a certain project does not have a task with the specified name, no action is
* performed for that project.
*
- *
This method does not guarantee that the task will be included into a standard
+ *
This method does not guarantee that the task will be included in a standard
* Gradle build.
*
*
Invocation of this method may substitute the invocation of
* {@link #insertAfterTask} or {@link #insertBeforeTask} if it's guaranteed that at least
- * one task with such name exists. Though the fallback is never handled and there is
+ * one task with such a name exists. Though the fallback is never handled, and there is
* no guarantee that the task will get into the Gradle task graph.
*
* @param target
@@ -232,7 +231,7 @@ public Builder allowNoDependencies() {
*
If none of the specified file system elements are present before the task
* execution, the task will be marked as {@code NO-SOURCE} and skipped.
*
- *
Multiple invocations appends the new files to the existing ones.
+ *
Multiple invocations append the new files to the existing ones.
*
* @param inputs
* the task input files
@@ -251,8 +250,8 @@ public Builder withInputFiles(FileCollection inputs) {
*
An input property is treated in a similar way as
* an {@linkplain #withInputFiles input file}.
*
- *
Multiple invocations of this method append new properties. If there already is
- * a property with is such a name, the value is overridden.
+ *
Multiple invocations of this method append new properties.
+ * If there already is a property with such a name, the value is overridden.
*
* @param propertyName
* the name of the property
@@ -309,9 +308,8 @@ public GradleTask applyNowTo(Project project) {
log.debug("Creating task `{}` in the project `{}`.", taskName, projectName);
TaskProvider newTask;
try {
- newTask = project.getTasks().register(taskName, Task.class, task -> {
- task.doLast(action);
- });
+ newTask = project.getTasks()
+ .register(taskName, Task.class, task -> task.doLast(action));
} catch (@SuppressWarnings("OverlyBroadCatchBlock") Exception e) {
log.error("Failed to create task `{}` in the project `{}`.", taskName, projectName);
throw new IllegalStateException(e);
@@ -356,6 +354,7 @@ private void dependTask(Task task, Project project) {
}
private void dependTaskOnAllProjects(Task task, Project rootProject) {
+ checkNotNull(previousTaskOfAllProjects, "Previous task of all projects is not set.");
var prevTaskName = previousTaskOfAllProjects.name();
ProjectHierarchy.applyToAll(rootProject, project -> {
var existingTask = project.getTasks()
@@ -399,7 +398,7 @@ public int hashCode() {
}
@Override
- public boolean equals(Object obj) {
+ public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
diff --git a/plugin-base/src/main/java/io/spine/tools/gradle/task/TaskName.java b/plugin-base/src/main/java/io/spine/tools/gradle/task/TaskName.java
index 1c38cf27..38e3a36f 100644
--- a/plugin-base/src/main/java/io/spine/tools/gradle/task/TaskName.java
+++ b/plugin-base/src/main/java/io/spine/tools/gradle/task/TaskName.java
@@ -33,6 +33,11 @@
*/
public interface TaskName {
+ /**
+ * The prefix for a compilation task name.
+ */
+ String COMPILE_PREFIX = "compile";
+
/**
* The value of the name.
*
diff --git a/plugin-base/src/main/kotlin/io/spine/tools/gradle/project/ProjectExts.kt b/plugin-base/src/main/kotlin/io/spine/tools/gradle/project/ProjectExts.kt
index a6e5079f..ac3c9200 100644
--- a/plugin-base/src/main/kotlin/io/spine/tools/gradle/project/ProjectExts.kt
+++ b/plugin-base/src/main/kotlin/io/spine/tools/gradle/project/ProjectExts.kt
@@ -35,6 +35,7 @@ import io.spine.tools.code.Language
import io.spine.tools.code.SourceSetName
import io.spine.tools.code.SourceSetName.Companion.main
import io.spine.tools.gradle.ConfigurationName
+import io.spine.tools.gradle.task.TaskName
import io.spine.tools.meta.MavenArtifact
import java.lang.reflect.Method
import org.gradle.api.Project
@@ -164,7 +165,7 @@ public fun Project.hasKotlin(): Boolean = hasCompileTask(Kotlin)
public fun Project.hasCompileTask(language: Language): Boolean {
val currentTasks = ImmutableList.copyOf(tasks)
val compileTask = currentTasks.find {
- it.name.startsWith("compile") && it.name.endsWith(language.name)
+ it.name.startsWith(TaskName.COMPILE_PREFIX) && it.name.endsWith(language.name)
}
return compileTask != null
}
diff --git a/plugin-base/src/main/kotlin/io/spine/tools/gradle/task/JavaTaskName.kt b/plugin-base/src/main/kotlin/io/spine/tools/gradle/task/JavaTaskName.kt
index 8368eac3..4d5e86a7 100644
--- a/plugin-base/src/main/kotlin/io/spine/tools/gradle/task/JavaTaskName.kt
+++ b/plugin-base/src/main/kotlin/io/spine/tools/gradle/task/JavaTaskName.kt
@@ -46,7 +46,7 @@ public class JavaTaskName(value: String, ssn: SourceSetName) : TaskWithSourceSet
*/
@JvmStatic
public fun compileJava(ssn: SourceSetName): TaskName =
- JavaTaskName("compile${ssn.toInfix()}Java", ssn)
+ JavaTaskName("${TaskName.COMPILE_PREFIX}${ssn.toInfix()}Java", ssn)
/**
* Obtains a name of the task which marks processing of all the classes and resources
diff --git a/plugin-base/src/main/kotlin/io/spine/tools/gradle/task/TaskWithSourceSetName.kt b/plugin-base/src/main/kotlin/io/spine/tools/gradle/task/TaskWithSourceSetName.kt
index b0743447..aafb3c32 100644
--- a/plugin-base/src/main/kotlin/io/spine/tools/gradle/task/TaskWithSourceSetName.kt
+++ b/plugin-base/src/main/kotlin/io/spine/tools/gradle/task/TaskWithSourceSetName.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2022, TeamDev. All rights reserved.
+ * Copyright 2026, TeamDev. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@ import io.spine.tools.code.SourceSetBasedName
import io.spine.tools.code.SourceSetName
/**
- * A base for a task name type the value of which depend on a name of a source set
+ * A base for a task name type the value of which depends on a name of a source set
* to which this task belongs.
*/
public open class TaskWithSourceSetName protected constructor(
diff --git a/plugin-base/src/test/kotlin/io/spine/tools/gradle/task/GradleTaskBuilderSpec.kt b/plugin-base/src/test/kotlin/io/spine/tools/gradle/task/GradleTaskBuilderSpec.kt
index cd1de614..20f72e4f 100644
--- a/plugin-base/src/test/kotlin/io/spine/tools/gradle/task/GradleTaskBuilderSpec.kt
+++ b/plugin-base/src/test/kotlin/io/spine/tools/gradle/task/GradleTaskBuilderSpec.kt
@@ -26,10 +26,10 @@
package io.spine.tools.gradle.task
-import com.google.common.collect.ImmutableList
-import com.google.common.truth.Truth.assertThat
+import io.kotest.assertions.throwables.shouldThrow
import io.kotest.matchers.collections.shouldContain
import io.kotest.matchers.collections.shouldHaveSize
+import io.kotest.matchers.maps.shouldContainKey
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import io.spine.testing.Assertions.assertIllegalState
@@ -42,9 +42,11 @@ import io.spine.tools.gradle.testing.GradleProject
import io.spine.tools.gradle.testing.NoOp
import java.io.File
import org.gradle.api.Project
+import org.gradle.api.Task
import org.gradle.testfixtures.ProjectBuilder
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.DisplayName
+import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
/**
@@ -76,11 +78,8 @@ internal class GradleTaskBuilderSpec {
val newTask = subProjectTasks.findByName(task.name.name())
newTask shouldNotBe null
val dependencies: Collection<*> = newTask!!.dependsOn
- assertThat(dependencies)
- .containsAtLeast(
- subProjectTasks.findByName(compileJava.name()),
- project.tasks.findByName(compileJava.name())
- )
+ dependencies shouldContain subProjectTasks.findByName(compileJava.name())
+ dependencies shouldContain project.tasks.findByName(compileJava.name())
}
@Test
@@ -130,8 +129,7 @@ internal class GradleTaskBuilderSpec {
}
@Test
- @DisplayName("return build task description")
- fun returnBuildTaskDescription() {
+ fun `return build task description`() {
val desc = GradleTask.newBuilder(preClean, NoOp.action())
.insertBeforeTask(BaseTaskName.clean)
.applyNowTo(project)
@@ -151,14 +149,121 @@ internal class GradleTaskBuilderSpec {
val task = project.tasks.findByPath(preClean.name)
task shouldNotBe null
- val inputs = task!!.inputs
- inputs shouldNotBe null
- val inputFiles = ImmutableList.copyOf(
- inputs.files.files
- )
- inputFiles.let {
- it shouldHaveSize 1
- it[0].canonicalFile shouldBe input.canonicalFile
+ val inputFiles = task!!.inputs.files.files.toList()
+ inputFiles shouldHaveSize 1
+ inputFiles[0].canonicalFile shouldBe input.canonicalFile
+ }
+
+ @Nested
+ inner class `'withInputProperty'` {
+
+ @Test
+ fun `register input property on task`() {
+ GradleTask.newBuilder(preClean, NoOp.action())
+ .insertBeforeTask(BaseTaskName.clean)
+ .withInputProperty("propName", "propValue")
+ .applyNowTo(project)
+
+ val task = project.tasks.findByPath(preClean.name)
+ task shouldNotBe null
+ task!!.inputs.properties["propName"] shouldBe "propValue"
+ }
+
+ @Test
+ fun `append multiple input properties on separate calls`() {
+ GradleTask.newBuilder(preClean, NoOp.action())
+ .insertBeforeTask(BaseTaskName.clean)
+ .withInputProperty("first", "alpha")
+ .withInputProperty("second", "beta")
+ .applyNowTo(project)
+
+ val task = project.tasks.findByPath(preClean.name)
+ task shouldNotBe null
+ val properties = task!!.inputs.properties
+ properties["first"] shouldBe "alpha"
+ properties["second"] shouldBe "beta"
+ }
+
+ @Test
+ fun `override input property value when called with same name`() {
+ GradleTask.newBuilder(preClean, NoOp.action())
+ .insertBeforeTask(BaseTaskName.clean)
+ .withInputProperty("key", "original")
+ .withInputProperty("key", "overridden")
+ .applyNowTo(project)
+
+ val task = project.tasks.findByPath(preClean.name)
+ task shouldNotBe null
+ task!!.inputs.properties["key"] shouldBe "overridden"
+ }
+
+ @Test
+ fun `accept null as input property value`() {
+ GradleTask.newBuilder(preClean, NoOp.action())
+ .insertBeforeTask(BaseTaskName.clean)
+ .withInputProperty("nullProp", null)
+ .applyNowTo(project)
+
+ val task = project.tasks.findByPath(preClean.name)
+ task shouldNotBe null
+ task!!.inputs.properties shouldContainKey "nullProp"
+ }
+ }
+
+ @Nested
+ inner class `'withOutputFiles'` {
+
+ @Test
+ fun `register output files on task`() {
+ val output = File(".").absoluteFile
+ val files = project.layout.files(output)
+ GradleTask.newBuilder(preClean, NoOp.action())
+ .insertBeforeTask(BaseTaskName.clean)
+ .withOutputFiles(files)
+ .applyNowTo(project)
+
+ val task = project.tasks.findByPath(preClean.name)
+ task shouldNotBe null
+ val outputFiles = task!!.outputs.files.files.toList()
+ outputFiles shouldHaveSize 1
+ outputFiles[0].canonicalFile shouldBe output.canonicalFile
+ }
+
+ @Test
+ fun `append output files on multiple calls`() {
+ val firstOutput = File(".").absoluteFile
+ val secondOutput = File("..").absoluteFile
+ GradleTask.newBuilder(preClean, NoOp.action())
+ .insertBeforeTask(BaseTaskName.clean)
+ .withOutputFiles(project.layout.files(firstOutput))
+ .withOutputFiles(project.layout.files(secondOutput))
+ .applyNowTo(project)
+
+ val task = project.tasks.findByPath(preClean.name)
+ task shouldNotBe null
+ val outputFiles = task!!.outputs.files.files
+ val canonicalPaths = outputFiles.map { it.canonicalFile }
+ canonicalPaths shouldContain firstOutput.canonicalFile
+ canonicalPaths shouldContain secondOutput.canonicalFile
}
}
+
+ @Test
+ fun `allow creating task with no dependencies if explicitly permitted`() {
+ val standaloneProject = ProjectBuilder.builder().build()
+ val taskName = TaskName.of("taskWithNoDependencies")
+
+ shouldThrow {
+ GradleTask
+ .newBuilder(taskName) { _: Task -> }
+ .applyNowTo(standaloneProject)
+ }
+
+ val task = GradleTask
+ .newBuilder(taskName) { _: Task -> }
+ .allowNoDependencies()
+ .applyNowTo(standaloneProject)
+
+ task.name shouldBe taskName
+ }
}
diff --git a/pom.xml b/pom.xml
index 23244ad9..0cdd20ec 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@ all modules and does not describe the project structure per-subproject.
-->
io.spine.tools
tool-base
-2.0.0-SNAPSHOT.377
+2.0.0-SNAPSHOT.378
2015
diff --git a/protobuf-setup-plugins/src/main/kotlin/io/spine/tools/protobuf/gradle/ProtobufTaskName.kt b/protobuf-setup-plugins/src/main/kotlin/io/spine/tools/protobuf/gradle/ProtobufTaskName.kt
index ab9c0180..ac781dd7 100644
--- a/protobuf-setup-plugins/src/main/kotlin/io/spine/tools/protobuf/gradle/ProtobufTaskName.kt
+++ b/protobuf-setup-plugins/src/main/kotlin/io/spine/tools/protobuf/gradle/ProtobufTaskName.kt
@@ -33,15 +33,9 @@ import io.spine.tools.gradle.task.TaskWithSourceSetName
/**
* Names of Gradle tasks defined by the Protobuf Gradle plugin.
*
- * ### API Note
- *
- * The class is made open only to support package migration of
- * [io.spine.tools.gradle.task.ProtobufTaskName], which is deprecated in favor of
- * this one. Once the deprecated class is removed, this class should become final.
- *
* @see Protobuf Gradle plugin
*/
-public open class ProtobufTaskName(value: String, ssn: SourceSetName) :
+public class ProtobufTaskName(value: String, ssn: SourceSetName) :
TaskWithSourceSetName(value, ssn) {
public companion object {
@@ -60,7 +54,7 @@ public open class ProtobufTaskName(value: String, ssn: SourceSetName) :
* Users should be conscious and cautious when depending on it.
*/
@JvmField
- public val generateProto: TaskName = generateProto(SourceSetName.Companion.main)
+ public val generateProto: TaskName = generateProto(SourceSetName.main)
/**
* Generates test code from Protobuf.
@@ -69,6 +63,6 @@ public open class ProtobufTaskName(value: String, ssn: SourceSetName) :
* Users should be conscious and cautious when depending on it.
*/
@JvmField
- public val generateTestProto: TaskName = generateProto(SourceSetName.Companion.test)
+ public val generateTestProto: TaskName = generateProto(SourceSetName.test)
}
}
diff --git a/protobuf-setup-plugins/src/main/kotlin/io/spine/tools/protobuf/gradle/plugin/GeneratedSourcePlugin.kt b/protobuf-setup-plugins/src/main/kotlin/io/spine/tools/protobuf/gradle/plugin/GeneratedSourcePlugin.kt
index bf42262e..6be0f0ad 100644
--- a/protobuf-setup-plugins/src/main/kotlin/io/spine/tools/protobuf/gradle/plugin/GeneratedSourcePlugin.kt
+++ b/protobuf-setup-plugins/src/main/kotlin/io/spine/tools/protobuf/gradle/plugin/GeneratedSourcePlugin.kt
@@ -39,7 +39,6 @@ import io.spine.tools.protobuf.gradle.plugin.GeneratedSubdir.KOTLIN
import io.spine.tools.resolve
import java.io.File
import java.nio.file.Path
-import kotlin.io.path.createDirectories
import org.gradle.api.Project
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.tasks.SourceSet
@@ -47,7 +46,7 @@ import org.gradle.plugins.ide.idea.GenerateIdeaModule
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
/**
- * A Gradle project plugin that configures Protobuf compilation process to
+ * A Gradle project plugin that configures the Protobuf compilation process to
* put the resulting output to the `generated` directory under the project root.
*
* The plugin does the following:
@@ -196,7 +195,8 @@ public fun GenerateProtoTask.setupKotlinCompile() {
}
/**
- * Ensures the generated dirs exist before IDEA module is created, so they can be added as sources.
+ * Ensures the generated dirs exist before an IDEA module is created,
+ * so they can be added as sources.
*/
@Internal
context(_: GeneratedDirectoryContext)
diff --git a/version.gradle.kts b/version.gradle.kts
index 966c8356..d0cda3a5 100644
--- a/version.gradle.kts
+++ b/version.gradle.kts
@@ -24,4 +24,4 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-val versionToPublish: String by extra("2.0.0-SNAPSHOT.377")
+val versionToPublish: String by extra("2.0.0-SNAPSHOT.378")