Creating the default project Jar in gradle through a custom plugin - plugins

I'm in the process of building my first custom plugin for gradle. This plugin does a number of things, including configuring the project it's applied to based on other plugins that the project has. One of the things I want this plugin to do is handle all of the Maven publishing work, so that it doesn't need to appear in every build.gradle. Each build does the exact same thing, they just have their source Jar and their base project Jar, and both are (or will be) published to our artifact repository.
That works, I can create the Jar file. However, the Jar file only contains the META-INF folder and manifest file, and none of the classes of the project. Has anyone encountered this problem and know the cause?
// Configure Jar Manifest
jar {
manifest = project.manifest {
from sharedManifest
}
}
// Configure sources Jar manifest
(project.getTasks()).create("sourcesJar", Jar) {
classifier "sources"
from project.sourceSets.main.allSource
manifest = project.manifest {
from sharedManifest
}
}
artifacts {
archives project.tasks.sourcesJar
}
publishing {
publications {
mavenJava(MavenPublication) {
from project.components.java
artifact project.tasks.sourcesJar
pom.withXml {
def root = asNode()
root.appendNode("name", project.name)
root.appendNode("description", project.name + "component of company.")
root.appendNode("inceptionYear", "2010")
}
}
}
repositories {
maven {
//We only publish to the Releases repository if the project is given the property "release"
if(project.hasProperty("release")) {
url "http://clipped/"
} else {
url "http://clipped/"
}
credentials {
if(project.hasProperty("nexusUsername") && project.hasProperty("nexusPassword"))
{
username = nexusUsername
password = nexusPassword
}
}
}
}
}

That was it, Peter, a developer had moved all of the projects calling the plugin from src/main/java to src/java, thinking that the folder structure was unnecessarily deep. Nothing wrong with the plugin code.

Related

Gradle DSL - Eclipse Equivalent for IDEA Module Property

