This is an automated email from the ASF dual-hosted git repository. benweidig pushed a commit to branch javax in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
commit 6e1317f94d4f7501b6fb5a27ea0ee7154c231e84 Author: Ben Weidig <[email protected]> AuthorDate: Sun Apr 19 12:00:05 2026 +0200 TAP5-2809: buildSrc cleanup/documentation, Gradle 9 preparations --- build.gradle | 63 +++++----- buildSrc/README.md | 139 +++++++++++++++++++++ .../main/groovy/t5build/GenerateChecksums.groovy | 12 ++ buildSrc/src/main/groovy/t5build/NpmTask.groovy | 112 +++++++++++++++++ buildSrc/src/main/groovy/t5build/SSshExec.groovy | 21 ---- buildSrc/src/main/groovy/t5build/Scp.groovy | 36 ------ buildSrc/src/main/groovy/t5build/SshTask.groovy | 94 -------------- .../main/groovy/t5build/TapestryBuildLogic.groovy | 22 ---- .../main/groovy/tapestry.java-convention.gradle | 12 +- .../src/main/groovy/tapestry.ssh-convention.gradle | 15 --- quickstart/build.gradle | 59 +++++---- tapestry-cdi/build.gradle | 1 - 12 files changed, 338 insertions(+), 248 deletions(-) diff --git a/build.gradle b/build.gradle index f4a9cb764..b32c83b33 100755 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,4 @@ import t5build.GenerateChecksums -import t5build.TapestryBuildLogic import org.apache.tools.ant.filters.ReplaceTokens plugins { @@ -43,15 +42,16 @@ ext { 'tapestry-core', ] + // Set via GRADLE_OPTS='-Dci=true' in CI (see Jenkinsfile). + // Controls version suffix, deploy target, and if integration tests will run headless continuousIntegrationBuild = Boolean.getBoolean('ci') + stagingUrl = 'https://repository.apache.org/service/local/staging/deploy/maven2/' snapshotUrl = 'https://repository.apache.org/content/repositories/snapshots' doSign = !project.hasProperty('noSign') && project.hasProperty('signing.keyId') // apacheDeployUserName and apacheDeployPassword should be specified in ~/.gradle/gradle.properties - - def deployFlavor = TapestryBuildLogic.isSnapshot(project) ? 'snapshot' : 'apache' - + def deployFlavor = continuousIntegrationBuild ? 'snapshot' : 'apache' deployUsername = providers.gradleProperty("${deployFlavor}DeployUserName") deployPassword = providers.gradleProperty("${deployFlavor}DeployPassword") archiveDeployFolder = providers.gradleProperty('apacheArchivesFolder') @@ -64,18 +64,18 @@ ext { } // Provided so that the CI server can override the normal version number for nightly builds. -version = TapestryBuildLogic.tapestryVersion(project) +version = continuousIntegrationBuild ? tapestryMajorVersion + '-SNAPSHOT' : tapestryMajorVersion + tapestryMinorVersion // Specific to top-level build, not set for subprojects: configurations { javadoc - published.extendsFrom archives, meta + published.extendsFrom archives, meta if (doSign) { published.extendsFrom signatures } - binaries // additional dependencies included in the binary archive + binaries } dependencies { @@ -130,9 +130,8 @@ subprojects { } configurations { - // published -- what gets uploaded to the Nexus repository + // published: what gets uploaded to the Nexus repository published.extendsFrom archives, meta - if (rootProject.doSign) { published.extendsFrom signatures } @@ -150,8 +149,9 @@ subprojects { pom { name = project.name - // TODO: find some way to get the subproject description here. - // description = + description = providers.provider { + project.description + } url = 'https://tapestry.apache.org/' licenses { license { @@ -162,13 +162,12 @@ subprojects { scm { connection = 'scm:git:https://gitbox.apache.org/repos/asf/tapestry-5.git' developerConnection = 'scm:git://gitbox.apache.org/repos/asf/tapestry-5.git' - url = 'https://git-wip-us.apache.org/repos/asf?p=tapestry-5.git;a=summary' + url = 'https://git-wip-us.apache.org/repos/asf?p=tapestry-5.git' } // Changes the generated pom.xml so its dependencies on suffixed artifacts // get properly updated with suffixed artifact ids withXml { - def artifactIdQName = new groovy.namespace.QName( - 'http://maven.apache.org/POM/4.0.0', 'artifactId') + def artifactIdQName = new groovy.namespace.QName('http://maven.apache.org/POM/4.0.0', 'artifactId') def node = asNode() def dependencies = node.get('dependencies')[0] if (dependencies != null) { @@ -183,6 +182,7 @@ subprojects { } } } + if (canDeploy) { repositories { mavenLocal() @@ -209,8 +209,9 @@ subprojects { } } + // Modules not in suffixedArtifactNames have no -jakarta counterpart + // and should not be published when artifactSuffix is empty (i.e. the javax branch) def actuallyPublish = !artifactSuffix.isEmpty() || suffixedArtifactNames.contains(project.name) - // println 'XXXXXX Actually publish? ' + actuallyPublish + ' project ' + project.name + ' ' + '!artifactSuffix.isEmpty() ' + !artifactSuffix.isEmpty() if (!actuallyPublish) { tasks.withType(PublishToMavenRepository).configureEach { it.enabled = false @@ -233,7 +234,7 @@ subprojects { // Cribbed from https://github.com/hibernate/hibernate-core/blob/master/release/release.gradle#L19 tasks.register('aggregateJavadoc', Javadoc) { - group = 'Documentation' + group = 'documentation' description = 'Build the aggregated JavaDocs for all modules' dependsOn configurations.javadoc @@ -303,14 +304,14 @@ tasks.register('aggregateJavadoc', Javadoc) { } tasks.register('typeScriptDocs') { - group = 'Documentation' + group = 'documentation' description = 'Builds typedoc documentation for all TypeScript sources' dependsOn(':tapestry-core:generateTypeScriptDocs') } tasks.register('combinedJacocoReport', JacocoReport) { - group = 'Verification' + group = 'verification' description = 'Generates combined JaCoCo coverage report for all subprojects' def excludedProjects = [ @@ -329,7 +330,7 @@ tasks.register('combinedJacocoReport', JacocoReport) { def subprojectsToConsider = subprojects.findAll { !excludedProjects.contains(it.name) } - dependsOn subprojectsToConsider.test + dependsOn subprojectsToConsider.collect { it.tasks.named('check') } def classFiles = files(subprojectsToConsider.sourceSets.main.output).asFileTree.matching { exclude 'org/apache/tapestry5/internal/plastic/asm/**' @@ -338,9 +339,12 @@ tasks.register('combinedJacocoReport', JacocoReport) { additionalSourceDirs.from(files(subprojectsToConsider.sourceSets.main.allSource.srcDirs)) sourceDirectories.from(files(subprojectsToConsider.sourceSets.main.allSource.srcDirs)) - executionData.from(files(subprojectsToConsider.jacocoTestReport.executionData).filter { - it.exists() + // Glob picks up all exec files regardless of task name: test.exec, testNG.exec, etc. + executionData.from(subprojectsToConsider.collect { p -> + p.fileTree(p.layout.buildDirectory) { include 'jacoco/*.exec' } }) + + // Reuse the JaCoCo agent classpath that each subproject's jacocoTestReport task already resolved. jacocoClasspath = files(subprojectsToConsider.jacocoTestReport.jacocoClasspath) reports { @@ -357,7 +361,7 @@ tasks.register('combinedJacocoReport', JacocoReport) { } tasks.register('continuousIntegration') { - group = 'Verification' + group = 'verification' description = 'Runs a full CI build: assembles all artifacts, runs all checks, and generates aggregate reports.' def dependants = [ @@ -365,20 +369,16 @@ tasks.register('continuousIntegration') { 'tapestry-core:testWithJqueryAndRequireJsDisabled', 'tapestry-core:testWithPrototypeAndRequireJsEnabled', subprojects.check, // jQuery and Require.js enabled - combinedJacocoReport + combinedJacocoReport, + aggregateJavadoc ] - // tapestry-javadoc doesn't work with Java 8 anymore. That's why it's only added if != 8. - if (JavaVersion.current() != JavaVersion.VERSION_1_8) { - dependants << aggregateJavadoc - } - dependsOn(dependants) } tasks.register('zippedSources', Zip) { - group = 'Release artifact' + group = 'release artifact' description = "Creates a combined Zip file of all sub-project's sources" dependsOn 'tapestry-core:compileTypeScript' @@ -403,7 +403,7 @@ tasks.register('zippedSources', Zip) { } tasks.register('zippedApidoc', Zip) { - group = 'Release artifact' + group = 'release artifact' description = "Zip archive of the project's aggregate JavaDoc and TypeScript documentation" dependsOn typeScriptDocs @@ -474,7 +474,6 @@ if (canDeploy) { uploads.extendsFrom archives, signatures } - artifacts { archives zippedApidoc, zippedSources, zippedBinaries } @@ -524,7 +523,7 @@ if (canDeploy) { } tasks.register('updateBootstrap') { - group = 'Maintenance' + group = 'maintenance' description = 'Updates the included Bootstrap dependencies from GitHub' doLast { diff --git a/buildSrc/README.md b/buildSrc/README.md new file mode 100644 index 000000000..d5c83b7f8 --- /dev/null +++ b/buildSrc/README.md @@ -0,0 +1,139 @@ +# buildSrc: Tapestry Build Conventions + +Gradle convention plugins and build utilities shared across all subprojects. +All convention files live in `src/main/groovy/` as precompiled script plugins. + +--- + +## Convention hierarchy + +```text +tapestry.java-convention applied to every subproject by root build.gradle + └─ tapestry.testing-base-convention JUnit Platform runner, shared test config + ├─ tapestry.junit5-convention + Jupiter API + engine + │ ├─ tapestry.junit5-spock-convention + Spock BOM / spock-core + │ └─ tapestry.junit4-legacy-convention + Vintage engine (JUnit 4 tests) + └─ tapestry.testng-convention + TestNG + EasyMock + testng-engine +``` + +--- + +## Conventions + +### `tapestry.java-convention` + +Applied automatically to every subproject by the root `build.gradle`. + +* Java 11 source/target compatibility +* `provided` configuration (compile-only scope, like Maven `<scope>provided</scope>`) +* Dependency version constraints to keep library versions consistent across modules +* JAR manifest: `Automatic-Module-Name` (JPMS) and `LICENSE`/`NOTICE` in `META-INF` + +--- + +### `tapestry.testing-base-convention` + +Foundation for all test conventions. + +**Do not apply directly** + +Use one of the specialized conventions below. + +Configures every `Test` task in the project via `tasks.withType(Test)`: + +* JUnit Platform as the runner (required by all engines: Jupiter, TestNG, Vintage) +* `junit-platform-launcher` and the JUnit BOM on the runtime classpath +* Standard system properties: file encoding, locale, CI flag, Selenium wait timeout +* Consistent test logging: full exception format, pass/skip/fail events, progress counter + +### `tapestry.junit5-convention` + +Use when the module's test sources use JUnit 5 Jupiter (`@Test`, `@ExtendWith`, ...). + +Adds Jupiter API to the test compile classpath and the Jupiter engine at runtime. + +```groovy +plugins { + id 'tapestry.junit5-convention' +} +``` + +### `tapestry.junit5-spock-convention` + +Use when the module writes tests in Spock (Groovy BDD framework). + +Extends `junit5-convention` with the Spock BOM and `spock-core`. +Spock runs on the JUnit Platform — no additional runner config needed. + +```groovy +plugins { + id 'tapestry.junit5-spock-convention' +} +``` + +### `tapestry.junit4-legacy-convention` + +Use **only** for modules that still have JUnit 4 test sources (`@RunWith`, `@Rule`, ...). + +Extends `junit5-convention` with the JUnit Vintage engine, so legacy tests run alongside any Jupiter tests without touching test source code. +Prefer migrating tests over adding this convention to new modules. + +```groovy +plugins { + id 'tapestry.junit4-legacy-convention' +} +``` + +### `tapestry.testng-convention` + +Use when the module's test sources use TestNG annotations (`@Test`, `@BeforeMethod`, `@DataProvider`, ...). + +Adds TestNG and EasyMock to the test compile classpath. +The `testng-engine` dependency at runtime lets the standard `test` task (JUnit Platform) discover and run TestNG unit tests automatically. + +```groovy +plugins { + id 'tapestry.testng-convention' +} +``` + +#### Modules with Selenium integration tests + +When a module has both TestNG unit tests and Selenium integration tests, _native_ TestNG **must** be used for the integration tests! + +This is because Selenium tests currently rely on `@BeforeTest` / `ITestContext` scoping that only works correctly with the native TestNG runner and a `testng.xml` suite file. +Each `<test>` element gets its own server instance with the right webapp. + +The required additions to the module's `build.gradle`: + +```groovy +// Exclude integration classes from the JUnit Platform 'test' task +tasks.named('test') { + exclude '**/integration/**' // adjust pattern to match your integration tests +} + +// Native TestNG task: uses testng.xml for correct ITestContext grouping +tasks.register('testNG', Test) { + group = 'verification' + + useTestNG { + suiteXmlFiles << project.file('src/test/resources/testng.xml') + } +} + +// Include in the check lifecycle +tasks.named('check') { + dependsOn 'testNG' +} +``` + +The `testng.xml` suite file for these modules should contain **only** integration `<test>` elements. + +Unit tests are handled by the `test` task via testng-engine by Jupiter and must not appear in `testng.xml`. + +--- + +## Helper classes (`t5build` package) + +**`GenerateChecksums`**: custom Gradle task type that generates MD5/SHA-256 checksum +files for release archives. diff --git a/buildSrc/src/main/groovy/t5build/GenerateChecksums.groovy b/buildSrc/src/main/groovy/t5build/GenerateChecksums.groovy index dd9f9997f..9a54c0e8e 100644 --- a/buildSrc/src/main/groovy/t5build/GenerateChecksums.groovy +++ b/buildSrc/src/main/groovy/t5build/GenerateChecksums.groovy @@ -1,3 +1,15 @@ +// 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 t5build import org.gradle.api.DefaultTask diff --git a/buildSrc/src/main/groovy/t5build/NpmTask.groovy b/buildSrc/src/main/groovy/t5build/NpmTask.groovy new file mode 100644 index 000000000..4312e6284 --- /dev/null +++ b/buildSrc/src/main/groovy/t5build/NpmTask.groovy @@ -0,0 +1,112 @@ +// 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 t5build + +import org.gradle.api.tasks.Exec +import org.gradle.api.tasks.Internal + +/** + * Gradle task that runs an npm command, either via Docker or the local npm executable. + * <p> + * When Docker is available, the task mounts the project's {@code src/main} directory into + * a container and runs {@cpde npm} there, ensuring a consistent Node.js environment. + * <p> + * On Linux, the container process runs as the current host user to avoid file-ownership + * issues on mounted volumes. + * <p> + * When Docker is not available, the task falls back to invoking the local {@code npm} (or + * {@code npm.cmd} on Windows) directly. + * <p> + * The Docker image used can be overridden via the {@code nodeDockerImage} Gradle project + * property (defaults to {@code node:lts-alpine}). + * <p> + * Usage in a build script: + * <pre> + * tasks.register('npmInstall', NpmTask) { + * npmArgs = ['install'] + * } + * </pre> + */ +class NpmTask extends Exec { + + private static Boolean dockerAvailableCache = null + + /** + * Arguments passed to the npm command (e.g. {@code ['install']}). + */ + @Internal + List<String> npmArgs = [] + + /** + * Docker image used to run npm when Docker is available. + * <p> + * Default: {@code node:lts-alpine} + */ + @Internal + String nodeDockerImage = (project.findProperty('nodeDockerImage') ?: 'node:lts-alpine') as String + + NpmTask() { + workingDir = 'src/main/typescript' + } + + @Override + protected void exec() { + commandLine(buildCommand()) + super.exec() + } + + private List<String> buildCommand() { + return isDockerAvailable() ? buildDockerCommand() : [npmExecutable()] + npmArgs + } + + private List<String> buildDockerCommand() { + def cmd = [ + 'docker', 'run', '--rm', + '-v', "${project.projectDir}/src/main:/work", + '-w', '/work/typescript', + // The node:lts-alpine image has a root-owned /.npm cache baked in. + // Redirect to /tmp so the container user can always write to it. + '-e', 'NPM_CONFIG_CACHE=/tmp/.npm'] + if (isLinux()) { + cmd += ['--user', "${['id', '-u'].execute().text.trim()}:${['id', '-g'].execute().text.trim()}"] + } + cmd += [nodeDockerImage, 'npm'] + npmArgs + return cmd + } + + private static boolean isDockerAvailable() { + if (dockerAvailableCache == null) { + try { + def proc = ['docker', 'info'].execute() + proc.waitFor() + dockerAvailableCache = proc.exitValue() == 0 + } catch (Exception ignored) { + dockerAvailableCache = false + } + } + return dockerAvailableCache + } + + private static String npmExecutable() { + return isWindows() ? 'npm.cmd' : 'npm' + } + + private static boolean isWindows() { + return System.properties['os.name'].toLowerCase().contains('windows') + } + + private static boolean isLinux() { + def os = System.properties['os.name'].toLowerCase() + return !os.contains('windows') && !os.contains('mac') + } +} diff --git a/buildSrc/src/main/groovy/t5build/SSshExec.groovy b/buildSrc/src/main/groovy/t5build/SSshExec.groovy deleted file mode 100644 index e985b4591..000000000 --- a/buildSrc/src/main/groovy/t5build/SSshExec.groovy +++ /dev/null @@ -1,21 +0,0 @@ -package t5build - -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.TaskAction - -class SshExec extends SshTask { - - @Input - List<String[]> commandLines = [] - - void commandLine(String... commandLine) { - commandLines << commandLine - } - - @TaskAction - void doActions() { - commandLines.each { commandLine -> - ssh(*commandLine) - } - } -} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/t5build/Scp.groovy b/buildSrc/src/main/groovy/t5build/Scp.groovy deleted file mode 100644 index 3280cfb9d..000000000 --- a/buildSrc/src/main/groovy/t5build/Scp.groovy +++ /dev/null @@ -1,36 +0,0 @@ -package t5build - -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputFiles -import org.gradle.api.tasks.SkipWhenEmpty -import org.gradle.api.tasks.TaskAction -import java.io.File - -class Scp extends SshTask { - - @InputFiles @SkipWhenEmpty - def source - - @Input - String destination - - @Input - boolean isDir = false - - @TaskAction - void doActions() { - if (isDir) { - scpDir(source, destination) - return - } - project.files(source).each { doFile(it) } - } - - private void doFile(File file) { - if (file.isDirectory()) { - file.eachFile { doFile(it) } - } else { - scpFile(file, destination) - } - } -} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/t5build/SshTask.groovy b/buildSrc/src/main/groovy/t5build/SshTask.groovy deleted file mode 100644 index 769b32adf..000000000 --- a/buildSrc/src/main/groovy/t5build/SshTask.groovy +++ /dev/null @@ -1,94 +0,0 @@ -package t5build - -import org.gradle.api.DefaultTask -import org.gradle.api.file.FileCollection -import org.gradle.api.logging.LogLevel -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputFiles -import org.gradle.api.tasks.Internal - -abstract class SshTask extends DefaultTask { - - @InputFiles - FileCollection sshAntClasspath - - @Input - String host - - @Input - String userName - - // TODO: Passwords should not be plain @Input. - @Input - String password - - @Input - boolean verbose = false - - private boolean antInited = false - - protected void initAnt() { - if (antInited) { - return - } - ant.taskdef(name: 'scp', - classname: 'org.apache.tools.ant.taskdefs.optional.ssh.Scp', - classpath: sshAntClasspath.asPath, - loaderref: 'ssh') - - ant.taskdef(name: 'sshexec', - classname: 'org.apache.tools.ant.taskdefs.optional.ssh.SSHExec', - classpath: sshAntClasspath.asPath, - loaderref: 'ssh') - antInited = true - } - - protected void withInfoLogging(Closure action) { - def oldLogLevel = getLogging().getLevel() - getLogging().setLevel([LogLevel.INFO, oldLogLevel].min()) - try { - action() - } finally { - if (oldLogLevel != null) { - getLogging().setLevel(oldLogLevel) - } - } - } - - protected void scpFile(Object source, String destination) { - initAnt() - withInfoLogging { - // TODO: This keyfile is hardcoded and uses an old algorithm (dsa) - ant.scp(localFile: project.files(source).singleFile, - remoteToFile: "${userName}@${host}:${destination}", - keyfile: "${System.properties['user.home']}/.ssh/id_dsa", - verbose: verbose) - } - } - - protected void scpDir(Object source, String destination) { - initAnt() - withInfoLogging { - ant.sshexec(host: host, - username: userName, - password: password, - command: "mkdir -p ${destination}") - - ant.scp(remoteTodir: "${userName}@${host}:${destination}", - keyfile: "${System.properties['user.home']}/.ssh/id_dsa", - verbose: verbose) { - project.files(source).addToAntBuilder(ant, 'fileSet', FileCollection.AntType.FileSet) - } - } - } - - protected void ssh(Object... commandLine) { - initAnt() - withInfoLogging { - ant.sshexec(host: host, - username: userName, - password: password, - command: commandLine.join(' ')) - } - } -} diff --git a/buildSrc/src/main/groovy/t5build/TapestryBuildLogic.groovy b/buildSrc/src/main/groovy/t5build/TapestryBuildLogic.groovy deleted file mode 100644 index 13f9b935a..000000000 --- a/buildSrc/src/main/groovy/t5build/TapestryBuildLogic.groovy +++ /dev/null @@ -1,22 +0,0 @@ -package t5build - -import org.gradle.api.Project - -class TapestryBuildLogic { - - static boolean isSnapshot(Project project) { - return tapestryVersion(project).endsWith('SNAPSHOT') - } - - static boolean isWindows() { - return System.properties['os.name'].toLowerCase().contains('windows') - } - - static String tapestryVersion(Project project) { - String major = project.rootProject.ext.tapestryMajorVersion - String minor = project.rootProject.ext.tapestryMinorVersion - - boolean isCiBuild = project.rootProject.hasProperty('continuousIntegrationBuild') && project.rootProject.continuousIntegrationBuild - return isCiBuild ? major + '-SNAPSHOT' : major + minor - } -} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/tapestry.java-convention.gradle b/buildSrc/src/main/groovy/tapestry.java-convention.gradle index d06cbb6ca..6787f2a5b 100644 --- a/buildSrc/src/main/groovy/tapestry.java-convention.gradle +++ b/buildSrc/src/main/groovy/tapestry.java-convention.gradle @@ -1,3 +1,9 @@ +// Base convention applied to every subproject in root build.gradle via `subprojects {}` +// - Java 11 source/target compatibility +// - 'provided' configuration (compile-only scope, like Maven <scope>provided</scope>) +// - Dependency version constraints to keep the classpath consistent across modules +// - JAR manifest: Automatic-Module-Name for JPMS, LICENSE/NOTICE in META-INF + plugins { id 'java-library' id 'eclipse' @@ -13,7 +19,10 @@ java { } configurations { + // 'provided': on compile + test classpaths but excluded from the runtime jar/war. provided + + // 'meta': collects artifacts (e.g. sourcesJar) that should be published alongside the main jar. meta } @@ -53,7 +62,8 @@ tasks.withType(Jar).configureEach { into 'META-INF' } - // JPMS compatibility + // Stable module name for JPMS (e.g. tapestry-ioc → org.apache.tapestry.ioc). + // Keeps the module name consistent even if the JAR file is renamed. manifest { attributes("Automatic-Module-Name": "org.apache.tapestry.${project.name}" .replace('tapestry-', '') diff --git a/buildSrc/src/main/groovy/tapestry.ssh-convention.gradle b/buildSrc/src/main/groovy/tapestry.ssh-convention.gradle deleted file mode 100644 index 2f6aa7c8a..000000000 --- a/buildSrc/src/main/groovy/tapestry.ssh-convention.gradle +++ /dev/null @@ -1,15 +0,0 @@ -import t5build.SshTask - -// This configuration will hold the ant-jsch.jar at runtime -configurations { - sshAntTask -} - -dependencies { - sshAntTask libs.ant.jsch -} - -// Configure all SshTask instances to use the files from the configuration -tasks.withType(SshTask).configureEach { - it.sshAntClasspath = configurations.sshAntTask -} diff --git a/quickstart/build.gradle b/quickstart/build.gradle index ad2136526..199f93414 100644 --- a/quickstart/build.gradle +++ b/quickstart/build.gradle @@ -1,50 +1,55 @@ import org.apache.tools.ant.filters.FixCrLfFilter import org.apache.tools.ant.filters.ReplaceTokens -task copyGradleWrapper(type: Copy) { - ext.srcDir = file("$buildDir/wrapper") +tasks.register('copyGradleWrapper', Copy) { + group = 'build setup' + description = 'Copies Gradle wrapper files to archetype resources' + def srcDir = layout.buildDirectory.dir('wrapper') inputs.dir srcDir - outputs.dir file("$buildDir/resources/main/archetype-resources") + outputs.dir layout.buildDirectory.dir('resources/main/archetype-resources') from srcDir - into file("$buildDir/resources/main/archetype-resources") - + into layout.buildDirectory.dir('resources/main/archetype-resources') exclude '.gradle' } -task addGradleWrapper(type: Exec) { - workingDir "$buildDir/wrapper" - commandLine "${rootProject.projectDir}/gradlew", 'wrapper', '--gradle-version', '7.3' +tasks.register('addGradleWrapper', Exec) { + group = 'build setup' + description = 'Generates Gradle wrapper in temporary directory' + workingDir = layout.buildDirectory.dir('wrapper') + commandLine = ["${rootProject.projectDir}/gradlew", 'wrapper', '--gradle-version', '8.14.2'] standardOutput = new ByteArrayOutputStream() - ext.output = { - return standardOutput.toString() - } - doFirst { - def wrapperDirectory = new File(buildDir, "wrapper") + def wrapperDirectory = layout.buildDirectory.dir('wrapper').get().asFile wrapperDirectory.mkdirs() - def settings = new File(wrapperDirectory, "settings.gradle") - new FileOutputStream(settings).close(); + def settings = new File(wrapperDirectory, 'settings.gradle') + settings.createNewFile() } - finalizedBy 'copyGradleWrapper' + finalizedBy copyGradleWrapper } -task addWrappers(dependsOn: [addGradleWrapper]) { +tasks.register('addWrappers') { + group = 'build setup' + description = 'Coordinates wrapper generation tasks' + + dependsOn addGradleWrapper } -task processFiltered(type: Copy) { - ext.srcDir = file('src/main/resources-filtered') +tasks.register('processFiltered', Copy) { + group = 'build' + description = 'Processes filtered resources with token replacement' + def srcDir = layout.projectDirectory.dir('src/main/resources-filtered') inputs.dir srcDir - outputs.dir sourceSets.main.output.resourcesDir + outputs.dir layout.buildDirectory.dir('resources/main') from srcDir - into sourceSets.main.output.resourcesDir + into layout.buildDirectory.dir('resources/main') filter(FixCrLfFilter) filter(ReplaceTokens, tokens: [ @@ -55,7 +60,7 @@ task processFiltered(type: Copy) { jacksonVersion: libs.versions.jackson.get(), log4jVersion: libs.versions.quickstart.log4j.get(), yassonVersion: libs.versions.quickstart.yasson.get(), - servletVersion: libs.versions.javax.servlet.api.get(), + servletVersion: libs.versions.jakarta.servlet.api.get(), mavenCompilerVersion: libs.versions.quickstart.maven.compiler.get(), mavenSurefireVersion: libs.versions.quickstart.maven.surefire.get(), mavenWarVersion: libs.versions.quickstart.maven.war.get(), @@ -64,8 +69,10 @@ task processFiltered(type: Copy) { ]) } -processResources.dependsOn([addWrappers, processFiltered]) +tasks.named('processResources') { + dependsOn addWrappers, processFiltered +} -jar { - dependsOn(copyGradleWrapper) -} \ No newline at end of file +tasks.named('jar') { + dependsOn copyGradleWrapper +} diff --git a/tapestry-cdi/build.gradle b/tapestry-cdi/build.gradle index d40e22e16..1bfbd7a89 100644 --- a/tapestry-cdi/build.gradle +++ b/tapestry-cdi/build.gradle @@ -1,5 +1,4 @@ import org.gradle.plugins.ide.idea.model.* -import t5build.* description = "Bridge to CDI for Apache Tapestry 5 Project"
