Gradle multi-project build order using Kotlin script - java

I use Kotlin DSL script (.kts) for building. There the structure of my project is:
Root project 'demo'
+--- Project ':backend'
\--- Project ':frontend'
I need to build project frontend first, than backend. I tried
include(":frontend")
include(":backend)
and
include(":frontend", ":backend")
with and without : in settings.gradle.kts of root project, but still the order of build is alphabetical - backend, than frontend.
View source code on GitHub
Do you have any ideas what is wrong?

There is nothing wrong. If you don't specify any inter-project dependencies, Gradle will execute them in alphabetical order. This should be fine if the two projects are unrelated, as they are now.
But let's say you like to build the frontend (using node) and then include those resources in the backend (using Spring Boot). Then you will need to make the backend depend on frontend project. Then Gradle will honor the dependency graph and build the frontend first.
There are many ways to do that. One is to use the java plugin in the frontend to build a jar file of your frontend resources. You can then make a normal project dependency to it. You could also make a dependency directly into the frontend project's "internal" build tasks, but that is a bit frowned upon. Or you could declare your own artifact, or do a it in a bunch of other different ways.
For the first approach, you can build a jar file of your frontend resources like this:
plugins {
// ...
id("java")
}
java {
// Required to make the jar artifact compatible with your backend, which is configured for Java 1.8
targetCompatibility = JavaVersion.VERSION_1_8
}
tasks.named("jar", Jar::class) {
dependsOn("assembleFrontend")
from("$buildDir/dist")
into("static")
}
Then in the backend, depend on it like this:
dependencies {
// ...
runtimeOnly(project(":frontend"))
}
There are a few other things wrong with your build script as well.
The runtime configuration is deprecated; use runtimeOnly instead (for your spring-boot-devtools dependency).
A multi-project should only have a single settings.gradle file, but you have one in each project. Delete them except for the one in the root folder.
You have declared the org.siouan.frontend plugin twice: once using the recommended way and once using the "old" way. Remove the latter (everything in the buildscript block and the apply statement.
Also, while I am not familiar with the org.siouan.frontend plugin, it appears it does not declare inputs and outputs for you - probably because it is very generic. So to avoid running npm each time you build your backend (as you now have a dependency to the frontend), you should declare proper inputs and outputs for the frontend tasks like installFrontend and assembleFrontend.

Related

Publish jar to maven local and use this dependency in root project

Update
I would like to use external library that is not available on maven repository.
Currently, I have subproject called libs and within CLIPSJNI.jar
In Gradle.build of root project I declare dependency like this
dependencies {
implementation files('/libs/library.jar')
}
but in order to run java application I also have to add file with .jnilib.
My question is it possible to publish to maven local this jar and reuse this dependency. So that .jnilib is redundant.
Initial question was resolve. If you wanna use CLIPSJNI in java application there are only 2 steps you should follow, which are described in comments down below.

Gradle Plugin dependency

What is the exact dependency I need to develop a Gradle Plugin in Java? Ideally I would like to get it from a well-known repository such as Maven Central or similar.
I have a Maven project with a core functionality and I just added two extra plugins, one for Ant, one for Maven. They are already tested and working; easy! Now, I wanted to add a third module for a Gradle plugin to make this functionality also available from any Gradle project.
However, I can't find the exact dependencies I need to develop a Gradle plugin.
The Gradle docs (such as https://docs.gradle.org/current/userguide/java_gradle_plugin.html) are not very well written to say the least. They mention:
the gradleAPI() dependency
or the java-gradle-plugin dependency
But they are quite unclear... no group, no version (really?).
If anyone can enlighten me to where I can get these dependencies from, I would be very thankful.
Gradle's public and internal APIs, aka gradleApi(), are bundled with the Gradle distribution and not independently published and therefore not easily consumable by Maven builds. There's the pending epic #1156 (Ensure plugin cross-version compatibility by allowing a user to depend on gradlePublicApi()) that might help here.
Since Gradle plugins are best to be built with Gradle, a pragmatic solution is to invoke the Gradle build from Maven and attach the produced artifact to the Maven build. Andres Almiray (aalmiray) once described this in the blog post Running Gradle Inside Maven (Web Archive Link). He describes the following high level steps:
Create a new Maven module (e.g. gradle-plugin) and add attach it to the parent POM
In the POM of gradle-plugin add a dependency to your core module. Use the maven-dependency-plugin to store dependencies to the Maven build folder, e.g. target/dependencies.
Create the build.gradle, add a Maven repository that points to target/dependencies (step 2) and let it depend on the core module as well as gradleApi(). Implement the Gradle plugin.
Use the exec-maven-plugin to invoke the Gradle build.
Use the maven-resources-plugin to copy the Gradle built plugin jars to the standard Maven build folder.
Use the build-helper-maven-plugin to attach the copied jars to the Maven build.
Sample project to be found here (gradle-in-maven).
https://docs.gradle.org/current/userguide/custom_plugins.html#sec:custom_plugins_standalone_project
In here it is mentioned that it is gradleApi() and I know that this works (from experience). The localGroovy() on that page is only needed if your plugin code uses groovy (does not apply if you only use groovy in the build.gradle of your plugin).
java-gradle-plugin is a library that makes it a bit simpler to make plugins, it is not required though. I personally prefer using gradleApi only.
EDIT:
It appears I've misunderstood the question. Here are the steps to get gradleApi jar:
Create a Gradle project with your desired Gradle version.
Add implementation gradleApi() dependency.
Import/run the project once.
Go to your .gradle folder (located in home folder in Linux-based operating systems).
Open caches folder
Open the version folder you want, e.g. 6.0.1
Open generated-gradle-jars folder.
Copy the jar to wherever you want and use it.
For me the 6.0.1 jar is at ~/.gradle/caches/6.0.1/generated-gradle-jars/gradle-api-6.0.1.jar
Please note that I have not tested this, I know the jar is there but I haven't tried using it.

How do I include a gradle composite build into a multi project build?

I have a project that is a library (ProjectLib) and is used in many other projects. I have another project which is a multi project build (MultiProject) with a few sub projects (SubProj1, SubProj2, CoreProj). Some of these sub projects depend on the library project.
Normally I have the sub projects that depend on the library have the library specified in the dependency block of each of their build scripts and it fetches a built version of my library.
Sometimes I have to develop something in my library for this multi project and while doing this I would like to include the library as a composite build so that I can make changes and see the effect in the multi project build.
I have tried adding the path to my library in the settings.gradle of the root project using 'includeBuild' but this only half works.
What I tried is this:
MultiProject settings.gradle
include "SubProj1", "SubProj2", "CoreProj"
includeBuild "../ProjectLib"
SubProj1 and SubProj2 build.gradle
dependencies {
implementation project(":CoreProj")
implementation "com.myCompany:ProjectLib:1.0.0"
}
The build file for the CoreProj doesn't depend on the ProjectLib.
My ProjectLib normally builds to a private repo which is fetched by gradle and so typically version 1.0.0 would be included from this repo. What I would like to happen is that instead of fetching this version of the library, gradle instead includes the project in my local directory so that it has my latest changes without me having to build and release the library to the repo.
What I am getting at the moment is that the ProjectLib is being included in my IDE (I am using IntelliJ) but I get the following warning:
org.gradle.api.artifacts.UnknownConfigurationException: Configuration with name 'default' not found.
This warning appears twice for my MultiProject and the once each for SubProj1 and SubProj2. This also breaks up my project structure in my IDE so that it looks like only CoreProj is included in the multi project build MultiProject.
I am using gradle 5.5.1

What is the proper Gradle project structure for switching between 'project' and 'external' dependencies

I have this small set of libraries and app:
forge-base - java project (Intellij IDEA project)
forge-android - android library project, depends on forge-base (AS project)
forge-android-skeleton - sample android app, depends on forge-android (AS project)
During the initial development I used structure with project dependencies like:
settings.gradle:
...
include ':forge-base'
project(':forge-base').projectDir=new File("$settingsDir/../forge/base")
...
and then in build.gradle:
compile project(':forge-base')
This worked like a charm but later I needed to publish the libs on maven repo and dependencies had to be changed like:
build.gradle:
compile 'com.bolyartech.forge:forge-base:2.0-SNAPSHOT'
The problem that I am facing now is that I am trying to do some major refactoring in all the 3 projects and I need the old deps structure in order easily to confirm the consistency of the projects, e.g. to build just the skeleton app and all the recursive recompile/building to take place automatically (as it does when a lib project is referenced with compile project(':forge-base')). If I use the 'new' structure with publishing to the (local) maven I have to publish the lib each time (with incremented version) I change something in it in order changes to be visible by the other two projects.
What (is there) is the usual/canonical why to handle situations like this?
Is there an easy way to switch between the two 'modes', e.g. 'internal' / 'external' dependencies?
It turns out it is pretty easy to do it. You can use different dependencies for the different build types, i.e. debug/release so for example for my forge-android-skeleton project now I have the following:
in settings.gradle:
include ':app'
include ':forge-base' project(':forge-base').projectDir=new
File("$settingsDir/../../../forge/base")
include ':forge-android' project(':forge-android').projectDir=new
File("$settingsDir/../../../forge-android/forge-android")
in app/build.gradle:
...
releaseCompile ('com.bolyartech.forge:forge-android:2.7-SNAPSHOT')
debugCompile project(':forge-android')
...
Please note that in the settings.gradle you need to have all the dependencies back to the bottom otherwise it will not work (that is the reason forge-base is defined there even not excplicitly used).
You can also define yet another build type like direct-deps and use it in case you don't like to mess with debug/release types.
Please note that in case you are using different IDEs for some of the projects (like in my case IDEA and AS) probably it will be good idea to ensure that both are using same (version of) gradle otherwise unexpected problems may occur.

Does anyone know how to build a gradle parent project with subprojects that uses the tomcat plugin

I am devolping a parent java project with 3 subprojects. I am using gradle as its build tool. I am new to using gradle for my build tool.
I am trying to get it to when I run the parent project, the parent project and possibly two of the subprojects automatically run on a web application (Tomcat web container).
I found a helpful website https://github.com/bmuschko/gradle-tomcat-plugin/blob/master/README.md
I see that I have to add a few things to the parent projects build.gradle. For instance:
apply plugin: 'tomcat'
which defines the following tasks:
tomcatRun: Starts a Tomcat instance and deploys the exploded web application to it.
tomcatRunWar: Starts a Tomcat instance and deploys the WAR to it.
tomcatStop: Stops the Tomcat instance.
tomcatJasper: Runs the JSP compiler (Jasper) and turns JSP pages into Java source using.
I would need to run the "tomcatRun" and the "tomcatStop" task. Where should I declare each task? I think I should declare it under repositories { } tomcatRun { ...., but I am not sure. Is that where I would declare it? Do I have to declare the httpPort if my port is 8080? I ask, because 8080 is the default value and I am using the default value?
I have to declare the classpath for tomcat (classpath 'org.gradle.api.plugins:gradle-tomcat-plugin:0.9.7') inside the dependencies. Right?
For each of the subprojects that I want to add to tomcat, do I have to delare the classpath in their dependencies in their 'project' section (project (':subproject-a') { dependences { classpath ... ?
I added aplly plugin:'tomcat', but when I run it I get "Plugin with id 'tomcat' not found. What am I missing?
Where do I define the tomcat options?
[tomcatRun, tomcatRunWar]*.contextPath = 'stock-webservice'
[tomcatRun, tomcatRunWar, tomcatStop]*.stopPort = 8081
[tomcatRun, tomcatRunWar, tomcatStop]*.stopKey = 'stopKey'
Many of your questions should have been answered by the plugin's documentation. First of all, the tasks you mention are provided by the plugin. You do not need to declare them yourself. Run gradle tasks for a list of task available to your project. If a default is given for a property, then you don't need to provide it. Tomcat dependencies are assigned to the tomcat configuration. You can just copy/paste the relevant code from the README file. If the plugin cannot be found, that means you didn't declare the plugin dependency for your buildscript's classpath. Again you can copy/paste the relevant code from the documentation.
In general I'd recommend reading up on the Gradle online documentation first to get a better understanding of the tool.

Categories