Good localtime,
I am in the process of updating legacy (4.8.1) Gradle build files for a big-McLarge-huge, multimodule project. We utilize an intellij.gradle file which has the following line (marked by comment):
idea {
module {
inheritOutputDirs = true // <-- HOW DO I DO THIS
downloadJavadoc = true
downloadSources = true
}
workspace.iws.withXml { provider ->
def node = provider.asNode()
def dynamicClasspath = node.component.find { it."#name" == "dynamic.classpath" }
if (dynamicClasspath != null) {
dynamicClasspath."#value" = "true"
}
}
From the 4.8.1 DSL docs:
If true, output directories for this module will be located below the
output directory for the project; otherwise, they will be set to the
directories specified by IdeaModule.getOutputDir() and
IdeaModule.getTestOutputDir().
Any ideas on what the Eclipse DSL equivalent of inheritOutputDirs? Should this be handled using the eclipseClasspath API? Right now everything is building fine, but the Eclipse Java builder is is flagging things.
References:
https://docs.gradle.org/4.8.1/dsl/org.gradle.plugins.ide.idea.model.IdeaModule.html
https://docs.gradle.org/4.8.1/dsl/org.gradle.plugins.ide.eclipse.model.EclipseClasspath.html
Usually this would have been picked up through sourceSets but I can't see what your project looks like...
If your subproject uses Gradle to generate sources into /build/cxf/generated-sources directory, then you can tell Eclipse via Gradle DSL to include that as a source folder like this:
plugins { id 'eclipse' }
eclipse.classpath.file.whenMerged {
// this is the brute-force approach; there is likely a better way to add a source folder
entries << new org.gradle.plugins.ide.eclipse.model.SourceFolder('build/cxf/generated-sources', null)
}
Once this is run (via gradle eclipseClasspath) you should see a build/cxf/generated-sources folder under your project node in the Package Explorer or Project Explorer. Sort of like this:
NOTE: This is untested because I don not have a sample project to work with.
There is more discussion here: How to add gradle generated source folder to Eclipse project?

Kotlin setup via gradle on eclipse

Struggling to get Kotlin running on eclipse.
I've started new graddle project. Added dependencies as prescribed on kotlin's site.
Build passes without errors.
I've created 'main.kt' file under src/java/main with:
fun main(args: Array<String>) {
println("foo")
}
BUT, I have two problems:
1. anything from kotlin e.g. println highlighted as 'unresolved reference'.
2. I can't run a program - Error: Could not find or load main class MainKt (rightclick on main.kr run as 'kotlin application')
If I create 'new kotlin project' everything works.
my graddle build script:
plugins {
id "org.jetbrains.kotlin.jvm" version "1.1.2-2"
}
repositories {
jcenter()
mavenCentral()
}
dependencies {
//api 'org.apache.commons:commons-math3:3.6.1'
implementation 'com.google.guava:guava:21.0'
testImplementation 'junit:junit:4.12'
compile "org.jetbrains.kotlin:kotlin-stdlib:1.1.2-2"
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8"
compile "org.jetbrains.kotlin:kotlin-reflect"
testCompile "org.jetbrains.kotlin:kotlin-test"
testCompile "org.jetbrains.kotlin:kotlin-test-junit"
}
sourceSets {
main.java.srcDirs = ['src/main/java']
main.kotlin.srcDirs = ['src/main/java', 'src/main/kotlin']
main.resources.srcDirs = ['src/main/resources']
}
What did I do wrong?
I've zero Java knowledge if that helps, so probably I've made some trivial error.
UPDATE:
Installed a Spring plugin and generated a new web app via it including gradle.
But Kotlin behaves unpredictably there too.
At first I was not able to run it as run as Kotlin application and it errored with main could not be found, BUT sometimes it run and crashed immediately. It started to launch and crash after I've deleted and edited classes, tried creating it under other package, removing and adding Kotlin (I can't reproduce sequence to make it work again).
Fun part that gradle boot build launches everything and all works it somehow finds Kotlin's main.
Probably some issue with Kotlin plugin itself (it's load probably depends on certain events that doesn't always fire)
Add the following to your configuration:
apply plugin: 'eclipse'
eclipse {
classpath {
containers 'org.jetbrains.kotlin.core.KOTLIN_CONTAINER'
}
}
See https://gitlab.com/frnck/kotlin-gradle-eclipse for a working configuration.
I'd like to add to frnck answer that this is only part of the solution. I also had to add these lines:
eclipse.project {
buildCommand 'org.jetbrains.kotlin.ui.kotlinBuilder'
natures 'org.jetbrains.kotlin.core.kotlinNature'
natures 'org.eclipse.jdt.core.javanature'
linkedResource name: 'kotlin_bin', type: '2', locationUri: 'org.jetbrains.kotlin.core.filesystem:/aio/kotlin_bin'
}
For Eclipse 2018-12 and kotlin 1.3 the solution was a combination of other answers plus some additional settings file:
eclipse {
classpath {
//Adds the kotlin container to the classpath
containers 'org.jetbrains.kotlin.core.KOTLIN_CONTAINER'
//Fixes the right output path
defaultOutputDir = file('bin')
//Make all src folders output in the same output folder (default)
file {
whenMerged {
// use default Output for all source-folders. see also defaultOutputDir per project
entries.each { source ->
// only Source-folders in the project starting with '/' are project-references
if (source.kind == 'src' && !source.path.startsWith('/')) {
source.output = null
}
}
}
}
}
project{
buildCommand 'org.jetbrains.kotlin.ui.kotlinBuilder'
//Fixes the natures
natures 'org.jetbrains.kotlin.core.kotlinNature'
natures 'org.eclipse.jdt.core.javanature'
//Links the kotlin_bin folder (generated class files)
linkedResource name: 'kotlin_bin', type: '2', locationUri: "org.jetbrains.kotlin.core.filesystem:/${project.name}/kotlin_bin".toString()
file{
whenMerged{
def kotlinPrefs = file('.settings/org.jetbrains.kotlin.core.prefs')
def jdkHome = System.properties.'java.home'
if(!(jdkHome)){
throw new GradleException('No JDK home available for setting up Eclipse Kotlin plugin, setup env "java.home" or update this script.')
}
kotlinPrefs.write """\
codeStyle/codeStyleId=KOTLIN_OFFICIAL
codeStyle/globalsOverridden=true
compilerPlugins/jpa/active=true
compilerPlugins/no-arg/active=true
compilerPlugins/spring/active=true
eclipse.preferences.version=1
globalsOverridden=true
jdkHome=$jdkHome
""".stripIndent()
}
}
}
}
I would like to add to Felipe Nascimento's answer that the location of the .settings folder does not yet exist. It works when the line below is inserted into that answer.
def kotlinPrefs = file("../${project.name}/.settings/org.jetbrains.kotlin.core.prefs".toString())
I have found that the JAVA_HOME environment variable that is set when your run this task ;
gradle cleanEclipse eclipse
is the one that is included in the Eclipse BuildPath

1 Eclipse project, 2 artifacts with Gradle

