How can I create a pathing jar in Gradle - groovy

When running groovyc in a Windows env, I am running into issues due to the length of the classpath, in my situation. I would like to work around this by creating a pathing jar, and then put that jar on the cp. How can I create a pathing jar w/ all of the classpath entries specified automatically in gradle and then add that jar to the cp?

Here is a tested solution:
task pathingJar(type: Jar) {
appendix = "pathing"
doFirst {
manifest {
attributes "Class-Path": configurations.compile.files.join(" ")
}
}
}
compileGroovy {
dependsOn(pathingJar)
classpath = files(pathingJar.archivePath)
}
Depending on your exact requirements, you might have to tweak this a bit. For example, if you have tests written in Groovy, you will also need a pathing Jar for the test compile class path. In this case you'll need to repeat above configuration as follows:
task testPathingJar(type: Jar) {
appendix = "testPathing"
doFirst {
manifest {
attributes "Class-Path": configurations.testCompile.files.join(" ")
}
}
}
compileTestGroovy {
dependsOn(testPathingJar)
classpath = files(testPathingJar.archivePath)
}

I finally got the "pathing jar" idea to work. I consider this to be a permanent workaround. This could be considered a solution if it is made part of gradle itself.
The original pathing jar code was provided by Peter, but it didn't work. The problem: classpath elements referenced in the pathing jar must be relative to the location of the pathing jar. So, this appears to work for me.
task pathingJar(type: Jar , dependsOn: 'cleanPathingJar') {
/**
* If the gradle_user_home env var has been set to
* C:\ on a Win7 machine, we may not have permission to write the jar to
* this directory, so we will write it to the caches subdir instead.
* This assumes a caches subdir containing the jars
* will always exist.
*/
gradleUserHome = new File(gradle.getGradleUserHomeDir(), "caches")
relativeClasspathEntries = configurations.compile.files.collect {
new File(gradleUserHome.getAbsolutePath()).toURI().
relativize(new File(it.getAbsolutePath()).toURI()).getPath()
}
appendix = "pathing"
destinationDir = gradleUserHome
doFirst {
manifest {
attributes "Class-Path": relativeClasspathEntries.join(" ")
}
}
}
compileGroovy {
dependsOn(pathingJar)
classpath = files(pathingJar.archivePath)
}

This is what helped me:
"The filename or extension is too long error" using gradle
In other words: use the com.github.ManifestClasspath plugin.
The other solutions did not work for me because the actual project main class ended up no being included in the classpath at execution time.

Related

Pitest is failing showing: No mutations found due to the supplied classpath or filters + Gradle

I'm trying to run a pitest report on a gradle + kotlin project, but I get the following error:
Exception in thread "main" org.pitest.help.PitHelpError: No mutations found. This probably means there is an issue with either the supplied classpath or filters.
See http://pitest.org for more details.
at org.pitest.mutationtest.tooling.MutationCoverage.checkMutationsFound(MutationCoverage.java:352)
at org.pitest.mutationtest.tooling.MutationCoverage.runReport(MutationCoverage.java:132)
at org.pitest.mutationtest.tooling.EntryPoint.execute(EntryPoint.java:123)
at org.pitest.mutationtest.tooling.EntryPoint.execute(EntryPoint.java:54)
at org.pitest.mutationtest.commandline.MutationCoverageReport.runReport(MutationCoverageReport.java:98)
at org.pitest.mutationtest.commandline.MutationCoverageReport.main(MutationCoverageReport.java:45)
I tried everything that I found on google but still not working for me:
This is my build.gradle config
plugins {
id 'groovy-gradle-plugin'
id 'info.solidsoft.pitest' version '1.7.4'
}
repositories {
maven { url "https://plugins.gradle.org/m2/" }
gradlePluginPortal()
}
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.20'
implementation 'com.github.jengelman.gradle.plugins:shadow:6.1.0'
}
pitest {
targetClasses = ['com.project.root.to.test.with.pitest.src*'] //by default
"${project.group}.*"
pitestVersion = '1.7.4' //not needed when a default PIT version should be used
threads = 4
outputFormats = ['XML', 'HTML']
timestampedReports = false
}
I tried this targetClasses in a different ways:
targetClasses = ['com.project.root.to.test.with.pitest.src.*'] //by default
targetClasses = ['com/project/root/to/test/with/pitest/src*'] //by default
Can someone help me, please?
You look to be trying to supply pitest with a source folder
com.project.root.to.test.with.pitest.src.
Pitest works against the compiled bytecode, not the source files. It expects
a glob that matches against the package.
com.example.*
I've experienced this same issue today. You'll need to make sure all references to pitest use the same version 1.7.4. This includes
plugin: id 'info.solidsoft.pitest' version '1.7.4'
pitestVersion: pitestVersion.set('1.7.4')
dependency: testCompile
'info.solidsoft.gradle.pitest:gradle-pitest-plugin:1.7.4'
Which out changing all references, then it will break.

