Resetting the UP-TO-DATE property of gradle tasks? - groovy

Is there a way I can force a gradle task to run again, or reset all tasks back to the not UP-TO-DATE state?

Try to run your build with -C rebuild that rebuilds Gradle's cache.
In newer versions of Gradle, use --rerun-tasks

If you want just a single task to always run, you can set the outputs property inside of the task.
outputs.upToDateWhen { false }
Please be aware that if your task does not have any defined file inputs, Gradle may skip the task, even when using the above code. For example, in a Zip or Copy task there needs to be at least one file provided in the configuration phase of the task definition.

You can use cleanTaskname
Let's say you have
:someproject:sometask1 UP-TO-DATE
:someproject:sometask2 UP-TO-DATE
:someproject:sometask3 UP-TO-DATE
And you want to force let's say sometask2 to run again you can
someproject:cleanSometask2
before you run the task that runs it all.
Apparently in gradle, every task that understands UP-TO-DATE also understand how to clean itself.

I had a tough case where setting outputs.upToDateWhen { false } inside the task or adding the flag --rerun-tasks didn't help since the task's setOnlyIf kept being set to false each time I ran it.
Adding the following to build.gradle forced the execution of myTask:
gradle.taskGraph.whenReady { taskGraph ->
def tasks = taskGraph.getAllTasks()
tasks.each {
def taskName = it.getName()
if(taskName == 'myTask') {
println("Found $taskName")
it.setOnlyIf { true }
it.outputs.upToDateWhen { false }
}
}
}

You can run:
./gradlew clean
It will force the gradle to rebuild.

Related

Puppet : Copy files only IF the package needs to be installed to the latest

I'm a puppet beginner - so bear with me :)
I'm trying to write a module that does the following :
Check if a package is installed with the latest version in the repos
If the package needs to be installed, then config files will be copied from puppet source location, to client. Then the package will be installed
Once files are copied and package installed, run the script that will use the config files on the client to apply the necessary settings.
Once all of this are done, remove the copied files on client
I've come up with the following :
class somepackage(
$package_files_base = "/var/tmp",
$package_setup = "/var/tmp/package-setup.sh",
$ndc_file = "/var/tmp/somefile.ndc",
$osd_file = "/var/tmp/somefile.osd",
$nds_file = "/var/tmp/somefile.nds",
$configini_file = "/var/tmp/somefile.ini",
$required_files = ["$package_setup", "$ndc_file", "$osd_file", $nds_file", "$configini_file"])
{
package { 'some package':
ensure => 'latest',
notify => Exec['Package Setup'],
}
file { 'Package Setup Files':
path => $package_files_base,
ensure => directory,
replace => false,
recurse => true,
source => "puppet:///modules/somepackage/${::domain}",
mode => '0755',
}
exec { 'Package Setup':
command => "$package_setup",
logoutput => true,
timeout => 1800,
require => [ File['Package Setup Files']],
refreshonly => true,
notify => Exec['Remove config files'],
}
exec { 'Remove config files':
path => ['/usr/bin','/usr/sbin','/bin','/sbin'],
command => "rm \"${package_setup}\" \"${ndc_file}\" \"${osd_file}\" \"${nds_file}\" \"${configini_file}\"",
refreshonly => true,
}
}
While this achieves most of what I want to do, I notice that upon rerunning puppet apply the files, although they were being removed, were being recopied.
I can understand why this happens, but I don't know how to code it so that the files get copied ONLY if the package gets updated/installed (e.g. package wasn't installed or old). Otherwise the files will get copied over and over again every time puppet runs every 30 min (default setup) on the client I assume... I tried using the replace => false to prevent this but that just means the files wont ever get removed from /var/tmp after the first run of the class, because it only prevents subsequent runs of the class to re-copy the files (from my testing). This does prevent the redundant, repetitive copying - however I just want the files to be gone the first time!
Is this possible? Head hurts :(
Thanks in advance! We're running Puppet version 3.8.6 on EL7.3.
EDIT: To be clear, this is the bit that I'm struggling with: the resource file { 'Package Setup Files':. This keeps getting files copied even though the package isn't updated/installed. How do I prevent this from happening?
Here are some suggestions.
1) Recommendation for a short term solution
Stop trying to clean up those files if you do not need to. Put them in /opt and forget about them. Better still, have Puppet place a README file in there with them that will explain to your future self and to your fellow admins what they are and why they are there.
While I completely understand the desire to clean up, you need to weigh the cost of having a few old files in a directory somewhere against the cost of having complicated logic in the Puppet code that will not make any sense to anyone in a few months.
This is what I would do and in my experience it is also what most Puppet module authors do with these sorts of set up files.
2) Consider an orchestration framework
That said, it appears to me that you are trying to use Puppet to do operational tasks, and while it can kind of do operational tasks (via features like ensure => latest etc) it is really intended to be a configuration management tool.
I recommend people use Puppet to ensure => installed for packages (make sure Puppet can install the app properly if you need to fully rebuild the node); then delegate the problem of applying version upgrades and hotfixes etc outside of Puppet.
There are a few reasons for this.
Puppet is a declarative configuration management system; your Puppet code should define an end-state. Puppet is not like a shell script, where instead of an end-state, you define steps that change the state of a server imperatively, "one step at a time".
The first problem with ensure => latest is philosophical.
latest does not define a single end-state. The behaviour of your code at time X is different from the behaviour at time Y. So your code is not idempotent.
The second problem is practical. You can never solve the problem of RPM updates in a general way using Puppet, because Puppet can never know about all of the RPMs and their dependencies in your system. So, one way or another, you still need a specialised tool for managing the version updates.
So, since you will need a specialised tool for managing the version updates anyway, it is cleaner to draw a clear boundary between the two tools' roles: always use Puppet to manage the configuration and the initial installation; and then always use the other tool to manage the updates.
Ok, great. I see in your comments that you already have a Red Hat Satellite server, and you have written:
...some hosts within the Satellite have got an older version of the
software within yum. But we don't update this software very
often.....maybe once every year.
So, it sounds like you are using Puppet here to work around a problem in the way you are using Satellite. Is it possible to address this by fixing the way you use Satellite? If so, I think that will be cleaner.
Of course, sometimes the right thing to do is use a work-around, and that's why I provided some other options.
3) If you really really want Puppet to clean up those files
Perhaps move the logic inside a shell script. Something like:
class somepackage {
$shell =
'#!/bin/bash
# maybe use wget instead of puppet to get the files
wget http://a.b/c.tgz
tar zxf c.tgz
# install stuff
# clean up stuff
'
file { '/usr/local/bin/installer.sh':
ensure => file,
mode => '0755',
content => $shell,
}
package { 'some package':
ensure => latest,
notify => Exec['installer'],
}
exec { 'installer':
command => '/usr/local/bin/installer.sh',
refreshonly => true,
require => File['/usr/local/bin/installer.sh'],
}
}

