I'm used to Maven but currently I'm using Gradle and I'm not really sure how to call tasks defined by other plugins. (Edit: I'm able to call these tasks in the CLI, but I'd like to also invoke them in my own, custom-defined tasks.)
But I'm importing this plugin to format (and enforce format) of my Java project; the tasks I'm most interested in calling are goJF and verGJF.
I've tried a few ways to either call included tasks and I've done even more Googling. I can share some of the (probably embarrassing) ways I've tried to call other tasks if it's helpful, but figured that might be unnecessary information at this point.
Here is my build.gradle:
plugins {
id 'java'
// https://github.com/sherter/google-java-format-gradle-plugin
id 'com.github.sherter.google-java-format' version '0.9'
}
group 'org.example'
version '1.0-SNAPSHOT'
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
repositories {
mavenCentral()
}
dependencies {
implementation("com.google.guava:guava:30.0-jre")
testImplementation(platform('org.junit:junit-bom:5.7.0'))
testImplementation('org.junit.jupiter:junit-jupiter:5.7.0')
}
// Alias for goJF:
task fmt {
goJF
}
// Alias for verGJF:
task vfmt {
verGJF
}
test {
useJUnitPlatform()
}
Working example here.
From the documentation, we note that there are examples of configuring the plugin tasks. So aliasing is a simplification of that approach. Consider:
plugins {
id 'java'
// https://github.com/sherter/google-java-format-gradle-plugin
id 'com.github.sherter.google-java-format' version '0.9'
}
import com.github.sherter.googlejavaformatgradleplugin.GoogleJavaFormat
import com.github.sherter.googlejavaformatgradleplugin.VerifyGoogleJavaFormat
group 'org.example'
version '1.0-SNAPSHOT'
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
repositories {
mavenCentral()
}
dependencies {
implementation("com.google.guava:guava:30.0-jre")
testImplementation(platform('org.junit:junit-bom:5.7.0'))
testImplementation('org.junit.jupiter:junit-jupiter:5.7.0')
}
task fmt(type: GoogleJavaFormat) {
}
task vfmt(type: VerifyGoogleJavaFormat) {
}
test {
useJUnitPlatform()
}
Here fmt is a new task of type GoogleJavaFormat; vfmt is of type VerifyGoogleJavaFormat. These instances can specify their own configuration (and do other things with doFirst, doLast, etc). But as-is, they act as aliases.
A few distinctions to begin with. The built in tasks defined by the plugin are called googleJavaFormat and verifyGoogleJavaFormat.
These tasks are immediately available to you once you have included the plugin which it seems you have done correctly from what I can see.
On the gradle command line, gradle implements a abbreviation functionality where you can call things with shorthand like:
~> gradle gooJF
which is shorthand for:
~> gradle googleJavaFormat
but this only works on the command line and only as long as your shorthand uniquely identifies a task name.
So when you work with tasks in the build.gradle file you will need to use the full name.
In gradle you create a new task via:
task SomeTaskName(type: SomeClassImplementingTheTask) {
// some configuration of the task
}
In your case you would want to do one of two things:
configure the two existing tasks added by the plugin so that they do what you want or if the tasks already do what they should, you might not need to configure them and can just run them as is.
create your own tasks with your own names but using the implementing classes (i.e. replacing SomeClassNameImplementingTheTask above with GoogleJavaFormat or VerifyGoogleJavaFormat) defined by the plugin.
The simplest of the two is to configure the already existing tasks. This can be done as follows:
googleJavaFormat {
source = sourceSets*.allJava
source 'src/special_dir'
include '**/*.java'
exclude '**/*Template.java'
exclude 'src/test/template_*'
}
The googleJavaFormat used here is actually a "plugin extension" which is exposed by the plugin. Plugin extensions are explicitly there for you to be able to alter the behavior of the plugin through configuration.
Note that the configurations options I defined are just examples, there are probably more things you can set here. The above would modify the two existing tasks with your custom settings and you could then call them from the command line using:
~> gradle googleJavaFormat
and
~> gradle verifyGoogleJavaFormat
Again, perhaps you don't even need to configure things and in that case you should just be able to call the tasks as in the above example.
Related
I am trying to create a task in my build that will list all the runtimeClasspath dependencies before it builds the project. So basically, it should be the equivalent of the following command but for all the subprojects:
gradle dependencies --configuration runtimeClasspath
So far I have managed to come up with a task that lists all the dependencies:
subprojects {
task listDependencies(type: DependencyReportTask) {}
complileJava.dependsOn listDependencies
}
It works great in the sense that it lists all the dependencies of all the subprojects, but as mentioned above, it also lists a lot of stuff I don't need to see.
How do I limit the output of the above task to just runtimeClasspath?
Thanks!
Since you are defining a task of type DependencyReportTask, you can configure its configuration property, which will be the equivalent of the --configuration flag on the CLI.
So something like:
subprojects {
def listDeps = tasks.register("listDependencies", DependencyReportTask) {
setConfiguration("runtimeClasspath")
}
tasks.withType(JavaCompile).configureEach {
dependsOn(listDeps)
}
}
Note however that printing the runtimeClasspath before executing compileJava is a bit weird. The classpath used by the compile task will be compileClasspath.
Edited to use lazy task API as there is otherwise an ordering problem with plugin application
A Kotlin version of the above accepted answer:
val listDeps = tasks.register<DependencyReportTask>("listDependencies") {
setConfiguration("compileClasspath")
}
tasks.withType<JavaCompile> {
dependsOn(listDeps)
}
I might be missing something major here. However, I am struggling to publish a simple library to a maven repository (which will be consumed by other maven based projects in the organization)
The best guide I've found is on the official Gradle website: https://docs.gradle.org/current/userguide/publishing_maven.html
However, there are still many unanswered questions:
Is there no way to differentiate between SNAPSHOT and release builds other than to manually include the if-else statement?
What is from components.java? IDEA gives no autocomplete or documentation on most of these DSLs (unlike Maven, where the code intelligence works well)
How do I publish to a private repository that requires authentication? I understand somewhere there must be a block that uses:
username = "${artifactory_user}"
password = "${artifactory_password}"
With the values being read from ~/.gradle/gradle.properties
But where do I put this block?
Overall, I feel like I a missing something here, maybe some documentation that is popularly read ... using maven itself the process is fairly straight-forward and the official documentation makes the process relatively painless
With Gradle, I feel like the simplest publish to a repository requires quite a lot what feels like customized logic when my intuition says something so common must already be encapsulated in a plugin with reasonable defaults
I see you've found your solution already, but my answer will aim to give you detailed answers to your questions.
Is there no way to differentiate between SNAPSHOT and release builds other than to manually include the if-else statement?
Correct. An if-else statement is exactly what you need to distinguish between a snapshot and release build. Gradle itself does not provide any sort of versioning functionality. That is left to you to handle or a plugin such as Nebula Release.
What is from components.java
The from is a method call from AbstractCopyTask which the Jar task type is a subclass of.
components is again another method call. You are actually calling getComponents() of Project.
components.java is sugar for components.getByName("java"). This works because of dynamic/magic of Groovy.
IDEA gives no autocomplete or documentation on most of these DSLs (unlike Maven, where the code intelligence works well)
This is due to the dynamic/weak typing of Groovy. The build.gradle file is written using Groovy. IntelliJ does try to infer the type of your build script, but it can't fully. Luckily you can now write your build script using Kotlin:
https://guides.gradle.org/migrating-build-logic-from-groovy-to-kotlin/
https://docs.gradle.org/current/userguide/kotlin_dsl.html
I highly suggest using the Kotlin DSL going forward. You will know exactly where everything is coming from.
How do I publish to a private repository that requires authentication?
Unfortunately the docs for the maven-publish plugin merely mentions it in a single sentence. Even so, it just directs you to API docs which aren't always helpful, but you were able to figure it out.
https://docs.gradle.org/current/userguide/publishing_maven.html
You can also configure any authentication details that are required to connect to the repository. See MavenArtifactRepository for more details.
And finally:
(...) the values being read from ~/.gradle/gradle.properties
Gradle will go out of its way to resolve a property. gradle.properties is just one of many locations that Gradle will look for properties. You can see more details under the Properties section on top here.
I'd like to finish off by providing a complete example of your answer using the Kotlin DSL. Also using the buildscript { } is a legacy method of applying plugins as noted here. You should use the newer/preferred plugins { } block going forward. More info here.
plugins {
`maven-publish`
id("org.jetbrains.kotlin.jvm") version "1.3.31"
}
group = "com.company"
version = "1.0.0-SNAPSHOT"
tasks.wrapper {
gradleVersion = "5.6.1"
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
}
val sourcesJar by tasks.registering(Jar::class) {
archiveClassifier.set("sources")
from(sourceSets.main.get().allSource)
}
repositories {
mavenCentral()
}
publishing {
publications {
register<MavenPublication>("mavenJava") {
artifactId = "some-artifactId"
from(components["java"])
artifact(sourcesJar.get())
pom {
name.set("Project Name")
}
}
}
repositories {
maven {
url = uri("https://company.jfrog.io/company/maven-local")
credentials {
username = property("artifactory_user") as String
password = property("artifactory_password") as String
}
}
}
}
val test by tasks.getting(Test::class) {
useJUnitPlatform()
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
// ...
}
To answer my own question here is the bare bones minimum to publish to a private repo:
buildscript {
ext.kotlin_version = '1.3.41'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
plugins {
id 'java-library'
id 'maven-publish'
}
apply plugin: 'kotlin'
group 'com.company'
version '1.0.0-SNAPSHOT'
wrapper {
gradleVersion = '4.9'
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
}
task sourcesJar(type: Jar, dependsOn: classes) {
classifier = 'sources'
from sourceSets.main.allSource
}
repositories {
mavenCentral()
}
publishing {
publications {
mavenJava(MavenPublication) {
artifactId = 'some-artifactId'
from components.java
artifact sourcesJar
pom {
name = 'Project Name'
}
}
}
repositories {
maven {
url = "https://company.jfrog.io/company/maven-local"
credentials {
username = "${artifactory_user}"
password = "${artifactory_password}"
}
}
}
}
test {
useJUnitPlatform()
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
compile "com.squareup.moshi:moshi-kotlin:1.8.0"
compile "com.squareup.moshi:moshi-adapters:1.8.0"
compile "com.squareup.okhttp3:okhttp:4.0.1"
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.1.0"
}
I have been following this tutorial - https://mcforge.readthedocs.io/en/latest/gettingstarted/
- and I am stuck on this section - Launch IDEA and choose to open/import the build.gradle file, using the default gradle wrapper choice. While you wait for this process to finish, you can open the gradle panel, which will get filled with the gradle tasks once importing is completed.
How do I import the build.gradle file? what is the build.gradle file? what does it do? I am new to coding, any help is appreciated. thx
Launch IDEA and select "File" → "New" → "Project from Existing Sources"
Select build.gradle file from the unpacked archive from the site you've provided
Check wrapper settings on the next screen. Leave the defaults.
Wait till IDEA builds the projects and makes indexes.
Happy hacking!
build.gradle is basically a build configuration file. It describes the way a piece of software is made. Like: where is the source code, what are the project's dependencies, where to get and how to link them, how to test and so on.
Speaking about particular build.gradle from forge-mdk:
buildscript {
repositories {
jcenter()
maven { url = "https://files.minecraftforge.net/maven" }
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
}
}
apply plugin: 'net.minecraftforge.gradle.forge'
This part applies net.minecraftforge.gradle.forge plugin that, I guess, is used to build Minecraft mods. As this is a third-party plugin buildscript block adds a repository (https://files.minecraftforge.net/maven) where it can be downloaded.
version = "1.0"
group = "com.yourname.modid" // http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = "modid"
This part describes the result ("artifact") of the projects. It has version 1.0, name modid and will be published (if published) under com.yourname.modid group. This is a Maven related vocabulary. I guess, you'll need to replace this values with your own.
sourceCompatibility = targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
compileJava {
sourceCompatibility = targetCompatibility = '1.8'
}
Here you state that the projects is built with Java 8
minecraft {
version = "1.12.2-14.23.5.2775"
runDir = "run"
mappings = "snapshot_20171003"
}
Here you configure net.minecraftforge.gradle.forge plugin that you've added previously. Basically, any plugin can expose it's own configuration block and you'll need to read the docs to know what do the values mean.
dependencies {
…
}
The project has no dependencies yet, thus empty dependencies block
processResources {
// this will ensure that this task is redone when the versions change.
inputs.property "version", project.version
inputs.property "mcversion", project.minecraft.version
// replace stuff in mcmod.info, nothing else
from(sourceSets.main.resources.srcDirs) {
include 'mcmod.info'
// replace version and mcversion
expand 'version':project.version, 'mcversion':project.minecraft.version
}
// copy everything else except the mcmod.info
from(sourceSets.main.resources.srcDirs) {
exclude 'mcmod.info'
}
}
Here you configure built-int processResources task that… processes resources. As you see, things are self-descriptive in Gradle. Tasks are Java classes that has documentation. For example, here are the docs for ProcessResources. One more link for DSL reference
Hope this answer will get you some info to start with!
I have a gradle project with 8 child projects and a configured shadowjar task to create an "all" jar. The toplevel project is setup to have dependencies to all its children, this tells shadowjar what to include:
project(':') {
dependencies {
compile project(':jfxtras-agenda')
compile project(':jfxtras-common')
compile project(':jfxtras-controls')
compile project(':jfxtras-icalendarfx')
compile project(':jfxtras-icalendaragenda')
compile project(':jfxtras-menu')
compile project(':jfxtras-gauge-linear')
compile project(':jfxtras-font-roboto')
}
}
shadowJar {
classifier = null // do not append "-all", so the generated shadow jar replaces the existing jfxtras-all.jar (instead of generating jfxtras-all-all.jar)
}
This works fine, but maven central is refusing the all jar, because it does not have an associated sources and javadocs jar.
How do I tell gradle to also generate the sources and javadoc? ShadowJar's documentation says it should do this by default.
The shadow plugin doesn't seem to have a feature of building a fat sources/javadocs jars.
Below, I provide a few short tasks (javadocJar and sourcesJar) that will build fat javadoc and source jars. They are linked to be always executed after shadowJar. But it has no dependency on the shadow jar plugin.
subprojects {
apply plugin: 'java'
}
// Must be BELOW subprojects{}
task alljavadoc(type: Javadoc) {
source subprojects.collect { it.sourceSets.main.allJava }
classpath = files(subprojects.collect { it.sourceSets.main.compileClasspath })
destinationDir = file("${buildDir}/docs/javadoc")
}
task javadocJar(type: Jar, dependsOn: alljavadoc) {
classifier = 'javadoc'
from alljavadoc.destinationDir
}
task sourcesJar(type: Jar) {
classifier = 'sources'
from subprojects.collect { it.sourceSets.main.allSource }
}
shadowJar.finalizedBy javadocJar
shadowJar.finalizedBy sourcesJar
Note, the subprojects section is required, even if you already apply the java plugin inside your subprojects.
Also note, it doesn't include javadocs of the third party libraries your subprojects might depend on. But usually you wouldn't want to do it anyway, probably.
This is an old thread, but I'm posting my solution, as it's a lot easier than the above, and I've confirmed it works:
plugins {
id 'com.github.johnrengelman.shadow' version '7.1.0'
id 'signing'
id 'maven-publish'
}
// If using Spring Boot, this is needed
jar.enabled = true
jar.dependsOn shadowJar
java {
withJavadocJar()
withSourcesJar()
}
// Remove the -all extension from the "fat" Jar, or it can't be used
// when published to Maven Central.
shadowJar {
archiveClassifier.set('')
}
// The contents of this section are described here:
// https://docs.gradle.org/current/userguide/publishing_maven.html
publishing {
publications {
jwtopaLibrary(MavenPublication) {
artifactId = 'jwt-opa'
artifacts = [ shadowJar, javadocJar, sourcesJar ]
pom {
// etc. ...
}
// Signs the `publication` generated above with the name `jwtopaLibrary`
// Signing plugin, see: https://docs.gradle.org/current/userguide/signing_plugin.html#signing_plugin
signing {
sign publishing.publications.jwtopaLibrary
}
It's not made clear anywhere, and the information needs to be collected in several places, but for the signing plugin to work, you need the short form hex key ID:
# gradle.properties
# The `signing` plugin documentation is less than helpful;
# however, this is the magic incantation to find the `keyId`:
#
# gpg --list-signatures --keyid-format 0xshort
#
# The key also needs to be distributed to public GPG servers:
#
# gpg --keyserver keyserver.ubuntu.com --send-keys 123...fed
#
# In all cases, we need to use the values from the `pub` key.
signing.keyId=0x1234abcde
Then, it's just a matter of running ./gradlew publish and magic happens (well, not really, you still have to go to Sonatype repository, do the "close & release dance", but you know, whatever).
I have read all the other threads about this problem and applied all the solutions I could find. Nothing helped. When I run the gradle.build task I get a .jar file. But when running the file I get no main manifest attribute, in DiscordBotJDA-1.0.jar
Can annyone provide help?
Thanks a lot!
Here is my gradle.buidl file:
/*
* This build file was auto generated by running the Gradle 'init' task
* by 'Timbo' at '7/13/16 2:08 PM' with Gradle 2.9
*
* This generated file contains a sample Java project to get you started.
* For more details take a look at the Java Quickstart chapter in the Gradle
* user guide available at https://docs.gradle.org/2.9/userguide/tutorial_java_projects.html
*/
// Apply the java plugin to add support for Java
apply plugin: 'java'
apply plugin: 'application'
mainClassName = 'start.StartUp'
version = '1.0'
task fatJar(type: Jar) {
manifest {
attributes 'Implementation-Title': 'MCI_Bot',
'Implementation-Version': version,
'Main-Class': 'start.StartUp'
manifest.attributes("Main-Class": 'start.startUp')
}
baseName = project.name + '-all'
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
// In this section you declare where to find the dependencies of your project
repositories {
// Use 'jcenter' for resolving your dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
}
// In this section you declare the dependencies for your production and test code
dependencies {
// The production code uses the SLF4J logging API at compile time
compile 'org.slf4j:slf4j-api:1.7.13'
compile 'net.dv8tion:JDA:2.1.3_327'
// Declare the dependency for your favourite test framework you want to use in your tests.
// TestNG is also supported by the Gradle Test task. Just change the
// testCompile dependency to testCompile 'org.testng:testng:6.8.1' and add
// 'test.useTestNG()' to your build script.
testCompile 'junit:junit:4.12'
}
I am using eclipse in case it matters.
Were you expecting that your "fatJar" task would be doing that? Just defining the task doesn't put it into the task execution tree. You have to either run the task directly, or specify a task dependency relationship including your task. For instance, saying that another task depends on it.
You might be better off just specifying a "jar" configuration block, which will configure the already existing "jar" task, which already has proper dependency relationships defined.
Read the User Guide for examples of configuring the "jar" task.
It might be more convenient to download the Gradle distribution, which provides the PDF of the User Guide, which might be easier to search.