How to ignore gradle build of root project for a multi-project Kotlin Spring Boot application? - spring-boot

Background:
I currently have a multi-module (multi-project) application repo. The "root" is not a runnable application. It's merely the source directory where I have a root build.gradle.kts file which holds the dependencies and plugins that are common between all my sub-projects. Each of my sub-projects have their own build.gradle.kts.
So my overall project structure looks sort of like this:
my_root_project
- gradle
- wrapper
- gradle-wrapper.jar
- gradle-wrapper.properties
- gradle.build.kts
- settings.gradle.kts
- my_nested_project_a
- src
- main
- kotlin
- my_nested_project_b
...
Issue:
Every time I run gradle build, I get an error saying:
> Task :bootJar FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':bootJar'.
> Main class name has not been configured and it could not be resolved
However when I run any one of my sub-projects (e.g. build :my_nested_project_a:build), it builds just fine.
Current Gradle Build Files
Here's what I currently have in the "root" gradle.build.kts:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
group = "com.example"
version = "1.0.0"
java.sourceCompatibility = JavaVersion.VERSION_1_8
java.targetCompatibility = JavaVersion.VERSION_1_8
plugins {
id("org.springframework.boot") version "2.1.8.RELEASE" apply false
id("io.spring.dependency-management") version "1.0.8.RELEASE" apply false
kotlin("jvm") version "1.3.50"
kotlin("plugin.spring") version "1.3.50"
kotlin("plugin.jpa") version "1.3.50"
kotlin("plugin.allopen") version "1.3.50"
}
allprojects {
repositories {
maven(url = "https://my.company.com/repo/with/all/the/stuff/I/need")
}
apply(plugin = "org.jetbrains.kotlin.jvm")
apply(plugin = "java")
apply(plugin = "org.springframework.boot")
apply(plugin = "io.spring.dependency-management")
apply(plugin = "org.jetbrains.kotlin.plugin.spring")
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "1.8"
}
}
}
NOTE: I'm using apply false on my plugins because I thought it would keep gradle from trying to find a main class when building using gradle build.
What I'm trying to do:
I have a CI pipeline that I'd like to simply run gradle build which should run the build task for all of the sub-projects. However, in that process, I'd like to ignore running the build for the "root" project or bypass it since it's not a runnable application, and just build the sub-projects.
Any help would be greatly appreciated! :)

If you want to ignore task bootJar,s o add the following configuration.
bootJar {
enabled = false
}

In your root build.gradle.kts, ignore bootJar task, with Kotlin DSL :
import org.springframework.boot.gradle.tasks.bundling.BootJar
tasks.getByName<BootJar>("bootJar") {
enabled = false
}

If you have the plugin applied in allprojects session, you're applying it to the root as well, and since it's the first one resolved in gradle build, you should have the main class configured there.
Alternatively, you can remove the apply(plugin = "org.springframework.boot") line from the root and apply the plugin only to the module that has the main method annotated with #SpringBootApplication, and point the plugin to the main class there.
Say your main class is in my_nested_project_a/src/main/com/example/MainClass.kt.
Your my_nested_project_a/build.gradle.kts should look like:
plugins {
id("org.springframework.boot")
}
springBoot {
mainClassName = "com.example.MainClass"
}
dependencies {
...
}
And you should remove this line from the root build.gradle.kts:
apply(plugin = "org.springframework.boot")

