Gradle (2.3.9) mysteriously hates setting "version" to a number - java

I'm rather baffled on this. If I pass in this version number, gradle fails:
gradle -Pversion=120151021 build
:eventing:compileJava
FAILURE: Build failed with an exception.
* What went wrong:
Could not resolve all dependencies for configuration ':eventing:compile'.
> Could not find eventing-test.jar
I've no idea why it thinks it needs to find eventing-test.jar. That's the name I have it creating for the jar of test classes. Seems like a red herring of a message.
If I simply put ANY alpha character in front of the version string, it works:
gradle -Pversion=z120151021 build
:eventing:compileJava
:eventing:processResources UP-TO-DATE
:eventing:classes
etc
etc
It seems to be a problem if it just starts with numbers:
gradle -Pversion=11abc build
:eventing:compileJava
FAILURE: Build failed with an exception.
Though, in a truly bizarre turn, it's ok if it starts with a single "1":
gradle -Pversion=1abc build
I don't see anything in the Gradle documentation that says a numeric version number is a problem.

I still don't know why the original setup didn't work, but I worked around it as follows. Inside each jar and publish target, I specifically pulled in another variable as the version. For example.
task testJar(type: Jar) {
from sourceSets.test.output
version = System.getProperty('RELEASE_VERSION', "unversioned")
appendix="test"
}
jar {
version = System.getProperty('RELEASE_VERSION', "unversioned")
}
Note, it does NOT work to do this trick to set version at the outer gradle level. It results in the same error I had before.
Does not work:
apply plugin: 'application'
version = System.getProperty('RELEASE_VERSION', "unversioned")
...define tasks and such that would use "version" ...

Related

Fail gradle build if file does not exist [duplicate]

I am starting to use Gradle for an Android application. I would like the build to fail if the developer fails to create a file at a specific location such as ./src/res/values/specialfile.xml
A bit of searching led me to believe that a .doFirst would work
android.doFirst {
assert file("./src/res/values/specialfile.txt").exists()
}
However, Gradle says "unsupported Gradle DSL method found: 'doFirst()'!"
What can I do to assert a file's existence?
doFirst only exists on tasks object. android is not a task.
If would want this test to always be done even if the developer doesn't try to build (for example when running the tasks task), you should simply put in your build.gradle
assert file("./src/res/values/specialfile.txt").exists()
However this is really not recommended as this would be executed even for non build tasks, or even when the model is built for IDE integration.
There is a task called preBuild that is executed before anything in the android build, so you can hook your test to it, either through another task or through doFirst:
preBuild.doFirst {
assert file("./src/res/values/specialfile.txt").exists()
}
One may want to check in a module build.gradle ...
below the plugins configuration block
above the android configuration block
eg. in order to determine which Gradle plugins to apply:
plugins {
id "com.android.application"
}
def json_google = "src/google-services.json";
if (project.file(json_google).exists()) {
println "found: ${project.file(json_google)}"
apply plugin: "com.google.gms.google-services"
apply plugin: "com.google.firebase.crashlytics"
...
} else {
def message = "missing: ${project.file(json_google)}"
// throw new GradleException(message)
println message
}
android { ... }
rootProject.file() and project.file() might be more convenient than file() (it depends). Using assert seems a bit harsh - but then one has to take care that it will not crash elsewhere.
My projects usually have a few optional config files, which the environment may or may not provide, because not every product flavor may require the same set of plugins & config files.

How to change/add dependencies in Gradle 3?

The following lines are in a Gradle plugin:
project.configurations.compile.incoming.resolutionResult.allComponents.findAll { ..}
//...
Dependency dependency = project.dependencies.add('packaged', dependencyDescription)
Applying this plugin works in Gradle 2, but fails in Gradle 3 with:
Failed to apply plugin [id 'test']
A problem occurred configuring project ':my-project'.
Cannot change dependencies of configuration ':my-project:packaged' after it has been included in
dependency resolution.
Removing the 2nd line, the error disappears in Gradle 3.
Now I would like to know the time & place which is valid in Gradle 3 to update the configuration. Reading the Gradle 3 manual i could not find an answer.
It looks like incoming.resolutionResult from the line
project.configurations.compile.incoming.resolutionResult.allComponents.findAll {..}
is triggering dependency resolution so any modification to the dependencies after that causes the error.
The resolution can be eliminated by doing a copy and reading from it instead.
project.configurations.compile.copyRecursive().incoming.resolutionResult.allComponents.findAll {..}

Dynamically add JAR to Gradle dependencies

