diff --git a/app/build.gradle.kts b/app/build.gradle.kts index de722df..29c1b77 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -3,15 +3,19 @@ import org.gradle.api.tasks.testing.logging.TestLogEvent import com.uwyn.rife2.gradle.TemplateType.* plugins { + application id("com.uwyn.rife2") `maven-publish` } -version = 1.0 -group = "com.example" - base { archivesName.set("hello") + version = 1.0 + group = "com.example" +} + +application { + mainClass.set("hello.App") } java { @@ -27,19 +31,16 @@ repositories { } rife2 { - mainClass.set("hello.App") version.set("1.4.0") useAgent.set(true) - precompiledTemplateTypes.addAll(HTML) } dependencies { - runtimeOnly("org.eclipse.jetty:jetty-server:11.0.13") - runtimeOnly("org.eclipse.jetty:jetty-servlet:11.0.13") - runtimeOnly("org.slf4j:slf4j-simple:2.0.5") + runtimeOnly(libs.bundles.jetty) + runtimeOnly(libs.slf4j.simple) - testImplementation("org.jsoup:jsoup:1.15.3") - testImplementation("org.junit.jupiter:junit-jupiter:5.9.1") + testImplementation(libs.jsoup) + testImplementation(libs.junit.jupiter) } tasks { diff --git a/app/src/main/templates/hello.html b/app/src/main/templates/hello.html index f7ffe8b..59ff81b 100644 --- a/app/src/main/templates/hello.html +++ b/app/src/main/templates/hello.html @@ -8,4 +8,4 @@

Hello World

- \ No newline at end of file + diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts index b9ea647..c7fabff 100644 --- a/build-logic/build.gradle.kts +++ b/build-logic/build.gradle.kts @@ -1,5 +1,6 @@ plugins { `java-gradle-plugin` + groovy } repositories { @@ -8,13 +9,8 @@ repositories { dependencies { gradleApi() -} - -tasks { - withType { - options.isDeprecation = true - options.compilerArgs.add("-Xlint:unchecked") - } + testImplementation(libs.spock.core) + testImplementation(gradleTestKit()) } gradlePlugin { @@ -25,3 +21,11 @@ gradlePlugin { } } } + +tasks.withType().configureEach { + useJUnitPlatform() + testLogging { + exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL + events = setOf(org.gradle.api.tasks.testing.logging.TestLogEvent.PASSED, org.gradle.api.tasks.testing.logging.TestLogEvent.SKIPPED, org.gradle.api.tasks.testing.logging.TestLogEvent.FAILED) + } +} diff --git a/build-logic/settings.gradle.kts b/build-logic/settings.gradle.kts index 7fbbd44..9ac59bd 100644 --- a/build-logic/settings.gradle.kts +++ b/build-logic/settings.gradle.kts @@ -1 +1,9 @@ rootProject.name = "build-logic" + +dependencyResolutionManagement { + versionCatalogs { + create("libs") { + from(files("../gradle/libs.versions.toml")) + } + } +} diff --git a/build-logic/src/main/java/com/uwyn/rife2/gradle/Rife2Extension.java b/build-logic/src/main/java/com/uwyn/rife2/gradle/Rife2Extension.java index 23a4ece..30fa218 100644 --- a/build-logic/src/main/java/com/uwyn/rife2/gradle/Rife2Extension.java +++ b/build-logic/src/main/java/com/uwyn/rife2/gradle/Rife2Extension.java @@ -18,10 +18,7 @@ package com.uwyn.rife2.gradle; import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.Property; -@SuppressWarnings("unused") public abstract class Rife2Extension { - public abstract Property getMainClass(); - public abstract Property getVersion(); public abstract Property getUseAgent(); diff --git a/build-logic/src/main/java/com/uwyn/rife2/gradle/Rife2Plugin.java b/build-logic/src/main/java/com/uwyn/rife2/gradle/Rife2Plugin.java index 9409eea..2777742 100644 --- a/build-logic/src/main/java/com/uwyn/rife2/gradle/Rife2Plugin.java +++ b/build-logic/src/main/java/com/uwyn/rife2/gradle/Rife2Plugin.java @@ -25,10 +25,14 @@ import org.gradle.api.component.AdhocComponentWithVariants; import org.gradle.api.component.ConfigurationVariantDetails; import org.gradle.api.file.DuplicatesStrategy; import org.gradle.api.plugins.BasePluginExtension; +import org.gradle.api.plugins.JavaApplication; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginExtension; import org.gradle.api.plugins.PluginContainer; -import org.gradle.api.tasks.*; +import org.gradle.api.tasks.JavaExec; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.TaskContainer; +import org.gradle.api.tasks.TaskProvider; import org.gradle.api.tasks.bundling.Jar; import org.gradle.api.tasks.testing.Test; import org.gradle.process.CommandLineArgumentProvider; @@ -36,12 +40,12 @@ import org.gradle.process.CommandLineArgumentProvider; import java.util.Collections; import java.util.Locale; -@SuppressWarnings({"ALL", "unused"}) public class Rife2Plugin implements Plugin { public static final String DEFAULT_TEMPLATES_DIR = "src/main/templates"; public static final String DEFAULT_GENERATED_RIFE2_CLASSES_DIR = "generated/classes/rife2"; public static final String RIFE2_GROUP = "rife2"; public static final String WEBAPP_SRCDIR = "src/main/webapp"; + public static final String PRECOMPILE_TEMPLATES_TASK_NAME = "precompileTemplates"; @Override public void apply(Project project) { @@ -59,12 +63,10 @@ public class Rife2Plugin implements Plugin { configurations.getByName(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME).extendsFrom(rife2Configuration); var precompileTemplates = registerPrecompileTemplateTask(project, rife2CompilerClasspath, rife2Extension); - createRife2DevelopmentOnlyConfiguration(project, configurations, dependencyHandler, precompileTemplates); + createRife2DevelopmentOnlyConfiguration(project, configurations, dependencyHandler); exposePrecompiledTemplatesToTestTask(project, configurations, dependencyHandler, precompileTemplates); configureAgent(project, plugins, rife2Extension, rife2AgentClasspath); - registerRunTask(project, rife2Extension, rife2AgentClasspath); - var uberJarTask = registerUberJarTask(project, plugins, javaPluginExtension, rife2Extension, tasks, precompileTemplates); - + TaskProvider uberJarTask = registerUberJarTask(project, plugins, javaPluginExtension, rife2Extension, tasks, precompileTemplates); bundlePrecompiledTemplatesIntoJarFile(tasks, precompileTemplates); configureMavenPublishing(project, plugins, configurations, uberJarTask); @@ -86,13 +88,11 @@ public class Rife2Plugin implements Plugin { conf.attributes(attrs -> { for (Attribute attribute : runtimeAttributes.keySet()) { Object value = runtimeAttributes.getAttribute(attribute); - if (value != null) { - if (Bundling.class.equals(attribute.getType())) { - attrs.attribute(Bundling.BUNDLING_ATTRIBUTE, project.getObjects().named(Bundling.class, Bundling.SHADOWED)); - } else { - //noinspection unchecked - attrs.attribute((Attribute) attribute, value); - } + //noinspection unchecked + if (Bundling.class.equals(attribute.getType())) { + attrs.attribute(Bundling.BUNDLING_ATTRIBUTE, project.getObjects().named(Bundling.class, Bundling.SHADOWED)); + } else { + attrs.attribute((Attribute) attribute, value); } } }); @@ -119,14 +119,13 @@ public class Rife2Plugin implements Plugin { private void createRife2DevelopmentOnlyConfiguration(Project project, ConfigurationContainer configurations, - DependencyHandler dependencies, - TaskProvider precompileTemplatesTask) { + DependencyHandler dependencies) { var rife2DevelopmentOnly = configurations.create("rife2DevelopmentOnly", conf -> { conf.setDescription("Dependencies which should only be visible when running the application in development mode (and not in tests)."); conf.setCanBeConsumed(false); conf.setCanBeResolved(false); }); - rife2DevelopmentOnly.getDependencies().add(dependencies.create(project.files(precompileTemplatesTask))); + rife2DevelopmentOnly.getDependencies().add(dependencies.create(project.files(DEFAULT_TEMPLATES_DIR))); configurations.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME).extendsFrom(rife2DevelopmentOnly); } @@ -173,7 +172,9 @@ public class Rife2Plugin implements Plugin { private static Rife2Extension createRife2Extension(Project project) { var rife2 = project.getExtensions().create("rife2", Rife2Extension.class); rife2.getUseAgent().convention(false); - rife2.getUberMainClass().set(rife2.getMainClass() + "Uber"); + rife2.getUberMainClass().convention(project.getExtensions().getByType(JavaApplication.class).getMainClass() + .map(mainClass -> mainClass + "Uber")); + rife2.getPrecompiledTemplateTypes().convention(Collections.singletonList(TemplateType.HTML)); return rife2; } @@ -216,7 +217,7 @@ public class Rife2Plugin implements Plugin { private static TaskProvider registerPrecompileTemplateTask(Project project, Configuration rife2CompilerClasspath, Rife2Extension rife2Extension) { - return project.getTasks().register("precompileTemplates", PrecompileTemplates.class, task -> { + return project.getTasks().register(PRECOMPILE_TEMPLATES_TASK_NAME, PrecompileTemplates.class, task -> { task.setGroup(RIFE2_GROUP); task.setDescription("Pre-compiles the templates."); task.getVerbose().convention(true); @@ -226,18 +227,4 @@ public class Rife2Plugin implements Plugin { task.getOutputDirectory().set(project.getLayout().getBuildDirectory().dir(DEFAULT_GENERATED_RIFE2_CLASSES_DIR)); }); } - - private static void registerRunTask(Project project, - Rife2Extension rife2Extension, - Configuration rife2CompilerClasspath) { - project.getTasks().register("run", RunTask.class, task -> { - task.setGroup(RIFE2_GROUP); - task.setDescription("Runs this project as a web application."); - task.getAgentClassPath().set(rife2CompilerClasspath.getAsPath()); - task.getClasspath().from(project.getExtensions().getByType(SourceSetContainer.class) - .getByName(SourceSet.MAIN_SOURCE_SET_NAME).getRuntimeClasspath()); - task.getMainClass().set(rife2Extension.getMainClass()); - task.getTemplatesDirectory().set(project.getLayout().getProjectDirectory().dir(DEFAULT_TEMPLATES_DIR)); - }); - } } diff --git a/build-logic/src/main/java/com/uwyn/rife2/gradle/RunTask.java b/build-logic/src/main/java/com/uwyn/rife2/gradle/RunTask.java deleted file mode 100644 index c107544..0000000 --- a/build-logic/src/main/java/com/uwyn/rife2/gradle/RunTask.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2003-2021 the original author or authors. - * - * 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. - */ -package com.uwyn.rife2.gradle; - -import org.gradle.api.DefaultTask; -import org.gradle.api.file.ConfigurableFileCollection; -import org.gradle.api.file.DirectoryProperty; -import org.gradle.api.provider.Property; -import org.gradle.api.tasks.*; -import org.gradle.process.ExecOperations; - -import javax.inject.Inject; -import java.util.List; - -@CacheableTask -public abstract class RunTask extends DefaultTask { - @Input - public abstract Property getAgentClassPath(); - - @Classpath - public abstract ConfigurableFileCollection getClasspath(); - - @Inject - protected abstract ExecOperations getExecOperations(); - - @Input - public abstract Property getMainClass(); - - @InputDirectory - @PathSensitive(PathSensitivity.RELATIVE) - public abstract DirectoryProperty getTemplatesDirectory(); - - @TaskAction - public void run() { - getExecOperations().javaexec(run -> { - run.setClasspath(getProject().getObjects().fileCollection().from(getTemplatesDirectory()).plus(getClasspath())); - run.getMainClass().set(getMainClass()); - run.args(List.of("-javaagent:" + getAgentClassPath().get())); - }); - } -} \ No newline at end of file diff --git a/build-logic/src/test-projects/minimal/build.gradle b/build-logic/src/test-projects/minimal/build.gradle new file mode 100644 index 0000000..697f9f5 --- /dev/null +++ b/build-logic/src/test-projects/minimal/build.gradle @@ -0,0 +1,40 @@ +import com.uwyn.rife2.gradle.TemplateType.* + +plugins { + id("application") + id("com.uwyn.rife2") +} + +base { + archivesName = "hello" + version = 1.0 + group = "com.example" +} + +application { + mainClass = "hello.App" +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +repositories { + mavenCentral() +} + +rife2 { + version = "1.4.0" + useAgent = true +} + +dependencies { + runtimeOnly("org.eclipse.jetty:jetty-server:11.0.13") + runtimeOnly("org.eclipse.jetty:jetty-servlet:11.0.13") + runtimeOnly("org.slf4j:slf4j-simple:2.0.5") + + testImplementation("org.jsoup:jsoup:1.15.3") + testImplementation("org.junit.jupiter:junit-jupiter:5.9.1") +} diff --git a/build-logic/src/test-projects/minimal/settings.gradle b/build-logic/src/test-projects/minimal/settings.gradle new file mode 100644 index 0000000..e87ab3c --- /dev/null +++ b/build-logic/src/test-projects/minimal/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'minimal' diff --git a/build-logic/src/test-projects/minimal/src/main/java/hello/App.java b/build-logic/src/test-projects/minimal/src/main/java/hello/App.java new file mode 100644 index 0000000..43a1870 --- /dev/null +++ b/build-logic/src/test-projects/minimal/src/main/java/hello/App.java @@ -0,0 +1,16 @@ +package hello; + +import rife.engine.*; + +public class App extends Site { + public void setup() { + var hello = get("/hello", c -> c.print(c.template("hello"))); + get("/", c -> c.redirect(hello)); + } + + public static void main(String[] args) { + new Server() + .staticResourceBase("src/main/webapp") + .start(new App()); + } +} diff --git a/build-logic/src/test-projects/minimal/src/main/java/hello/AppUber.java b/build-logic/src/test-projects/minimal/src/main/java/hello/AppUber.java new file mode 100644 index 0000000..8dbf6a6 --- /dev/null +++ b/build-logic/src/test-projects/minimal/src/main/java/hello/AppUber.java @@ -0,0 +1,11 @@ +package hello; + +import rife.engine.Server; + +public class AppUber extends App { + public static void main(String[] args) { + new Server() + .staticUberJarResourceBase("webapp") + .start(new AppUber()); + } +} \ No newline at end of file diff --git a/build-logic/src/test-projects/minimal/src/main/resources/META-INF/native-image/reflect-config.json b/build-logic/src/test-projects/minimal/src/main/resources/META-INF/native-image/reflect-config.json new file mode 100644 index 0000000..9b0c3be --- /dev/null +++ b/build-logic/src/test-projects/minimal/src/main/resources/META-INF/native-image/reflect-config.json @@ -0,0 +1,6 @@ +[ +{ + "name":"rife.template.html.hello", + "methods":[{"name":"","parameterTypes":[] }] +} +] diff --git a/build-logic/src/test-projects/minimal/src/main/resources/META-INF/native-image/resource-config.json b/build-logic/src/test-projects/minimal/src/main/resources/META-INF/native-image/resource-config.json new file mode 100644 index 0000000..ad0b0a3 --- /dev/null +++ b/build-logic/src/test-projects/minimal/src/main/resources/META-INF/native-image/resource-config.json @@ -0,0 +1,8 @@ +{ + "resources":{ + "includes":[ + {"pattern":"^webapp/.*$"} + ] + }, + "bundles":[] +} diff --git a/build-logic/src/test-projects/minimal/src/main/templates/hello.html b/build-logic/src/test-projects/minimal/src/main/templates/hello.html new file mode 100644 index 0000000..59ff81b --- /dev/null +++ b/build-logic/src/test-projects/minimal/src/main/templates/hello.html @@ -0,0 +1,11 @@ + + + + + <!--v title-->Hello<!--/v--> + + + +

Hello World

+ + diff --git a/build-logic/src/test-projects/minimal/src/main/webapp/css/style.css b/build-logic/src/test-projects/minimal/src/main/webapp/css/style.css new file mode 100644 index 0000000..52bf6c7 --- /dev/null +++ b/build-logic/src/test-projects/minimal/src/main/webapp/css/style.css @@ -0,0 +1,21 @@ +:root { + /* fonts */ + --main-font: sans-serif; + + /* font sizes */ + --main-font-size: 18px; + + /* colors */ + --main-background-color: #0d0d0d; + --main-text-color: #d0d0d0; + + /* margins and padding */ + --content-padding: 2em; +} +body { + background: var(--main-background-color); + font-family: var(--main-font); + font-style: var(--main-font-size); + color: var(--main-text-color); + padding: var(--content-padding); +} \ No newline at end of file diff --git a/build-logic/src/test-projects/minimal/src/test/java/hello/AppTest.java b/build-logic/src/test-projects/minimal/src/test/java/hello/AppTest.java new file mode 100644 index 0000000..45a0763 --- /dev/null +++ b/build-logic/src/test-projects/minimal/src/test/java/hello/AppTest.java @@ -0,0 +1,24 @@ +/* + * This Java source file was generated by the Gradle 'init' task. + */ +package hello; + +import org.junit.jupiter.api.Test; +import rife.test.MockConversation; + +import static org.junit.jupiter.api.Assertions.*; + +public class AppTest { + @Test + void verifyRoot() { + var m = new MockConversation(new App()); + assertEquals(m.doRequest("/").getStatus(), 302); + } + + @Test + void verifyHello() { + var m = new MockConversation(new App()); + assertEquals("Hello", m.doRequest("/hello") + .getTemplate().getValue("title")); + } +} diff --git a/build-logic/src/test/groovy/com/uwyn/rife2/gradle/AbstractFunctionalTest.groovy b/build-logic/src/test/groovy/com/uwyn/rife2/gradle/AbstractFunctionalTest.groovy new file mode 100644 index 0000000..7629d3f --- /dev/null +++ b/build-logic/src/test/groovy/com/uwyn/rife2/gradle/AbstractFunctionalTest.groovy @@ -0,0 +1,184 @@ +package com.uwyn.rife2.gradle + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import org.gradle.util.GFileUtils +import org.gradle.util.GradleVersion +import spock.lang.Specification +import spock.lang.TempDir + +import java.nio.file.Path + +abstract class AbstractFunctionalTest extends Specification { + + private final String gradleVersion = System.getProperty("gradleVersion", GradleVersion.current().version) + + @TempDir + Path testDirectory + + boolean debug + + private StringWriter outputWriter + private StringWriter errorOutputWriter + private String output + private String errorOutput + + BuildResult result + + Path path(String... pathElements) { + Path cur = testDirectory + pathElements.each { + cur = cur.resolve(it) + } + cur + } + + File file(String... pathElements) { + path(pathElements).toFile() + } + + File getGroovyBuildFile() { + file("build.gradle") + } + + File getBuildFile() { + groovyBuildFile + } + + File getKotlinBuildFile() { + file("build.gradle.kts") + } + + File getGroovySettingsFile() { + file("settings.gradle") + } + + File getKotlinSettingsFile() { + file("settings.gradle.kts") + } + + File getSettingsFile() { + groovySettingsFile + } + + void run(String... args) { + try { + result = newRunner(args) + .build() + } finally { + recordOutputs() + } + } + + void outputContains(String text) { + assert output.normalize().contains(text.normalize()) + } + + void outputDoesNotContain(String text) { + assert !output.normalize().contains(text.normalize()) + } + + void errorOutputContains(String text) { + assert errorOutput.normalize().contains(text.normalize()) + } + + void tasks(@DelegatesTo(value = TaskExecutionGraph, strategy = Closure.DELEGATE_FIRST) Closure spec) { + def graph = new TaskExecutionGraph() + spec.delegate = graph + spec.resolveStrategy = Closure.DELEGATE_FIRST + spec() + } + + private void recordOutputs() { + output = outputWriter.toString() + errorOutput = errorOutputWriter.toString() + } + + private GradleRunner newRunner(String... args) { + outputWriter = new StringWriter() + errorOutputWriter = new StringWriter() + ArrayList autoArgs = computeAutoArgs() + def runner = GradleRunner.create() + .forwardStdOutput(tee(new OutputStreamWriter(System.out), outputWriter)) + .forwardStdError(tee(new OutputStreamWriter(System.err), errorOutputWriter)) + .withPluginClasspath() + .withProjectDir(testDirectory.toFile()) + .withArguments([*autoArgs, *args]) + if (gradleVersion) { + runner.withGradleVersion(gradleVersion) + } + if (debug) { + runner.withDebug(true) + } + runner + } + + private ArrayList computeAutoArgs() { + List autoArgs = [ + "-s", + "--console=verbose" + ] + if (Boolean.getBoolean("config.cache")) { + autoArgs << '--configuration-cache' + } + autoArgs + } + + private static Writer tee(Writer one, Writer two) { + return TeeWriter.of(one, two) + } + + void fails(String... args) { + try { + result = newRunner(args) + .buildAndFail() + } finally { + recordOutputs() + } + } + + private class TaskExecutionGraph { + void succeeded(String... tasks) { + tasks.each { task -> + contains(task) + assert result.task(task).outcome == TaskOutcome.SUCCESS + } + } + + void failed(String... tasks) { + tasks.each { task -> + contains(task) + assert result.task(task).outcome == TaskOutcome.FAILED + } + } + + void skipped(String... tasks) { + tasks.each { task -> + contains(task) + assert result.task(task).outcome == TaskOutcome.SKIPPED + } + } + + void contains(String... tasks) { + tasks.each { task -> + assert result.task(task) != null: "Expected to find task $task in the graph but it was missing" + } + } + + void doesNotContain(String... tasks) { + tasks.each { task -> + assert result.task(task) == null: "Task $task should be missing from the task graph but it was found with an outcome of ${result.task(task).outcome}" + } + } + } + + void usesProject(String name) { + File sampleDir = new File("src/test-projects/$name") + GFileUtils.copyDirectory(sampleDir, testDirectory.toFile()) + } + + File file(String path) { + new File(testDirectory.toFile(), path) + } +} diff --git a/build-logic/src/test/groovy/com/uwyn/rife2/gradle/PackagingTest.groovy b/build-logic/src/test/groovy/com/uwyn/rife2/gradle/PackagingTest.groovy new file mode 100644 index 0000000..e08ff3c --- /dev/null +++ b/build-logic/src/test/groovy/com/uwyn/rife2/gradle/PackagingTest.groovy @@ -0,0 +1,35 @@ +package com.uwyn.rife2.gradle + +import java.nio.file.FileSystems +import java.nio.file.Files + +class PackagingTest extends AbstractFunctionalTest { + def setup() { + usesProject("minimal") + } + + def "#archive contains compiled resources"() { + def jarFile = file(archive).toPath() + when: + run task + + then: "compiles templates are found in the archive" + tasks { + succeeded ":${Rife2Plugin.PRECOMPILE_TEMPLATES_TASK_NAME}" + } + Files.exists(jarFile) + try (def fs = FileSystems.newFileSystem(jarFile, [:])) { + fs.getRootDirectories().each { + Files.walk(it).forEach { path -> + println path + } + } + assert Files.exists(fs.getPath("/rife/template/html/hello.class")) + } + + where: + task | archive + 'jar' | 'build/libs/hello-1.0.jar' + 'uberJar' | 'build/libs/hello-uber-1.0.jar' + } +} diff --git a/build-logic/src/test/groovy/com/uwyn/rife2/gradle/TeeWriter.groovy b/build-logic/src/test/groovy/com/uwyn/rife2/gradle/TeeWriter.groovy new file mode 100644 index 0000000..89f60c1 --- /dev/null +++ b/build-logic/src/test/groovy/com/uwyn/rife2/gradle/TeeWriter.groovy @@ -0,0 +1,81 @@ +package com.uwyn.rife2.gradle + +import groovy.transform.CompileStatic + +@CompileStatic +class TeeWriter extends Writer { + private final Writer one + private final Writer two + + static TeeWriter of(Writer one, Writer two) { + new TeeWriter(one, two) + } + + private TeeWriter(Writer one, Writer two) { + this.one = one + this.two = two + } + + @Override + void write(int c) throws IOException { + try { + one.write(c) + } finally { + two.write(c) + } + } + + @Override + void write(char[] cbuf) throws IOException { + try { + one.write(cbuf) + } finally { + two.write(cbuf) + } + } + + @Override + void write(char[] cbuf, int off, int len) throws IOException { + try { + one.write(cbuf, off, len) + } finally { + two.write(cbuf, off, len) + } + } + + @Override + void write(String str) throws IOException { + try { + one.write(str) + } finally { + two.write(str) + } + } + + @Override + void write(String str, int off, int len) throws IOException { + try { + one.write(str, off, len) + } finally { + two.write(str, off, len) + } + } + + @Override + void flush() throws IOException { + try { + one.flush() + } finally { + two.flush() + } + } + + @Override + void close() throws IOException { + try { + one.close() + } finally { + two.close() + } + } +} diff --git a/build-logic/src/test/groovy/com/uwyn/rife2/gradle/TemplateCompilationTest.groovy b/build-logic/src/test/groovy/com/uwyn/rife2/gradle/TemplateCompilationTest.groovy new file mode 100644 index 0000000..12f14a6 --- /dev/null +++ b/build-logic/src/test/groovy/com/uwyn/rife2/gradle/TemplateCompilationTest.groovy @@ -0,0 +1,58 @@ +package com.uwyn.rife2.gradle + +class TemplateCompilationTest extends AbstractFunctionalTest { + def setup() { + usesProject("minimal") + } + + def "doesn't precompile templates when calling `run`"() { + given: + buildFile << """ + tasks.named("run") { + doFirst { + throw new RuntimeException("force stop") + } + } + """ + when: + fails 'run' + + then: "precompile templates task must not be present in task graph" + errorOutputContains("force stop") + tasks { + doesNotContain ":${Rife2Plugin.PRECOMPILE_TEMPLATES_TASK_NAME}" + } + } + + def "`run` task classpath includes template sources"() { + given: + buildFile << """ + tasks.register("dumpRunClasspath") { + doLast { + tasks.named("run").get().classpath.files.each { + println "Classpath entry: \$it" + } + } + } + """ + + when: + run("dumpRunClasspath") + + then: "template sources must be present in the classpath" + outputContains("Classpath entry: ${file("src/main/templates").absolutePath}") + } + + def "compiles templates when running #task"() { + when: + run task + + then: "precompile templates task must be present in task graph" + tasks { + succeeded ":${Rife2Plugin.PRECOMPILE_TEMPLATES_TASK_NAME}" + } + + where: + task << ['jar', 'test', 'uberJar'] + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..3a8c200 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,17 @@ +[versions] +jetty = "11.0.13" +jsoup = "1.15.3" +junit-jupiter = "5.9.1" +slf4j = "2.0.5" +spock = "2.3-groovy-3.0" + +[libraries] +jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "jetty" } +jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "jetty" } +jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" } +junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-jupiter" } +slf4j-simple = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j" } +spock-core = { module = "org.spockframework:spock-core", version.ref = "spock" } + +[bundles] +jetty = [ "jetty-server", "jetty-servlet" ] diff --git a/war/build.gradle.kts b/war/build.gradle.kts index 477784d..206f003 100644 --- a/war/build.gradle.kts +++ b/war/build.gradle.kts @@ -2,10 +2,9 @@ plugins { war } -version = 1.0 - base { archivesName.set("hello") + version = 1.0 } repositories { @@ -21,4 +20,4 @@ tasks.war { webAppDirectory.set(file("../app/src/main/webapp")) webXml = file("src/web.xml") rootSpec.exclude("**/jetty*.jar", "**/slf4j*.jar", "**/rife2*-agent.jar") -} +} \ No newline at end of file