Running two Gradle application tasks concurrently in same project - gradle

It looks like when I try to run a second Gradle task for the same project in a different window, the second one blocks on a lock. Is there a straightforward way around this?
What I'm trying to do: My project has a couple server subprojects that both use the application plugin. I'd like to start both (e.g., $ gradle :server1:run) so I could connect and try them out.
I know I can write a task to deploy the two servers to a test area and start them there, but the application:run task is convenient during development for one application, so I'd like to use it for two if possible.
I'm using Gradle 2.7.

Here is what I ended up doing. Rather than using the application plugin's run task, I used installDist, and wrote a simple task to run the generated start script. Then I extended it by creating a simple service script that I stored under src/dist/bin. The script handles start, stop, and status operations. The final result:
ext.installDir = "$buildDir/install/" + project.name
ext.command = "$installDir/bin/" + project.name
task start(type:Exec, dependsOn:'installDist') {
description "Starts the " + applicationName + " application"
workingDir "$installDir"
commandLine "$command", "start"
}
task stop(type:Exec, dependsOn:'installDist') {
description "Stops the " + applicationName + " application"
workingDir "$installDir"
commandLine "$command", "stop"
}
task status(type:Exec, dependsOn:'installDist') {
description "Displays the " + applicationName + " application status"
workingDir "$installDir"
commandLine "$command", "status"
}
Now from the parent project I can just type:
$ gradlew start
to start both servers and
$ gradlew stop
to shut them both down.

Related

GitHub Action Gradle buildBootImage

Spring boot 2.3 onwards comes with Gradle tasks buildBootImage which creates a container and by default pushes it to docker.io/library. How can this task be customized, in the context of Gradle running in GitHub action to push the container to GHCR, ECR, or GCR; ie, when GitHub action executes ./gradlew buildBootImage
Gradle's buildBootImage task comes with the below config parameters block, what's the best way to set these values within the build script and how do we pass these values from GitHub actions?
tasks.getByName<BootBuildImage>("bootBuildImage") {
imageName = "bestway to set image name"
isPublish = true
docker {
publishRegistry {
url = "best way to set container registry URL"
username = "best way to set user name for CR"
password = "best way to set password for CR"
}
}
}

Jenkins Pipeline emailext: How to access build object in pre-send script

I'm using Jenkins ver. 2.150.1 and have some freestyle jobs and some pipeline jobs.
In both job types I am using the emailext plugin, with template and pre-send scripts.
It seems that the build variable, which is available in the freestyle projects, is null in the pipeline projects.
The pre-send script is the following (just an example, my script is more complex):
msg.setSubject(msg.getSubject() + " [" + build.getUrl() + "]")
There is no problem with the msg variable.
In the freestyle job, this script adds the build url to the mail subject.
In the pipeline job, the following is given in the job console:
java.lang.NullPointerException: Cannot invoke method getUrl() on null object
The invocation of emailext in the pipeline job is:
emailext body: '${SCRIPT, template="groovy-html.custom.pipeline.sandbox.template"}',
presendScript: '${SCRIPT, template="presend.sandbox.groovy"}',
subject: '$DEFAULT_SUBJECT',
to: 'user#domain.com'
I would rather find a general solution to this problem (i.e. Access the build variable in a pipeline pre-send script), but would also appreciate any workarounds to my current needs:
Access job name, job number, and workspace folder in a pipeline pre-send script.
I have finally found the answer -
Apparently for presend script in pipeline jobs, the build object does not exist, and instead the run object does. At the time I posted this question this was still undocumented!
Found the answer in this thread
Which got the author to update the description in the wiki:
run - the build this message belongs to (may be used with FreeStyle or Pipeline jobs)
build - the build this message belongs to (only use with FreeStyle jobs)
You can access the build in a script like this:
// findUrl.groovy
def call(script) {
println script.currentBuild.rawBuild.url
// or if you just need the build url
println script.env.BUILD_URL
}
and would call the script like this from the pipeline:
stage('Get build URL') {
steps {
findUrl this
}
}
The currentBuild gives you a RunWrapper object and the rawBuild a Run. Hope this helps.

Gradle HttpFileServer, keep running, but kill on ctrl+c

During my Gradle build I need to run a simple web server to serve some static content. I’m using Gradle’s integrated classes for that.
Here's a very simple version of my build.gradle:
apply plugin: 'groovy'
task server() {
doLast {
def root = new File(project.buildDir, '/site')
def port = 8765
def factory = new SimpleHttpFileServerFactory();
def server = factory.start(root, port)
println "HTTP server started on $port"
}
}
I'm facing the following two issues:
When running gradle server, gradle executes, starts the server, and then quits (with the daemon obviously staying in the background and the server running, which leads to the second problem)
I’ve no possibility to stop the server through gradle. When running gradle server again, I get an exception because the port is in use.
I’d fancy either of the following solutions:
When running gradle server, gradle keeps running until I hit ctrl+c, then the server is killed as well
There are two tasks, gradle startServer and gradle stopServer which are used to start and stop
How can I achieve this or is there a different, better solution?
A little hack-ish but it works, the server task will hang and the SIGKILL will kill the server too
apply plugin: 'groovy'
task server() {
doLast {
def root = new File(project.buildDir, '/site')
def port = 8765
def factory = new SimpleHttpFileServerFactory();
def server = factory.start(root, port)
println "HTTP server started on $port"
while(true) Thread.sleep(1000)
}
}