Currently, my build.gradle has a dependency on an external library built with Ant. To accomplish building the library, I followed the advice here and created a task which builds the external library, and copies it to the libs/ folder.
The task is called as part of a dependency:
build.gradle
dependencies {
compile fileTree('libs') {
include '*.jar'
builtBy 'myTask'
}
}
task myTask (type: GradleBuild) { GradleBuild antBuild ->
antBuild.buildFile('external-stub.gradle')
antBuild.tasks = ['clean', 'ivy.check', 'ivy.download', 'ivy.task', 'ivy',
'init', 'mergeCode', 'compile', 'jar', 'copyJarsToProject']
}
However, when the compile actually runs, the library I just built and copied in is not included in the dependencies, as evidenced by a whole lot of compilation errors.
Am I including the library the wrong way?
The full build.gradle and associated files are over at Github, and I've linked to the specific commit I'm having issues with: Source Repository
Alright, took me a while to get a build I was happy with. But, here's what was changed.
The actual build of the JAR was built using the same style, but moved to the external project (so that the main build project wasn't reaching across to it). I'll give an in-depth explanation below, but the commits are here and here. These are in order.
Basically, we export the jar as an artifact that other projects can depend on, rather than copying over the Jar ourselves. This way, the Ant build runs and other projects can see the Jar we just created. This is the end of the first commit. In the second commit, the task outputs are marked as needing to be regenerated only if the Jar does not exist. This was due to the fact that whenever I tried to build the app, it would take minutes to regen the Jar, and then have to repackage everything else as well. The code is below:
build.gradle External Project
configurations {
buildJSword
}
task doBuildJSword (type: GradleBuild) {
buildFile = 'jsword-stub.gradle'
tasks = ['clean', 'ivy.check', 'ivy.download', 'ivy.task', 'ivy',
'init', 'mergeCode', 'compile', 'jar'] //, 'copyJarsToMinimalBible']
ext.outputJar = file('distribution/jsword.jar')
outputs.upToDateWhen {
ext.outputJar.exists()
}
}
artifacts {
buildJSword(doBuildJSword.ext.outputJar) {
builtBy doBuildJSword
}
}
Then, the main project just has to add this project as a compile-time dependency:
build.gradle Main Project
compile project(path: ':jsword-minimalbible', configuration: 'buildJSword')
Hope this is helpful for anyone with a similar issue, let me know if you have questions!
Note: The build currently does not clean itself properly, so if you change any code in the external project, you need to delete the external Jar for everything to regenerate itself correctly.

Perform an action on each file during installApp phase of Gradle build

Here is a minimal build.gradle file I'm using.
apply plugin: 'application'
installApp {
eachFile {
println "$it.name"
loadProperties(it)
}
}
I'm trying to load properties into some placeholders in a properties file located in src/dist/bin. This technique works fine if the properties file is in src/main/resources and I replace installApp with processResources which I am doing in another project within the build.
The println isn't printing anything so it makes sense the placeholders aren't replaced but I don't understand why it's not iterating through all the files the installApp task is copying.
Running this as ./gradlew clean installApp using gradle 1.10.
It appears that the installApp task doesn't run closure passed to the eachFile function. Here is a complete build.gradle file that demonstrates this behavior
apply plugin: "application"
mainClassName = "test.Test"
installApp {
eachFile {
println "$it.name"
}
}
I run gradle clean installApp -i
and around the installApp section get
:installApp (Thread[main,5,main]) started.
:installApp
Executing task ':installApp' (up-to-date check took 0.011 secs) due to:
Output file /Users/joshbrackett/Documents/workspace/gtest/build/install/gtest has changed.
Output file /Users/joshbrackett/Documents/workspace/gtest/build/install/gtest/bin/gtest has been removed.
Output file /Users/joshbrackett/Documents/workspace/gtest/build/install/gtest/lib/gtest.jar has been removed.
:installApp (Thread[main,5,main]) completed. Took 0.748 secs.
I have replicated your issue. I suspect this is a bug. While we investigate further, here is a workaround that worked for me.
make your eachFile call on the applicationDistribution copySpec rather than the installApp task.
applicationDistribution.eachFile {
println "$it.name"
}
I suspect that this is what you want to do anyway, since then it will also be used by the dist tasks.
BTW you may also find that the expand method is of interest http://www.gradle.org/docs/current/javadoc/org/gradle/api/file/CopySpec.html#expand(java.util.Map)
This has changed again in Gradle 2.3 apparently. Now using applicationDistribution doesn't work and you need to use installDist instead.

Copy file from a jar in a custom gradle plugin

I write a custom gradle plugin where I would like to copy a specific file from a jar inside the classpath into the buildDir. I played around in a sandbox project and got this solution working:
task copyFile(type: Copy) {
from zipTree(project.configurations.compile.filter{it.name.startsWith('spring-webmvc')}.singleFile)
include "overview.html"
into project.buildDir
}
but if copy it into my plugin:
project.task(type: Copy, "copyFile") {
from zipTree(project.configurations.compile.filter{it.name.startsWith('spring-webmvc')}.singleFile)
include "overview.html"
into project.buildDir
}
I got the error:
* What went wrong:
A problem occurred evaluating root project 'gradle-springdoc-plugin-test'.
> Could not find method zipTree() for arguments [/Users/blackhacker/.gradle/caches/artifacts-26/filestore/org.springframework/spring-webmvc/4.0.0.RELEASE/jar/a82202c4d09d684a8d52ade479c0e508d904700b/spring-webmvc-4.0.0.RELEASE.jar] on task ':copyFile'.
The result of
println project.configurations.compile.filter{it.name.startsWith('spring-webmvc')}.singleFile.class
is
class java.io.File
What I am doing wrong?
Unlike a build script, a plugin does not have an implicit project context (unless you give it one). Hence you'll have to use project.task rather than task, project.zipTree rather than zipTree, project.file rather than file, etc.
PS: In your case, it's important to use project.zipTree { ... } (note the curly braces) to defer searching for the file until the Zip contents are actually requested. Otherwise you risk slowing down each build invocation (even ones that never execute copyFile) and, if the file is being produced by the same build, even build failures (because the configuration is resolved before the file has been added).

Categories