I have a similar setup and question. I replaced allprojects with subprojects and added jar.enabled(false) to the root build.gradle file and it worked.
plugins {
id("java-library")
id('org.jetbrains.kotlin.jvm') version "${kotlinVersion}"
id("com.diffplug.spotless") version "${spotlessVersion}"
id("maven-publish")
}
jar.enabled(false)
subprojects {
apply plugin: "java-library"
apply plugin: "org.jetbrains.kotlin.jvm"
apply plugin: "com.diffplug.spotless"
apply plugin: "maven-publish"
group = GROUP
version = VERSION_NAME
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
dependencies {
testImplementation 'org.jetbrains.kotlin:kotlin-test'
testImplementation("org.junit.jupiter:junit-jupiter:${junitVersion}")
}
publishing {
publications {
library(MavenPublication) {
from components.java
}
}
repositories {
maven {
url "https://gitlab.mhighpoint.com/api/v4/projects/${System.getenv('CI_PROJECT_ID')}/packages/maven"
credentials(HttpHeaderCredentials) {
name = "Job-Token"
value = System.getenv('CI_JOB_TOKEN')
}
authentication {
header(HttpHeaderAuthentication)
}
}
}
}
spotless {
java {
googleJavaFormat() // googleJavaFormat('1.1') to specify a specific version
}
kotlin {
target '**/src/**/*.kt'
ktlint("0.41.0").userData('disabled_rules': 'no-wildcard-imports,import-ordering')
trimTrailingWhitespace()
indentWithSpaces()
endWithNewline()
}
format 'misc', {
target '**/*.gradle'
trimTrailingWhitespace()
indentWithSpaces() // or spaces. Takes an integer argument if you don't like 4
endWithNewline()
}
}
test {
useJUnitPlatform()
}
jar {
archiveBaseName = "${rootProject.name}-${project.name}"
}
tasks {
assemble.dependsOn(spotlessApply)
}
}

Related

Gradle dependency resolution issue

I am converting a project from Maven to Gradle.
Here is my gradle.build file
plugins {
id 'java'
id 'maven-publish'
id "org.jetbrains.kotlin.jvm" version "1.5.30"
id "org.jetbrains.kotlin.plugin.spring" version "1.5.30"
id 'org.springframework.boot' version "2.5.4"
id 'io.spring.dependency-management' version "1.0.11.RELEASE"
}
group = 'com.aeonai.lib'
version = '1.0.0'
description = 'Aeon AI Library'
java.sourceCompatibility = JavaVersion.VERSION_1_8
repositories {
mavenCentral()
maven {
url = uri 'https://repo.osgeo.org/repository/release/'
}
maven {
url = uri 'https://repo.maven.apache.org/maven2/'
}
}
dependencies {
...
implementation 'org.geotools:gt-cql:25.2:sources#jar'
implementation 'org.geotools:gt-epsg-hsql:25.2:sources#jar'
implementation 'org.geotools:gt-geojson:25.2:sources#jar'
implementation 'org.geotools:gt-main:25.2:sources#jar'
implementation 'org.geotools:gt-opengis:25.2:sources#jar'
implementation 'org.geotools:gt-shapefile:25.2:sources#jar'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
...
}
configurations {
all {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
}
}
bootRun.enabled = false
bootJar {
mainClass.set('NONE')
}
publishing {
publications {
maven(MavenPublication) {
from(components.java)
}
}
}
test {
useJUnitPlatform()
}
I am importing many of the geotools from https://repo.osgeo.org/repository/release/.
When I run gradle build all of my dependency show up as they should, but the build still fails. The compiler cannot find some of the dependencies (which I have added in a screenshot below), although I can see the files in the External Libraries tree (also in a screenshot below). I can also see the libraries in the ~/.gradle/caches.
Here is a screenshot of the files not being found.
Here is another screenshot of the files in the tree.
Why is gradle/compiler not recognizing the file is there? What else am I missing?

How to setup a multi-module gradle project with Quarkus?

A multi-module gradle project with the Quarkus plugin applied in the root build.gradle.kts fails at the :quarkusBuild step with a NoSuchElementException:
> Task :quarkusBuild FAILED
building quarkus jar
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':quarkusBuild'.
> java.util.NoSuchElementException
The root build.gradle.kts is like so:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm") version "1.3.72"
id("io.quarkus") version "1.9.1.Final"
}
group = "org.example"
version = "1.0-SNAPSHOT"
allprojects {
repositories {
mavenCentral()
}
}
subprojects {
apply {
plugin("kotlin")
}
dependencies {
implementation(kotlin("stdlib"))
}
}
However move the line id("io.quarkus") version "1.9.1.Final" to the sub projects' build.gradle.kts and the build succeeds. It seems that the quarkus build step is run where the plugin is declared, rather than where it is actually applied.
Ideally I want to declare the plugin once in the root, then apply it to subprojects only, not have it execute against the root project, where there's obviously nothing to build.
Any ideas?
You need to add apply false
plugins {
kotlin("jvm") version "1.3.72" apply false
id("io.quarkus") version "1.9.1.Final" apply false
}
https://docs.gradle.org/current/userguide/plugins.html#sec:subprojects_plugins_dsl
Your build also assumes that every sub-module will be a Kotlin module which may or may not be true. You can do something a little more like this to apply specific configurations to specific tasks:
subprojects { subproject ->
subproject.tasks.withType(JavaCompile).configureEach {
sourceCompatibility = JavaVersion.VERSION_11
}
subproject.tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11
}
}
}