I want to create structure for my new project and I intend to build it with Gradle. I already know that if I place sources and tests in one project plugins like MoreUnit will handle it easily and create tests for my classes right where I want them.
However it creates some awkward dependency issues when my project consists of several subprojects depending on each other - to be precise when I want to use some common code in tests in project A and then reuse it in tests in project B I had to do some workarounds like
project(':B') {
// ...
dependencies {
// ...
if (noEclipseTask) {
testCompile project(':A').sourceSets.test.output
}
}
}
sometimes there were also some evaluation problem so another hack had to be introduced:
project(':B') {
evaluationDependsOn(':A')
}
Splitting this into 2 separate projects got rid of that issue but then MoreUnit no longer was able to trace where it should create new test files, and mark which methods have been tested. I haven't found anything in MoreUnit config that would allow me to fix that, so am trying to fix this from Gradle side.
Can we arrange things so I can have several subprojects, sources and tests are arranged in maven like manner (project/src/java, project/test/java) but tests and sources will create separate artifacts? If I am solving the wrong problem then how should I solve the right one?
You can create some testenv jar for common like:
sourceSets {
testenv {
compileClasspath += main.output
runtimeClasspath += main.output
}
}
configurations {
testenvCompile {
extendsFrom runtime
}
testCompile {
extendsFrom testenvRuntime
}
testenvDefault {
extendsFrom testenvRuntime
}
}
and
task testenvJar(type: Jar, group: 'build', description: 'Assembles a jar archive containing the testenv classes.') {
from sourceSets.testenv.output
appendix = 'testenv'
// add artifacts to testenvRuntime as task 'jar' does automatically (see JavaPlugin#configureArchivesAndComponent:106 and http://www.gradle.org/docs/current/userguide/java_plugin.html, "Figure 23.2. Java plugin - dependency configurations")
configurations.testenvRuntime.artifacts.add new org.gradle.api.internal.artifacts.publish.ArchivePublishArtifact(testenvJar)
}
task testenvSourcesJar(type: Jar, group: 'build', description: 'Assembles a jar archive containing all testenv sources.') {
from sourceSets.testenv.allSource
appendix = 'testenv'
classifier = 'sources'
}
artifacts {
archives testenvJar
archives testenvSourcesJar
}
and use it in your depended projects like
testCompile project(path: ':common', configuration: 'testenvDefault')
I hope this helps!

Gradle Api Sources and Doc when writing Gradle Plugins

The question:
How do I get the sources and javadoc/groovydoc for the gradle-api code integrated into an Eclipse project?
Background:
I'm using Gradle to build a Gradle-plugin that I'm writing. I'm using Eclipse as an IDE for this project and my Gradle script for building this plugin is using the 'Eclipse' plugin to generate my Eclipse project. Also, I'm using Spring's Gradle plugin for Eclipse which grabs all my dependencies from my build.gradle file.
The dependencies block for this Gradle script has
dependencies {
compile localGroovy()
compile gradleApi()
// I want something like: 'compile gradleApiSources()' here
// I want something like: 'compile gradleApiDoc()' here as well
}
Justification:
As I'm learning to write Gradle plugins, it would be helpful to be able to see the documentation and even implementation for Gradle to help me learn what I'm doing.
This works for me in Eclipse:
plugins.withType(EclipsePlugin) {
plugins.withType(JavaBasePlugin) {
eclipse {
classpath {
file {
whenMerged { classpath ->
String gradleHome = gradle.getGradleHomeDir()
.absolutePath
.replace(File.separator, '/')
String gradleSourceDirectory = "${gradleHome}/src"
classpath.entries.each { entry ->
if (entry in org.gradle.plugins.ide.eclipse.model.AbstractLibrary
&& entry.library.path.contains('generated-gradle-jars')) {
entry.sourcePath =
new org.gradle.plugins.ide.eclipse.model.internal.FileReferenceFactory()
.fromPath(gradleSourceDirectory)
}
}
}
}
}
}
}
}
Make sure that your Gradle Home contains the source directory. If you use the wrapper this can be done by updating the distributionUrl to an -all version in the wrapper task.
You will also need to stop the Gradle daemons that are running otherwise they will keep their own "home": ./gradlew --stop, then you can go ahead and run the task: ./gradlew eclipse
See GRADLE-2133 (which this answer was adapted from)
I don't have an answer for eclipse but I can tell you how I do this for intellij which might give you some inspiration. It would be nice if this were available more easily.
private void addGradleSourceDeps() {
PathFactory pf = new PathFactory()
pf.addPathVariable('GRADLE_HOME', project.gradle.gradleHomeDir)
project.extensions.idea.module.iml.whenMerged { Module module ->
module.dependencies.grep {
it instanceof ModuleLibrary && ((ModuleLibrary) it).classes.grep { Path path ->
path.relPath.substring(path.relPath.lastIndexOf('/') + 1).startsWith('gradle-')
}
}.each { ModuleLibrary lib ->
// TODO this needs to be fixed for gradle 1.9 which now includes separate sub directory for each jar
// for now a workaround is to execute the following
// cd $GRADLE_HOME
// for each in $(find . -mindepth 2 -maxdepth 2 -type d ! -name META\-INF); do cp -a ${each} .;done
lib.sources.add(pf.path('file://$GRADLE_HOME$/src'))
}
module.dependencies.grep {
it instanceof ModuleLibrary && ((ModuleLibrary) it).classes.grep { Path path ->
path.relPath.substring(path.relPath.lastIndexOf('/') + 1).startsWith('groovy-all')
}
}.each { ModuleLibrary lib -> lib.sources.add(pf.path('file://$GROOVY_SRC_HOME$')) }
}
}
This relies on me having installed a gradle src distribution into a location available via the GRADLE_HOME path variable in intellij (and similar for GROOVY_SRC_HOME). You can also see my plugin currently uses gradle 1.8, the src layout changed in 1.9 so I need to fix this when I upgrade.