Spring boot + Groovy + logback.groovy

I am mixing Groovy and Java in my Spring-boot application. Rest controllers and data access is written in Groovy. Configurations are mainly in Java.
As per logback documentation, if there is a logback.groovy file in the classpath, it's supposed to be picked ahead of logback.xml. However only logback.xml is working in my case.
I am running the app as sprint-boot-application.
Also, it's worth noting that spring suggest to inherit some of the logging configuration like shown below
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<logger name="org.springframework.web" level="DEBUG"/>
</configuration>
There is no way to do this in Groovy config.
build.gradle:
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework:spring-jdbc")
compile("com.h2database:h2")
compile("org.hsqldb:hsqldb")
testCompile("junit:junit")
compile('org.codehaus.groovy:groovy-all:2.3.10')
testCompile('org.codehaus.groovy.modules.http-builder:http-builder:0.5.0-RC2')
compile('org.slf4j:slf4j-simple:1.6.1')
}
sourceSets {
main {
groovy {
srcDirs = ['src/main/groovy', 'src/main/java']
}
java {
srcDirs = []
}
}
test {
groovy {
srcDirs = ['src/test/groovy', 'src/test/java']
}
java {
srcDirs = []
}
}
}
First, your build.gradle looks strange to me:
you don't include the spring-boot-gradle-plugin
in your sourceSets options you define settings which are the default values of the Groovy plugin, see Project layout
Note: even if you mix java and groovy files you don't have to separate them (you can if you want). I usally keep them both in the groovy directory.
in your dependencies section you are using simple dependencies instead of Spring Boot starters (see also the reference doc)
You have 2 DB dependencies (H2 and HSQL)
Try to create a sample project with Spring Initializr - switch to full version. Your build.gradle would look like
buildscript {
ext {
springBootVersion = '1.5.1.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'groovy'
apply plugin: 'org.springframework.boot'
jar {
baseName = 'demo'
version = '0.0.1-SNAPSHOT'
}
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile 'org.springframework.boot:spring-boot-starter'
compile 'org.springframework.boot:spring-boot-starter-logging'
compile 'org.springframework.boot:spring-boot-starter-jdbc'
compile 'org.codehaus.groovy:groovy'
compile 'com.h2database:h2'
testCompile 'org.springframework.boot:spring-boot-starter-test'
testCompile 'org.codehaus.groovy.modules.http-builder:http-builder:0.5.0-RC2'
}
With this configuration logback.groovy should work. For specific problems just post your logback.groovy. But as you have noted, the Groovy config is not a full citizen. When you include the spring-boot-starter-logging starter you can also extend the standard logging config with logback-spring.groovy or logback-spring.xml.
For full control you have to use the XML config and for small projects I stopped using logback.groovy and instead just config the logging starter via some settings in the application.properties, see Custom log configuration.
E.g. some settings for application.properties with logs with colored columns (all platforms except windows < 10 and in IDEA even under windows < 10):
logging.file = logs/jira.log
spring.output.ansi.enabled = DETECT
logging.level.root = INFO
logging.level.org.apache.http = WARN

Create a Groovy executable jar with Spock test set as to be executed

I want to create jar with two groovy files, AppLogic.groovy which consists of two few groovy classes and another file, AppSpec that has Spock test suite and I would like to have this Spock class executed (set as executable). How can I create such jar with all dependencies? I found sth similar for jUnit here: how to export (JUnit) test suite as executable jar but could not adapt it for my needs.
I use gradle for build, here is my build.gradle file:
group 'someGroup'
version '1.0'
apply plugin: 'groovy'
apply plugin: 'java'
apply plugin:'application'
sourceCompatibility = 1.7
repositories {
//some repos here
maven { url "http://repo.maven.apache.org/maven2" }
}
dependencies {
//some dependencies here
}
I was browsing around and found SpockRuntime, but I do not know if and how I can use it to achive my goal.
And the winner is:
static void main(String[] args) {
EmbeddedSpecRunner embeddedSpecRunner = new EmbeddedSpecRunner()
embeddedSpecRunner.runClass(MySpec)
}
I do not advise using the EmbeddedSpecRunner from spock implementation as described in accepted answer.
This is what I found to work reliably with gradle 4.9. The basic approach is to use:
The gradle application plugin to create a single tarfile with all testRuntimeClasspath dependencies and shell scripts to run the spock tests
The gradle maven-publish plugin to publish the tar file as an artifact to your maven repo (in my case nexus)
The build.gradle file looks like this:
apply plugin: 'java'
apply plugin: 'groovy'
apply plugin: 'maven-publish'
apply plugin: 'application'
mainClassName = 'org.junit.runner.JUnitCore' // The junit 4 test runner class
applicationName = 'run-tests-cli' // Feel free to change
repositories {
...
}
dependencies {
...
testImplementation "org.codehaus.groovy:groovy-all:${groovyVersion}"
testImplementation "org.spockframework:spock-core:${spockVersion}"
}
// Package compiled spock / junit tests to <artifact>-test-<version>.jar
task testJar(type: Jar) {
classifier = 'tests'
from sourceSets.test.output.classesDirs
}
// Copy all testRuntimeClasspath dependencies to libs folder
task copyToLibs(type: Copy) {
from configurations.testRuntimeClasspath
into "$buildDir/libs"
}
// Make sure test jar is copied
copyToLibs.dependsOn('testJar')
// Make sure platform-specific shell scripts are created after copyToLibs
startScripts.dependsOn(copyToLibs)
// Configure what goes into the tar / zip distribution file created by gradle distribution plugin assembleDist task
distributions {
main {
contents {
// Include test jar
from(testJar) {
into "lib"
}
// Include all dependencies from testRuntimeClasspath
from(copyToLibs) {
into "lib"
}
}
}
}
startScripts {
// Ensure ethat all testRuntimeClasspath dependencies are in classpath used by shell scripts
classpath = project.tasks['testJar'].outputs.files + project.configurations.testRuntimeClasspath
}
publishing {
repositories {
maven {
def releasesRepoUrl = "https://nexus.yourcompany.com/repository/maven-releases/"
def snapshotsRepoUrl = "https://nexus.yourcompany.com/repository/maven-snapshots/"
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
credentials {
username = rootProject.getProperty('NEXUS_USERNAME')
password = rootProject.getProperty('NEXUS_PASSWORD')
}
}
}
publications {
maven(MavenPublication) {
groupId = 'com.yourgroupId'
version = "${rootProject.getVersion()}"
}
TestJar(MavenPublication) {
artifact(testJar)
}
RunTestsCliTar(MavenPublication) {
artifact(distTar)
artifactId "${applicationName}"
}
}
}
Now you can do the following:
To build the project (including the tar file) without running test task: gradle -x test clean build
To publish artifacts produced by project (including tar file to maven repo - in my case nexus): gradlew -x test publish. Note you will need to provide credentials to upload artifacts to repo. It is good practice to define them (NEXUS_USERNAME, NEXUS_PASSWORD in my example) in ~/.gradle/gradle.properties or specify them via -P options on the gradle command line.

Add a single file to gradle resources

I'm using the config var plugin for heroku (see https://devcenter.heroku.com/articles/config-vars).
It allows me to use a .env file which I do not push to source control to define the heroku environment.
So when I'm on heroku, I can access sensible information via System.properties.
In dev, I would like to read from this file so it would be best if it were on my classpath.
The .env file is at the root of my project so I cannot use something like this :
sourceSets {
main {
resources {
srcDirs = ['src/main/resources', '/']
}
}
}
What is the simplest way to include a single file into gradle resources ?
The earlier answers seemed more complicated than I was hoping for, so I asked on the gradle forums and got a reply from a Sterling Green who's one of the gradle core devs.
He suggested configuring processResources directly
processResources {
from(".env")
}
He also mentioned that it might be a bad idea to include the project root as an input directly.
After merging the previous answer here with another tips from other sites, I came up with the following solution:
sourceSets {
specRes {
resources {
srcDir 'extra-dir'
include 'extrafiles/or-just-one-file.*'
}
}
main.resources {
srcDir 'src/standard/resources'
srcDir specRes.resources
}
}
processResources {
rename 'some.file', 'META-INF/possible-way-to-rename.txt'
}
I still wonder whether there is some better way.
What I ended up doing was to add project root directory as a resource folder including only the file I was interested in :
sourceSets.main.resources { srcDir file('.') include '.env' }
Seems to do the trick. I wonder if it's the best solution thought

Create multiple .WAR files with different dependencies in Gradle

I am using the war plugin to generate a simple .WAR file for my project in gradle. I'd like to know how to configure gradle so that I can create 4 different .WAR files with different dependencies.
I've configured the dependency compile configuration with the jars that are needed to go into the distribution. None of the code in the src depends on a couple of these jars but I would like to know how to configure the project to create
a standard.WAR file that contains all of the jars in the dependency graph (Even though they aren't used - that is OK - I am testing something)
another standard-qas-only.WAR file that only contains the qas.jar
another standard-qas-log4j.WAR file that contains qas.jar and log4j
What tasks do i configure to have the artifact generated use a particular dependency configuration?
FYI: The only jar that is required for compilation is qas.jar in this case.
My example below creates a war file that only includes one jar but i'd like to have 5 different .war files generated with different jars.
build.gradle
apply plugin: 'java'
apply plugin: 'war'
dependencies {
compile files('/lib/qas.jar','/lib/axis1-1.4.jar','/lib/axis2-kernel-1.3.jar','/lib/dom4j-1.6.1.jar','/lib/log4j-1.2.14.jar')
providedCompile files('/lib/j2ee-1.4.03.jar')
}
war {
classpath = ['/lib/qas.jar']
}
task dist(dependsOn: 'war') << {
copy {
from war.archivePath
into "dist/"
}
}
I got a bit confused on how many WAR distributions you are actually trying to build. You can easily modify it to create additional WAR files. Here's one approach to make this happen:
task createStandardWar(type: War, dependsOn: classes) {
baseName = 'standard'
destinationDir = file("$buildDir/dist")
}
task createStandardWarQasOnly(type: War, dependsOn: classes) {
baseName = 'standard-qas-only'
destinationDir = file("$buildDir/dist")
classpath = war.classpath.minus(files('/lib/axis1-1.4.jar','/lib/axis2-kernel-1.3.jar','/lib/dom4j-1.6.1.jar','/lib/log4j-1.2.14.jar'))
}
task createStandardWarQasAndLog4J(type: War, dependsOn: classes) {
baseName = 'standard-qas-log4j'
destinationDir = file("$buildDir/dist")
classpath = war.classpath.minus(files('/lib/axis1-1.4.jar','/lib/axis2-kernel-1.3.jar','/lib/dom4j-1.6.1.jar'))
}
task createDists(dependsOn: [createStandardWar, createStandardWarQasOnly, createStandardWarQasAndLog4J])
This build script excerpt creates three different WAR files by declaring enhanced tasks of type War. It assumes that you still want to have your compiled source files under WEB-INF/classes within the WAR files so I didn't remove it from the classpath. The distributions end up in the directory build/dist. The task createDists creates all of them.

Resources