diff --git a/.gitignore b/.gitignore index 47e1517b..1187f335 100644 --- a/.gitignore +++ b/.gitignore @@ -209,3 +209,6 @@ gradle-app.setting **/build/ # End of https://www.gitignore.io/api/IntelliJ,macOS,osx,linux,windows,Gradle,java,gradle,lombok + +lombok.config +**/gen/ \ No newline at end of file diff --git a/build.gradle b/build.gradle index 05d4d289..e7b66bad 100644 --- a/build.gradle +++ b/build.gradle @@ -60,6 +60,7 @@ allprojects { testImplementation 'org.assertj:assertj-core:3.23.1' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2' + testImplementation 'org.mockito:mockito-core:4.6.1' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' } } diff --git a/examples/plantuml/build.gradle b/examples/plantuml/build.gradle new file mode 100644 index 00000000..8be004d4 --- /dev/null +++ b/examples/plantuml/build.gradle @@ -0,0 +1,17 @@ +import io.freefair.gradle.plugins.plantuml.PlantumlTask + +plugins { + id "io.freefair.plantuml" +} + +plantUml { + fileFormat = "PNG" + outputDirectory = layout.buildDirectory.dir("dist") +} + +tasks.register("plantUml2", PlantumlTask) { + source("src/plantuml2") + includePattern = "**/*.tuml" + fileFormat = "SVG" + outputDirectory = layout.buildDirectory.dir("dist2") +} diff --git a/examples/plantuml/src/plantuml/include/test-i.iuml b/examples/plantuml/src/plantuml/include/test-i.iuml new file mode 100644 index 00000000..5972f809 --- /dev/null +++ b/examples/plantuml/src/plantuml/include/test-i.iuml @@ -0,0 +1,3 @@ +@startuml + +@enduml \ No newline at end of file diff --git a/examples/plantuml/src/plantuml/test.puml b/examples/plantuml/src/plantuml/test.puml new file mode 100644 index 00000000..df3a9839 --- /dev/null +++ b/examples/plantuml/src/plantuml/test.puml @@ -0,0 +1,9 @@ +@startuml +!include include/test-i.iuml + +Alice -> Bob: Authentication Request +Bob --> Alice: Authentication Response + +Alice -> Bob: Another authentication Request +Alice <-- Bob: another authentication Response +@enduml diff --git a/examples/plantuml/src/plantuml2/test2.tuml b/examples/plantuml/src/plantuml2/test2.tuml new file mode 100644 index 00000000..d0f7d798 --- /dev/null +++ b/examples/plantuml/src/plantuml2/test2.tuml @@ -0,0 +1,7 @@ +@startuml +Alice -> Bob: Authentication Request +Bob --> Alice: Authentication Response + +Alice -> Bob: Another authentication Request +Alice <-- Bob: another authentication Response +@enduml \ No newline at end of file diff --git a/examples/settings.gradle b/examples/settings.gradle index 7c122ab3..75b0497e 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -42,3 +42,4 @@ include ":code-generator:generator" include ":test-maven-plugin" include 'quicktype' +include 'plantuml' diff --git a/plantuml-plugin/README.md b/plantuml-plugin/README.md new file mode 100644 index 00000000..e69de29b diff --git a/plantuml-plugin/build.gradle b/plantuml-plugin/build.gradle new file mode 100644 index 00000000..52a16c6b --- /dev/null +++ b/plantuml-plugin/build.gradle @@ -0,0 +1,27 @@ +apply plugin: "maven-publish" +apply plugin: "java-gradle-plugin" +apply plugin: "com.gradle.plugin-publish" + +description = "Gradle Plugin for PlantUML" + +dependencies { + //noinspection GradlePackageUpdate + compileOnly 'net.sourceforge.plantuml:plantuml:1.2022.5' + + testRuntimeOnly 'net.sourceforge.plantuml:plantuml:1.2022.5' +} + +gradlePlugin { + plugins { + plantuml { + id = "io.freefair.plantuml" + implementationClass = "io.freefair.gradle.plugins.plantuml.PlantumlPlugin" + displayName = "PlantUML Plugin" + description = "PlantUML Plugin" + } + } +} + +pluginBundle { + tags = ["plantuml"] +} diff --git a/plantuml-plugin/src/main/java/io/freefair/gradle/plugins/plantuml/PlantumlAction.java b/plantuml-plugin/src/main/java/io/freefair/gradle/plugins/plantuml/PlantumlAction.java new file mode 100644 index 00000000..7368c02a --- /dev/null +++ b/plantuml-plugin/src/main/java/io/freefair/gradle/plugins/plantuml/PlantumlAction.java @@ -0,0 +1,36 @@ +package io.freefair.gradle.plugins.plantuml; + +import lombok.SneakyThrows; +import net.sourceforge.plantuml.FileFormat; +import net.sourceforge.plantuml.FileFormatOption; +import net.sourceforge.plantuml.SourceFileReader; +import org.gradle.workers.WorkAction; + +/** + * Gradle {@link WorkAction} for PlantUML {@link SourceFileReader}. + * + * @author Lars Grefer + * @see SourceFileReader + */ +public abstract class PlantumlAction implements WorkAction { + + @SneakyThrows + @Override + public void execute() { + + FileFormat fileFormat = getParameters().getFileFormat() + .map(String::toUpperCase) + .map(FileFormat::valueOf) + .getOrElse(FileFormat.PNG); + + FileFormatOption fileFormatOption = new FileFormatOption(fileFormat, getParameters().getWithMetadata().get()); + + SourceFileReader sourceFileReader = new SourceFileReader( + getParameters().getInputFile().getAsFile().get(), + getParameters().getOutputDirectory().getAsFile().get(), + fileFormatOption + ); + + sourceFileReader.getGeneratedImages(); + } +} diff --git a/plantuml-plugin/src/main/java/io/freefair/gradle/plugins/plantuml/PlantumlParameters.java b/plantuml-plugin/src/main/java/io/freefair/gradle/plugins/plantuml/PlantumlParameters.java new file mode 100644 index 00000000..7247ee73 --- /dev/null +++ b/plantuml-plugin/src/main/java/io/freefair/gradle/plugins/plantuml/PlantumlParameters.java @@ -0,0 +1,23 @@ +package io.freefair.gradle.plugins.plantuml; + +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.Property; +import org.gradle.workers.WorkParameters; + +/** + * {@link WorkParameters} for {@link PlantumlAction}. + * + * @author Lars Grefer + * @see PlantumlPlugin + */ +public interface PlantumlParameters extends WorkParameters { + + RegularFileProperty getInputFile(); + + DirectoryProperty getOutputDirectory(); + + Property getFileFormat(); + + Property getWithMetadata(); +} diff --git a/plantuml-plugin/src/main/java/io/freefair/gradle/plugins/plantuml/PlantumlPlugin.java b/plantuml-plugin/src/main/java/io/freefair/gradle/plugins/plantuml/PlantumlPlugin.java new file mode 100644 index 00000000..759a295e --- /dev/null +++ b/plantuml-plugin/src/main/java/io/freefair/gradle/plugins/plantuml/PlantumlPlugin.java @@ -0,0 +1,30 @@ +package io.freefair.gradle.plugins.plantuml; + + +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; + +/** + * @author Lars Grefer + */ +public class PlantumlPlugin implements Plugin { + + @Override + public void apply(Project project) { + Configuration plantuml = project.getConfigurations().create("plantuml"); + + plantuml.defaultDependencies(s -> { + s.add(project.getDependencies().create("net.sourceforge.plantuml:plantuml:1.2022.5")); + }); + + project.getTasks().withType(PlantumlTask.class).configureEach(plantumlTask -> { + plantumlTask.getPlantumlClasspath().from(plantuml); + plantumlTask.getOutputDirectory().convention(project.getLayout().getBuildDirectory().dir("plantuml")); + }); + + project.getTasks().register("plantUml", PlantumlTask.class, plantumlTask -> { + plantumlTask.source("src/plantuml"); + }); + } +} diff --git a/plantuml-plugin/src/main/java/io/freefair/gradle/plugins/plantuml/PlantumlTask.java b/plantuml-plugin/src/main/java/io/freefair/gradle/plugins/plantuml/PlantumlTask.java new file mode 100644 index 00000000..b3841cf5 --- /dev/null +++ b/plantuml-plugin/src/main/java/io/freefair/gradle/plugins/plantuml/PlantumlTask.java @@ -0,0 +1,71 @@ +package io.freefair.gradle.plugins.plantuml; + +import lombok.Getter; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.file.FileSystemOperations; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.*; +import org.gradle.workers.WorkQueue; +import org.gradle.workers.WorkerExecutor; + +import javax.inject.Inject; +import java.io.File; + +/** + * @author Lars Grefer + */ +public class PlantumlTask extends SourceTask { + + private final WorkerExecutor workerExecutor; + + private final FileSystemOperations fileSystemOperations; + + @Getter + @Classpath + private final ConfigurableFileCollection plantumlClasspath = getProject().files(); + + @Getter + @OutputDirectory + private final DirectoryProperty outputDirectory = getProject().getObjects().directoryProperty(); + + @Getter + @Input + @Optional + private final Property fileFormat = getProject().getObjects().property(String.class); + + @Getter + @Input + private final Property withMetadata = getProject().getObjects().property(Boolean.class).convention(true); + + @Getter + @Input + private final Property includePattern = getProject().getObjects().property(String.class).convention("**/*.puml"); + + @Inject + public PlantumlTask(WorkerExecutor workerExecutor, FileSystemOperations fileSystemOperations) { + this.fileSystemOperations = fileSystemOperations; + this.workerExecutor = workerExecutor; + this.setGroup("plantuml"); + } + + @TaskAction + public void execute() { + + fileSystemOperations.delete(deleteSpec -> deleteSpec.delete(outputDirectory)); + + WorkQueue workQueue = workerExecutor.processIsolation(process -> { + process.getClasspath().from(plantumlClasspath); + process.getForkOptions().systemProperty("java.awt.headless", true); + }); + + for (File file : getSource().matching(p -> p.include(includePattern.get()))) { + workQueue.submit(PlantumlAction.class, params -> { + params.getInputFile().set(file); + params.getOutputDirectory().set(outputDirectory); + params.getFileFormat().set(fileFormat); + params.getWithMetadata().set(withMetadata); + }); + } + } +} diff --git a/plantuml-plugin/src/test/java/io/freefair/gradle/plugins/plantuml/PlantumlPluginTest.java b/plantuml-plugin/src/test/java/io/freefair/gradle/plugins/plantuml/PlantumlPluginTest.java new file mode 100644 index 00000000..3d2e2a1b --- /dev/null +++ b/plantuml-plugin/src/test/java/io/freefair/gradle/plugins/plantuml/PlantumlPluginTest.java @@ -0,0 +1,63 @@ +package io.freefair.gradle.plugins.plantuml; + +import org.gradle.api.Project; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.Property; +import org.gradle.internal.impldep.org.junit.Before; +import org.gradle.testfixtures.ProjectBuilder; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class PlantumlPluginTest { + + private Project project; + + @BeforeEach + void init() { + project = ProjectBuilder.builder().build(); + } + + @Test + void apply() { + project.getPlugins().apply(PlantumlPlugin.class); + + assertThat(project.getTasks().getNames()).contains("plantUml"); + } + + @Test + void execute() { + project.getPlugins().apply(PlantumlPlugin.class); + + PlantumlTask task = project.getTasks().withType(PlantumlTask.class).getByName("plantUml"); + + task.source(getClass().getClassLoader().getResource("puml-files").getPath()); + + assertThrows(UnsupportedOperationException.class, task::execute); + } + + @Test + void taskExecution(@TempDir File tempDir) { + PlantumlParameters parameters = project.getObjects().newInstance(PlantumlParameters.class); + + parameters.getInputFile().set(new File(getClass().getClassLoader().getResource("puml-files/test.puml").getPath())); + parameters.getOutputDirectory().set(tempDir); + parameters.getFileFormat().set("PNG"); + parameters.getWithMetadata().set(false); + + PlantumlAction action = new PlantumlAction() { + @Override + public PlantumlParameters getParameters() { + return parameters; + } + }; + + action.execute(); + } +} diff --git a/plantuml-plugin/src/test/resources/puml-files/test.puml b/plantuml-plugin/src/test/resources/puml-files/test.puml new file mode 100644 index 00000000..f9740ee8 --- /dev/null +++ b/plantuml-plugin/src/test/resources/puml-files/test.puml @@ -0,0 +1,6 @@ +@startuml + +Bob -> Alice: Test +Alice --> Bob: return Test + +@enduml \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index cd15cef2..358576a6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -20,3 +20,4 @@ include "okhttp-plugin" include "git-plugin" include "mkdocs-plugin" include "quicktype-plugin" +include "plantuml-plugin"