Gradle (tomcat-plugin): tomcatRun cannot execute GWT JS

I am trying to build a GWT enabled web application with Gradle (on Ubuntu Linux).
I have configured everything, and Gradle manages to successfully build the application, but when I run the task "tomcatRun", I can only see a blank page, which is a result of GWT javascript not executing (if I view the page source, it is there). No errors, no warnings from Tomcat, just that blank page.
However, when I run "tomcatRunWar", everything works perfectly. I can't figure out what might be wrong or why might this happen.
This is my gradle.build file:
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'tomcat'
apply plugin: 'eclipse-wtp'
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "org.gradle.api.plugins:gradle-tomcat-plugin:1.0"
}
}
repositories {
mavenCentral()
}
dependencies {
/* Tomcat plugin dependencies */
def tomcatVersion = '7.0.47'
tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
"org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}"
tomcat("org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}") {
exclude group: 'org.eclipse.jdt.core.compiler', module: 'ecj'
}
/* Google Web Toolkit */
def gwtVersion = '2.5.1'
providedCompile "com.google.gwt:gwt-user:${gwtVersion}"
providedCompile "com.google.gwt:gwt-dev:${gwtVersion}"
runtime "com.google.gwt:gwt-servlet:${gwtVersion}"
/* Spring Security */
def springVersion = '3.1.4.RELEASE'
compile "org.springframework.security:spring-security-web:${springVersion}"
compile "org.springframework.security:spring-security-config:${springVersion}"
}
/* Task to compile the client package GWT code to JavaScript */
task gwtCompile (dependsOn: classes, type: JavaExec) {
buildDir = "${project.buildDir}/gwt"
extraDir = "${project.buildDir}/extra"
inputs.source sourceSets.main.java.srcDirs
inputs.dir sourceSets.main.output.resourcesDir
outputs.dir buildDir
doFirst {
file(buildDir).mkdirs()
}
main = "com.google.gwt.dev.Compiler"
classpath {
[
sourceSets.main.java.srcDirs, // Java source
sourceSets.main.output.resourcesDir, // Generated resources
sourceSets.main.output.classesDir, // Generated classes
sourceSets.main.compileClasspath, // Dependencies
]
}
args = [
'<package_path_to_GWT_module>', // Our GWT module
'-war', buildDir,
'-logLevel', 'INFO',
'-localWorkers', '2',
'-compileReport',
'-extra', extraDir,
]
maxHeapSize = '256M'
}
/* Make the war plugin depend on the gwtCompile task */
war.dependsOn gwtCompile
/* Include the contents of the GWT compilation in the generated WAR file */
war {
from gwtCompile.buildDir
}
/* Configure the eclipse plugin in case it is used */
eclipse {
project {
natures 'com.google.gwt.eclipse.core.gwtNature'
buildCommand 'com.google.gdt.eclipse.core.webAppProjectValidator'
buildCommand 'com.google.gwt.eclipse.core.gwtProjectValidator'
}
classpath {
containers 'com.google.gwt.eclipse.core.GWT_CONTAINER'
}
}
My directory tree looks like this:
ProjectHome
-- src
-- main
-- java
-- <packages>
-- webapp
-- WEB-INF
-- web.xml
-- index.html
-- test
-- build.gradle
I have also compared the resulting WAR's directory tree with the one used by the 'tomcatRun' task (build/libs/ProjectName) and they seem identical.
Does anyone have any ideas for this?
// Edit: Actually, it does not display an empty page, it just can't execute the GWT Javascript, to assign content to the only div in body.
OK, found the solution.
You actually have to copy the needed files into the src/main/webapp directory (or make the build script do that or even better configure the tomcat-plugin to read the files from elsewhere - if that is possible), because tomcatRun reads the files from there. I was expecting it to read them from where the WAR file lies in (build/libs), but this is not the case.
So, the best option here, given that the GWT plugin is still a work in progress, is to use the tomcatRunWar option.