How do I specify optional inputs on a Gradle task without an #Optional annotation? - gradle

I want to use an optional input if it exists and just move on if it does not exist.
When I run gradle -Dorg.gradle.warning.mode=all I got a deprecation warning for just specifying the input:
A problem was found with the configuration of task ':addWorkingCopyInfo'. Registering invalid inputs and outputs via TaskInputs and TaskOutputs methods has been deprecated and is scheduled to be removed in Gradle 5.0.
- File '/Users/robert/test/special-build-tag' specified for property '$1' does not exist.
This is the task in the build script:
task addWorkingCopyInfo(type: Exec) {
inputs.file file("tagFile") // deprecated if the file does not exist
outputs.file file("generated/taginfo")
executable "perl" args "..."
}
I've seen that I could add an #Optional annotation if I had a custom task class, but that's not the case here.
My best solution was to add a check for the file and only make it an input if it exists. This seems to work.
task addWorkingCopyInfo(type: Exec) {
def tagFile = new File("tagFile");
if (tagFile.exists()) {
inputs.file tagFile
}
outputs.file file("generated/taginfo")
executable "perl" args "..."
}
Is there a better / more Gradle-ish way to do this?

The method inputs.files(...) returns a TaskInputFilePropertyBuilder that provides the methods optional() and optional(boolean).
Just try:
inputs.files('my-file').optional()

Related

Passing a gradle task arguments in command line

I'm trying to find the best way to pass a gradle task arguments from the command line.
I have this task. I want to unpack solutions from student exercises and copy them into the right place in the project to evaulate them. I call this task like this:
> gradle swapSolution -Pstudent=MyStudent -Pexercise=ex05
One Problem i have with this while doing this in IntelliJ while having the Gradle plugin enabled is that i get this error message when build the project. What could be a solution to this?
A problem occurred evaluating root project 'kprog-2020-ws'.
> Could not get unknown property 'student' for root project 'kprog-2020-ws' of type org.gradle.api.Project.
This is the gradle task:
task swapSolution(type: Copy) {
new File("${rootDir}/Abgaben").eachDir { file ->
if (file.name.toString().matches("(.*)" + project.property("student") + "(.*)")) {
def exDir = new File("/src/main/java/prog/" + project.property("exercise"))
if (!exDir.exists()) {
delete exDir
}
new File(file.path).eachFile { zipSolution ->
//def zipFile = new File("./Abgaben/" + file.name.toString() + "/" + project.property("exercise") + "Solution.zip")
from zipTree(zipSolution)
into "/src/main/java/"
}
}
}
}
Do you have any suggestions to optimize this process?
-P denotes the Gradle Project Property. If you need to use project properties you can specify it as a system property in gradle.properties file in project root directory.
If your task is of type JavaExec you can use --args switch and pass it in Arguments text field of the Gradle Task Run Configuration togenther with the task name like swapSolution -args="-student=MyStudent -exercise=ex05". See also
https://stackoverflow.com/a/48370451/2000323

Gradle - Configure tests includes from property file

I've got a Java project build with Gradle and a property file that contains custom configuration for my testing framework (amount of thread to use, test environment url, custom username & password for those environments, etc...).
I'm facing an issue related to using properties from that file that I can't figure out:
if my Test task include '**/*Test.class', all tests are running as expected.
if my Test task include '**/MyTest.class', only that test is running as expected.
if my Test task include readProperty(), the task is skipped as NO-SOURCE. <- this is the part I can't understand - as the readProperty return the correct value.
Let's get into details:
This is how the property is defined in a my.property file:
testng.class.includes='**/MyTest.class'
This is what the build.gradle file looks like:
Properties props = new Properties()
props.load(new FileInputStream(projectDir.toString() + '/common.properties'))
def testsToRunWorking(p) {
String t = 'MyTest.class'
println "Tests = $t"
return t ? t : '**/*Test.class'
}
def testsToRunNotWorking(p) {
String t = getProperty(p, "testng.class.includes")
println "Tests = $t"
return t ? t : '**/*Test.class'
}
task testCustom(type: Test) {
outputs.upToDateWhen { false }
testLogging.showStandardStreams = true
classpath = configurations.customTest + sourceSets.customTest.output
include testsToRunNotWorking(props) ///< Does not work!
// include testsToRunWorking(props) ///< Works!
useTestNG()
}
In terms of debugging:
The println properly return the value I expect, even when the testCustom task doesn't do what I would expect.
I tried adding a dependsOn task just to print the content of testCustom.configure { println $includes } which looks correct as well.
--info
Tests = '**/MyTest.class'
:clean
:compileCustomTestJava - is not incremental (e.g. outputs have changed, no previous execution, etc.).
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
:processCustomTestResources
:customTestClasses
:testCustom NO-SOURCE
The core of the issue seems to be coming from the fact that I'm reading that value from property. I hard coded inside the build.gradle everything works as expected. If read from a property file - build stops with a NO-SOURCE statement.
Any idea?
Thanks!
You are using quotation marks in the values of your property files. Everything that comes after the assignment sign in a property file is used as value, so the quotation marks remain in the string. They are printed in your output Tests = '**/MyTest.class'. On the other hand, if you define a string in your (Groovy) code with quotation marks, they are not included in the string. Therefor, the passed strings are not the same.
Remove the quotation marks from your property file(s) and everything should work, since the class files will match your string without the quotation marks.