How to open allure from gradle tasks?

I am very new to gradle and trying to write a gradle task to generate and open allure report. I am trying to use gradle node plugin(com.moowork.node) to use the "allure-commandline" nodejs package. The report runs fine when I have a custom node script but not when doing the same thing from gradle from the default allure-commandline script.The report process I think works in background and thus ie does not open.
task allure(type: NodeTask){
script =file('node_modules/allure-commandline/index.js')
args = ["allure","generate","allureResults","--clean","-o","allureReport"]
args = ["allure","open","allureReport"]
}
This Node task works:
task nodeAllure(type: NodeTask){
script =file('allure.js')
}
My allure.js:
var allure = require('allure-commandline');
// returns ChildProcess instance
var generation = allure(['generate', 'reports/allure-results','--clean','-o','allure-report']);
generation.on('exit', function(exitCode) {
allure(['open','allure-report']);
});
There is Allure Gradle plugin available that will handle all the work for you. See the docs for more details https://docs.qameta.io/allure/2.0/#_gradle_3

Jenkins - run child build before aborting the main build

I am looking for a way to make a build run another build right after stoping it (aka clicking a red cross button) but BEFORE actually aborting itself. Post-build Actions is not an option because it will run after the main job is killed/finished, therefore losing the data when child build is run. Passing parameters is also not an option; the reason for this is to keep the parent PID and pass it to second build. I could do it in script and set it as ENV variable but I don't want to do this for each Jenkins job.
Thanks.
You can do this with try catch, the catch block looking like this:
catch (org.jenkinsci.plugins.workflow.steps.FlowInterruptedException e) {
error = e
currentBuild.result = "ABORTED"
build 'your_other_job'
}

How to mark the jenkins build unstable with groovy postbuild