Running Play service from Gradle

I am attempting to use a Gradle task to run a Play service, but I'm finding the Gradle task will hang (presumably waiting for a return value from the Play bootstrap script).
What I'm doing from the Play side is simply:
sbt dist
Which produces a .zip distribution (like 'myproject.zip'), which I then expand where I want to run this service from.
On the Gradle side, I was thinking I would do something like this:
task start(type: Exec) {
workingDir "myproject/bin"
commandLine './myproject'
}
This does indeed start up the Play service just fine, but the Gradle task will hang indefinitely (until you do a control+C).
The most obvious thing that came to mind to try was something like:
task start(type: Exec) {
workingDir "myproject/bin"
commandLine 'nohup ./myproject &'
}
But that ends in a dead end:
Execution failed for task ':start'.
> A problem occurred starting process 'command 'nohup ./playservicetemplate &''
It seems like this is a really common use case, so I'm wondering if there is an obvious solution that I'm overlooking.
There is perhaps a more Gradle-ish way to do this, but I solved it by leveraging ProcessBuilder. My new task looks like:
task start {
ProcessBuilder builder = new ProcessBuilder("./myproject")
builder.directory(new File("myproject/bin"))
builder.start()
}
Obviously, you can get a lot fancier with this (a quick Google of 'java processbuilder' will net you pages upon pages of examples), but this will do the trick for my purposes.

Jenkins: How to get node name from label to use as a parameter

I need to give a server name to a maven build. During the maven build this server name will be used to make a call that server do some tests on that server.
Our servers have jenkins slaves on them and is grouped using labels
Example
Slaves/Node | Label
Server1 | BackEndServers
Server2 | BackEndServers
Server3 | FrontEndServers
Server4 | FrontEndServers
With Elastic Axis plugin i can say run my Jenkins job on this Node Label (for example on BackEndServers) and the same project will be executed on both of the servers (Server1 & Server2).
In my case I cannot do this as maven is not installed on the BackEndServers where my code is running. But the maven build needs to know about the server names though.
So is there a way how I can get the server names from a label and then run the same job multiple times passsing each servername to the maven build?
Example
Giving that I have the label 'BackEndServers'
obtain a list of node names 'Server1,Server2'
and run my job for each node name and pass a parameter to it
aka
Having Job (with parameter Server1)
Having Job (with parameter Server2)
Use Jenkins environment variables like NODE_NAME in the Maven command of the build job as value for a system property. For example:
mvn clean install -Djenkins.node.name=${NODE_NAME}
In your Maven project (pom.xml) configure the plugin, which requires the node name, with the help of following property: ${jenkins.node.name}
Here are some links - how to trigger Jenkins builds remotely:
How to trigger Jenkins builds remotely and to pass paramter
Triggering builds remotely in Jenkins
Launching a build with parameters
I don't, if it is possible in the way you want it. But the provided information should help you to find a solution.
Try Jenkins.getInstance().getComputer(env.NODE_NAME).getNode() See more on official Doc
In the end I created a 2 jobs.
To interogate the Jenkens nodes for me and build up a string of servers to use
Then use Dynamic Axis lable with the list I have in Job 1 to execute my maven build
In Job 1 - I used The EnjEnv plugin and it has a 'Evaludated Groovy Script' section that basically you can do anything... but it should return a property map. I don't know how to return a value from a Groovy script so this worked kewl for me as I can reference property (or Environment variables) from almost anyware
import hudson.model.*
String labelIWantServersOf = TheLabelUsedOnTheElasticAxisPlugin; // This is the label assosiated with nodes for which i want the server names of
String serverList = '';
for (aSlave in hudson.model.Hudson.instance.slaves) {
out.println('Evaluating Server(' + aSlave.name + ') with label = ' + aSlave.getLabelString());
if (aSlave.getLabelString().indexOf(labelIWantServersOf ) > -1) {
serverList += aSlave.name + ' ';
out.println('Valid server found: ' + aSlave.name);
}
}
out.println('Final server list where SOAP projects will run on = ' + serverList + ' which will be used in the environment envInject map');
Map<String, String> myMap = new HashMap<>(2);
myMap.put("serverNamesToExecuteSoapProjectOn", serverList );
return myMap;
Then I had some issue to pass the Environment var onto my next job. So I simply wrote the values that I wanted to a property file using a windows batc script in the Build process
echo serverNamesToExecuteSoapProjectOn=%serverNamesToExecuteSoapProjectOn%> baseEnvMap.properties
Then as a post build action I had a "Trigger parameterized build on other projects' calling my 2nd job and I passed the baseEnvMap.properties to it.
Then on my Job 2 which is a Multiconfig job I added a Dynamic Axis using the environment var that was passed via the property file to job 2.
This will duplicate Job 2 and execute it each time with the value that the groovy script build up which I can reference in my mvn arguments.
To list out all nodes of label name LABELNAME:
http://ServerIP:8080/label/LABELNAME/api/json?pretty=true

Resources