How do you disable distZip in a multi project builds on Kotlin DSL in Gradle

I have set up a Gradle multi project build using Kotlin DSL. This is build.gradle.kts in the root:
plugins {
kotlin("jvm") version "1.2.70" apply false
}
allprojects {
repositories {
mavenCentral()
}
}
subprojects {
version = "1.0"
}
This is sub/build.gradle.kts in my sub project:
plugins {
application
kotlin("jvm")
}
application {
mainClassName = "me.package.MainKt"
}
dependencies {
compile(kotlin("stdlib"))
compile("io.github.microutils:kotlin-logging:1.6.10")
compile("ch.qos.logback:logback-classic:1.2.3")
}
When I run $ gradle build the application plugin creates me a distribution in sub/build/distribution.
I don't need the zip distribution and I want no version number in the tar distribution. Both should be trivial in the regular build.gradle like:
distZip.enabled = false
distTar.archiveName = "${project.name}.tar"
Whatever I try using Kotlin DSL, I get Unresolved reference: distZip. How do I address the distZip and distTar tasks?
What you need is:
val distZip by tasks
distZip.enabled = false
val distTar by tasks
distTar.archiveName = "${project.name}.tar"
or:
tasks.getByName<Zip>("distZip").enabled = false
tasks.getByName<Tar>("distTar").archiveName = "${project.name}.tar"

Allure report is empty when use Allure2+Junit5+Gradle+Selenide

My build.gradle is:
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'org.junit.platform.gradle.plugin'
apply plugin: 'io.qameta.allure'
defaultTasks 'clean', 'test'
ext.junitJupiterVersion = '5.0.0-M4'
ext.selenideVersion = '4.4.3'
compileTestJava {
sourceCompatibility = 1.8
targetCompatibility = 1.8
options.encoding = 'UTF-8'
options.compilerArgs += "-parameters"
}
compileJava.options.encoding = 'UTF-8'
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
repositories {
jcenter()
mavenCentral()
}
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0-M4'
classpath 'io.qameta.allure:allure-gradle:2.3'
}
}
allure {
aspectjweaver = true
autoconfigure = true
version = '2.1.1'
}
configurations {
agent
}
dependencies {
// JUnit5
compile("org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}")
compile("org.junit.jupiter:junit-jupiter-engine:${junitJupiterVersion}")
// Selenide
compile("com.codeborne:selenide:${selenideVersion}") {
exclude group: 'junit'
}
// Allure
agent 'org.aspectj:aspectjweaver:1.8.10'
compile 'ru.yandex.qatools.allure:allure-junit-adaptor:1.4.23'
compile 'io.qameta.allure:allure-junit5:2.0-BETA6'
}
junitPlatform {
platformVersion = "1.0.0-M5"
enableStandardTestTask = true
}
task runJupiter(type: JavaExec) {
jvmArgs '-ea'
jvmArgs "-javaagent:${configurations.agent.singleFile}"
classpath = project.sourceSets.test.runtimeClasspath
main 'org.junit.platform.console.ConsoleLauncher'
args '--scan-class-path'
args "--reports-dir=${buildDir}/allure-results"
finalizedBy 'allureReport'
}
test.dependsOn runJupiter
Tests are finished successfully and three folders are created automatically:
{projectDir}\allure-results with .json file
{projectDir}\build\test-results\junit-platform with TEST-junit-jupiter.xml file
{projectDir}\build\reports\allure-report
I tried to open .json and .xml result locally via allure command line (CLI). The allure report is opened but it is blank:
this is a report view
I suppose my mistake in gradle dependencies. I quite confused which libraries and versions should be used for JUnit5+Allure2+Gradle+Selenide+Java8?
The JUnit Platform Gradle plugin does currently not use the test task (it needs changes in Gradle core in order to do so). Thus, things like test.doFirst {...} are not going to work.
Instead of using the plugin, you should be able to create your own task that runs the ConsoleLauncher and add the JVM agent there. See https://stackoverflow.com/a/43512503/6327046 for an example.