I'm running test cases with nosetests in Jenkins. In general, it will have 100 test cases and I want to mark the build unstable when less than 20 test cases failed. If more than 20 test cases failed, then, mark the build failed.
The command I ran:
nosetests test.py --tc-file config.yml --tc-format yaml
First of all, I tried to just change the status of the build to Unstable but it still failed.
The groovy script I used:
manager.addWarningBadge("Thou shalt not use deprecated methods.")
manager.createSummary("warning.gif").appendText("<h1>You have been warned!</h1>", false, false, false, "red")
manager.buildUnstable()
The first two lines of code are executed, but the job is still marked as Failed.
Is there anything wrong with my jenkins config? Or the groovy postbuild plugin does not work with nosetest?
This is the console output:
FAILED (failures=2)
Build step 'Execute shell' marked build as failure
Build step 'Groovy Postbuild' marked build as failure
Finished: FAILURE
As DevD outlined, FAILED is a more significant build state than UNSTABLE. This means calling manager.buildUnstable() or manager.build.setResult(hudson.model.Result.UNSTABLE) after a step failed will still leave the build result FAILED.
However, you can override a failed build result state to be UNSTABLE by using reflection:
manager.build.#result = hudson.model.Result.UNSTABLE
Below example iterates over the build log lines looking for particular regex. If found it which will change (downgrade) build status, add badges & append to the build summary.
errpattern = ~/TIMEOUT - Batch \w+ did not complete within \d+ minutes.*/;
pattern = ~/INSERT COMPLETE - Batch of \d+ records was inserted to.*/;
manager.build.logFile.eachLine{ line ->
errmatcher=errpattern.matcher(line)
matcher=pattern.matcher(line)
if (errmatcher.find()) {
// warning message
String errMatchStr = errmatcher.group(0) // line matched
manager.addWarningBadge(errMatchStr);
manager.createSummary("warning.gif").appendText("<h4>${errMatchStr}</h4>", false, false, false, "red");
manager.buildUnstable();
// explicitly set build result
manager.build.#result = hudson.model.Result.UNSTABLE
} else if (matcher.find()) {
// ok
String matchStr = matcher.group(0) // line matched
manager.addInfoBadge(matchStr);
manager.createSummary("clipboard.gif").appendText("<h4>${matchStr}</h4>", false, false, false, "black");
}
}
Note: this iterates over every line, so assumes that these matches are unique, or you want a badge & summary appended for every matched line!
Post-build result is:
Build step 'Execute Groovy script' marked build as failure
Archiving artifacts
Build step 'Groovy Postbuild' changed build result to UNSTABLE
Email was triggered for: Unstable
Actually It is the intended way to work.
Preference
FAILED -> UNSTABLE -> SUCCESS
using groovy post build we can change the lower result(SUCCESS) to higher preference(FAILED/UNSTABLE)..
not vise versa.
as workaround after your Nosetest ,add an execute shell and "exit 0". so always your result will be the lower preference. now by your post build groovy script decide your exit criteria based on test results. This is actually a tweak.. will explore more and update you on this.

How to force a Test task to run when the task is defined within a task rule?

I understand that you can force a Test task to run by adding something like below to build.gradle:
tasks.withType( Test ) {
outputs.upToDateWhen { false }
}
However, that doesn't seem to apply to a Test task that is defined inside a task rule. Specifically, I have a task rule as below:
tasks.addRule("Pattern: single<ID>: Run single test.") { String taskName ->
if (taskName.startsWith("single")) {
String pattern = taskName - 'single'
task(taskName, type: Test ) {
outputs.upToDateWhen { false }
include pattern
}
}
}
However, even though I have the first block above in my build.gradle, the task rule always finishes without doing anything. Below is an example output:
$ gradle cleanTest singleBuildInfoScenario000001
:cleanTest UP-TO-DATE
:compileJava UP-TO-DATE
:compileGroovy UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:compileTestJava UP-TO-DATE
:compileTestGroovy UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:singleBuildInfoScenario000001 UP-TO-DATE
BUILD SUCCESSFUL
Total time: 4.868 secs
So, how can I have the corresponding test to run when I use the task rule?
Thank you very much.
I think singleBuildInfoScenario000001 is up-to-date because it doesn't have any tests to run. (Running with --info might give more information.) Looks like the task is missing some configuration information such as classpath and testClassesDir. For an example on how to configure a Test task from scratch, see samples/java/withIntegrationTests in the full Gradle distribution.

Resources