Gradle clean erasing my file prior to ZIP task execution

I have the following simple task in my build:
task generateFile << {
def file = new File("$buildDir/setclasspath.sh")
file.text = "sample"
outputs.file(file)
}
task createDistro(type: Zip, dependsOn: ['copyDependencies','packageEnvironments','jar', 'generateFile']) <<{
from generateClasspathScript {
fileMode = 0755
into 'bin'
}
}
When I run gradle clean build I see the following output:
Cannot call TaskOutputs.file(Object) on task ':generateFile' after task has started execution. Check the configuration of task ':generateFile' as you may have misused '<<' at task declaration
How do I declare the task file creation outputs as an input to the zip task while also ensuring they happen in the execution phase?
If I leave off the << then the clean task wipes the generated file before the ZIP can use it. If I keep them, I get the above error.
It's the opposite as what is being suggested in the comments. You are trying to set the outputs in execution phase. The correct way to do what you are probably trying to do is for example:
task generateFile {
def file = new File("$buildDir/setclasspath.sh")
outputs.file(file)
doLast {
file.text = "sample"
}
}

include not found copySpec / Sync task Gradle

I'm trying to sync specific files from a dir with Gradle. But I get a odd error that I can't seem to solve. If there is a better (working) way to filter files while syncing that would also be welcome.
Implementation 1
def updateAbstractsContentSpec = copySpec {
from('../../base') {
includes "../../base/shared/**/*_abstract.*"
}
}
task updateAbstracts(type: Sync) {
group 'build'
with updateAbstractsContentSpec
}
Error 1
Error:(24, 0) Could not find method includes() for arguments [../../base/shared/**/*_abstract.*] on object of type org.gradle.api.internal.file.copy.CopySpecWrapper_Decorated.
Implementation 2 (Preferable)
task updateAbstracts(type: Sync) {
group 'build'
from '../../base'
includes '../../base/shared/**/*_abstract.*'
}
Error 2
Error:(23, 0) Could not find method includes() for arguments [../../base/shared/**/*_abstract.*] on task ':apps:TestApp1:updateAbstracts' of type org.gradle.api.tasks.Sync.
I assume that its clear what I try to do. I hope that somebody can help me with this.
As of Gradle 3.0 CopySpec documentation, CopySpec does not contain includes method.
You should use include instead:
task updateAbstracts(type: Sync) {
group 'build'
from '../../base'
include '../../base/shared/**/*_abstract.*'
}

How to configure lazily a Gradle task?

I'm trying to configure the following custom task:
task antecedeRelease(type: AntecedeReleaseTask) {
antecedeWithVersion = project.'antecede-with-version'
antecedeToVersion = project.'antecede-to-version'
}
The problem is that the properties antecede-with-version and antecede-to-version are to be set through the command line with a -P option. If they're not set and antecedeRelease isn't being called, that shouldn't be a cause for an error:
$ ./gradlew tasks
org.gradle.api.GradleScriptException: A problem occurred evaluating project ...
Caused by: groovy.lang.MissingPropertyException: Could not find property 'antecede-with-version' on project ...
I could conditionally define the antecedeRelease task such that it's defined only if those properties are defined but I'd like to keep the build.gradle file as clean as possible.
If you need the antecedeRelease task to run "lazily" as-in, at the end of the configuration phase, or at the beginning of the execution phase, your best bet is to use doFirst
task antecedeRelease(type: AntecedeReleaseTask) {
doFirst {
antecedeWithVersion = project.'antecede-with-version'
antecedeToVersion = project.'antecede-to-version'
}
}
One option might be to use Groovy's elvis operator like so:
task antecedeRelease(type: AntecedeReleaseTask) {
antecedeWithVersion = project.ext.get('antecede-with-version') ?: 'unused'
antecedeToVersion = project.ext.get('antecede-with-version') ?: 'unused'
}
If this fails still, you can consider project.ext.has('property') when setting the value.

Resources