Publish Java artifact to Maven Local with Gradle

I am facing a problem when trying to install a generated jar into my local Maven Repository. The message error just show me 'task 'publish' is not found'
I am using this Gradle Script:
buildscript {
ext {
springBootVersion = '1.3.2.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'
apply plugin: 'maven-publish'
jar {
baseName = 'mongofoundry'
version = '1.0.0'
}
sourceCompatibility = 1.7
targetCompatibility = 1.7
repositories {
mavenCentral()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter-data-mongodb')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
}
eclipse {
classpath {
containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7'
}
}
task wrapper(type: Wrapper) {
gradleVersion = '2.9'
}
Do you have some idea Why I am reading that error message?
Thanks.
UPDATED
Running the command as #RaGe mentioned, solved the problem:
gradle publishToMavenLocal
The correct task to publish artifacts to local maven is
gradle publishToMavenLocal
Check Maven locally
For developing and testing it is useful to check library locally
gradle settings for apply plugin: 'com.android.library' not apply plugin: 'java-library'(where you can use it by default)
apply plugin: 'maven-publish'
//simple settings
project.afterEvaluate {
publishing {
publications {
library(MavenPublication) {
//setGroupId groupId
setGroupId "com.company"
//setArtifactId artifactId
setArtifactId "HelloWorld"
version "1.1"
artifact bundleDebugAar
/* add a dependency into generated .pom file
pom.withXml {
def dependenciesNode = asNode().appendNode('dependencies')
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', 'com.company')
dependencyNode.appendNode('artifactId', 'HelloWorld-core')
dependencyNode.appendNode('version', '1.1')
}
*/
}
}
}
}
to run it using command line or find this command in Gradle tab
./gradlew publishToMavenLocal
Location
artefact will be added into .m2 folder
//Unix
~/.m2
//Windows
C:\Users\<username>\.m2
//For example
/Users/alex/.m2/repository/<library_path>/<version>/<name>.<extension>
build folder
<project_path>/build/outputs/<extension>
other repositories location
~/.gradle/caches/modules-2/files-2.1/<group_id>/<artifact_id>/<version>/<id>
//For example
/Users/alex/.gradle/caches/modules-2/files-2.1/com.company/HelloWorld/1.1/c84ac8bc425dcae087c8abbc9ecdc27fafbb664a
To use it add mavenLocal(). It is important to place it as a first item for prioritise it, which is useful for internal dependencies
buildscript {
repositories {
mavenLocal()
}
allprojects {
repositories {
mavenLocal()
}
}
and
dependencies {
implementation 'com.company:HelloWorld:+'
}
*Also remember if you use a kind of shared.gradle file (via apply from) you should set path which is relevant to project.gradle (not shared.gradle)
[iOS CocoaPod local]
This is how I did it with Kotlin DSL (build.gradle.kts) for my Android library:
plugins {
id("maven-publish")
// OR simply
// `maven-publish`
// ...
}
publishing {
repositories {
// Local repository which we can first publish in it to check artifacts
maven {
name = "LocalTestRepo"
url = uri("file://${buildDir}/local-repository")
}
}
publications {
// ...
}
}
You can create all the publications with the following command:
./gradlew publishAllPublicationsToLocalTestRepoRepository
Or just a single publication with this command:
./gradlew publishReleasePublicationToLocalTestRepoRepository
See Gradle documentations: Maven Publish Plugin for more information.
Add maven plugin to your project and then:
gradle clean install
Here is an alternative skeleton for Gradle 7.5.1 with Java 17
build.gradle
plugins {
id 'org.gradle.java'
id 'org.gradle.maven-publish'
}
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
withJavadocJar()
withSourcesJar()
}
publishing {
publications {
mavenJava(MavenPublication) {
groupId = 'your-group'
artifactId = 'your-artifact'
version = "0.0.1"
from components.java
}
}
repositories {
mavenLocal()
}
}
Publishing
You can see more details on the publishing steps with --info
./gradlew --info publishToMavenLocal
Output Directory
Linux/macOS
/Users/<username>/.m2/repository/your-group/your-artifact/0.0.1
Windows
C:\Users\<username>\.m2\repository\your-group\your-artifact\0.0.1

Resources