If statement in Jenkinsfile, comparing strings not working

I am trying to add a “validation” stage in Jenkinsfile based on the day of the week. If today is Sunday, validation is required, otherwise not.

the if statement is not working

here I am declaring the variable

DAY=sh(returnStdout: true, script: 'date +"%a"').trim()

and here is the stage

stage('validation') {
  steps {
    script {
      if ( DAY == "SUN" ) {
        echo "Validation is required, today is $DAY"
      }
      else {
        echo "No validation required, today is $DAY"
      }
    }
  }
}

and here is the output

No validation required, today is Sun

the value of the variable Day is correct, but the if statement doesnt work correctly

thanks in advance

Solution:

It looks like the comparison is failing because the case of the word in DAY is different.
Try this

      if ( DAY == "Sun" ) {
        echo "Validation is required, today is $DAY"
      }
      else {
        echo "No validation required, today is $DAY"
      }

passing parameters from groovy to python ( Jenkins job)

I am using groovy to call a python in my Jenkins job. i would like to pass few parameters also to the python and i need to use those in the python

I am calling the python like below

result = sh(returnStdout:true , script: '#!/bin/sh -e\n' + 'python test.py').trim()

The parameters i need to pass are jenkins build job parameters.

Can you suggest a solution to this problem.?

Solution:

Try:

cmd = """#!/bin/sh -e\n' + 'python test.py ${JENKINS_VAR_1} ${JENKINS_VAR_1}"""
result = sh(returnStdout:true , script: cmd).trim()

Assuming you already have the code in python to access the argument.

Function .contains() not working in Groovy on expected way

I am trying to check if number is member of list by using Groovy programming language.

I have this piece of code:

List<Long> list = [1, 2, 3]
Long number = 3

println(list.contains(number))​

Expected output is true, but the result I get is false.

Does anybody have an explanation?

Solution:

Generic type parameters don’t feature at runtime. Check this:

List<Long> list = [1, 2, 3]
list.each{println it.getClass()}

Which prints:

class java.lang.Integer
class java.lang.Integer
class java.lang.Integer

The true confusion is introduced by the bizarre behavior difference between .equals and == implementations:

Long.valueOf(3).equals(Integer.valueOf(3))
===> false
Long.valueOf(3) == Integer.valueOf(3)
===> true

List.contains seems to be using .equals, which checks the class of the parameter, thus explaining why forcing element types to Long resolves the problem.

So, in the midst of this uncertainty, I think the only sure thing is that Groovy’s == execution performs the most intuitive and predictable comparison. So I’d change the check to:

boolean contains = list.grep{it == 3L} //sets value to true if matches at least 1

It helps when one doesn’t have to be cognizant of data types linked to literals:

def ints = [1, 2, 3]
def longs = [1L, 2L, 3L]

boolean found1 = ints.grep{it == 3L}
boolean found2 = ints.grep{it == 3}
boolean found3 = longs.grep{it == 3L}
boolean found4 = longs.grep{it == 3}

println found1
println found2
println found3
println found4

Which works as anyone would want:

true
true
true
true

Jenkins pipeline No signature of method: java.util.Collections $UnmodifiableMap.$()

I’m using the Kubernetes Jenkins plugin in order to create Jenkins slaves on demand. The slaves job is to deploy and provision my apps to the Kubernetes cluster.

I created a pipeline project and wrote a very simple Jenkinsfile:

podTemplate(label: 'jenkins-pipeline', containers: [
containerTemplate(name: 'jnlp', image: 'lachlanevenson/jnlp-slave:3.10-1-alpine', args: '${computer.jnlpmac} ${computer.name}', workingDir: '/home/jenkins', resourceRequestCpu: '200m', resourceLimitCpu: '300m', resourceRequestMemory: '256Mi', resourceLimitMemory: '512Mi'),
containerTemplate(name: 'helm', image: 'lachlanevenson/k8s-helm:v2.6.0', command: 'cat', ttyEnabled: true),
containerTemplate(name: 'kubectl', image: 'lachlanevenson/k8s-kubectl:v1.4.8', command: 'cat', ttyEnabled: true),
containerTemplate(name: 'curl', image: 'appropriate/curl:latest', command: 'cat', ttyEnabled: true)
],
volumes:[
    hostPathVolume(mountPath: '/var/run/docker.sock', hostPath: 
'/var/run/docker.sock'),
]){

node ('jenkins-pipeline') {

def pwd = pwd()
def chart_dir = "${pwd}/chart"

checkout([$class: 'SubversionSCM', additionalCredentials: [], excludedCommitMessages: '', excludedRegions: '', excludedRevprop: '', excludedUsers: '', filterChangelog: false, ignoreDirPropChanges: false, includedRegions: '', locations: [[credentialsId: '4041436e-e9dc-4060-95d5-b28be47b1a14', depthOption: 'infinity', ignoreExternalsOption: true, local: '.', remote: 'https://svn.project.com/repo/trunk/RnD/dev/server/src/my-app']], workspaceUpdater: [$class: 'CheckoutUpdater']])

stage ('deploy canary to k8s') {
  container('helm') {
    def version = params.${VERSION}
    def environment = params.${ENVIRONMENT}
    // Deploy using Helm chart

    sh "helm upgrade --install ${version} ${chart_dir} --set imageTag=${version},replicas=1,environment=${environment} --namespace=dev"  

      }
    }
  }
}

The Jenkins slave spins up on Kubernetes but the job fails with this stack trace:

[Pipeline] stage
[Pipeline] { (deploy canary to k8s)
[Pipeline] container
[Pipeline] {
[Pipeline] }
[Pipeline] // container
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // podTemplate
[Pipeline] End of Pipeline
hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: java.util.Collections$UnmodifiableMap.$() is applicable for argument types: (org.jenkinsci.plugins.workflow.cps.CpsClosure2) values: [org.jenkinsci.plugins.workflow.cps.CpsClosure2@7d7d26fa]
Possible solutions: is(java.lang.Object), any(), get(java.lang.Object), any(groovy.lang.Closure), max(groovy.lang.Closure), min(groovy.lang.Closure)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:58)
    at org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.call(PojoMetaClassSite.java:49)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
    at com.cloudbees.groovy.cps.sandbox.DefaultInvoker.methodCall(DefaultInvoker.java:18)
    at WorkflowScript.run(WorkflowScript:20)
    at ___cps.transform___(Native Method)
    at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:57)
    at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:109)
    at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixArg(FunctionCallBlock.java:82)
    at sun.reflect.GeneratedMethodAccessor512.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
    at com.cloudbees.groovy.cps.impl.ClosureBlock.eval(ClosureBlock.java:46)
    at com.cloudbees.groovy.cps.Next.step(Next.java:74)
    at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:154)
    at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:165)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:328)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$100(CpsThreadGroup.java:80)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:240)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:228)
    at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:64)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:112)
    at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:748)
Finished: FAILURE

I understand that the error comes from a type mismatch but I’m having a hard time understanding in which part of the Jenkinsfile and what I should do about it.

Can anyone please help me?

Solution:

This

def version = params.${VERSION}
def environment = params.${ENVIRONMENT}

Should be this

def version = params."${VERSION}"
def environment = params."${ENVIRONMENT}"

How to handle unsigned shorts/ints/longs in Java

I’m reading a file format that specifies some types are unsigned integers and shorts. When I read the values, I get them as a byte array. The best route to turning them into shorts/ints/longs I’ve seen is something like this:

ByteBuffer wrapped = ByteBuffer.wrap(byteArray);
int x = wrapped.getInt();

That looks like it could easily overflow for unsigned ints. Is there a better way to handle this scenario?

Update: I should mention that I’m using Groovy, so I absolutely don’t care if I have to use a BigInteger or something like that. I just want the maximum safety on keeping the value intact.

Solution:

A 32bit value, signed or unsigned, can always be stored losslessly in an int*. This means that you never have to worry about putting unsigned values in signed types from a data safety point of view.

The same is true for 8bit values in bytes, 16bit values in shorts and 64bit values in longs.

Once you’ve read an unsigned value into the corresponding signed type, you can promote them to signed values of a larger types to more easily work with the intended value:

Since there’s no primitive type larger than long, you can either go via BigInteger, or use the convenience methods on Long to do unsigned operations:


* This is thanks to the JVM requiring integer types to be two’s complement.

How to replace github branch inside jenkins job scm from parameter value

I have a jenkins job groovy script like below. I want the Github branch to be taken from the parameter value.

Groovy Script :

 git_url = "git@github.deere.com:ABC/XYZ.git" jenkins_node = "master"
    freeStyleJob('myjob') {
    logRotator(numToKeep = 100)
    parameters {    stringParam("GIT_BRANCH", "master" , "master cert dev")   }
    label(jenkins_node)
    scm {
     git {
      remote { url(git_url) }
      branch($GIT_BRANCH)  
      extensions { }
         }
     }

Solution:

You have to put $GIT_BRANCH variable into single quotes so it is not get parsed by job DSL script. Paste your script to this Job DSL playground app and you will get an exception:

javaposse.jobdsl.dsl.DslScriptException: (script, line 12) No such property: $GIT_BRANCH for class: javaposse.jobdsl.dsl.helpers.scm.GitContext
    at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScriptEngine(AbstractDslScriptLoader.groovy:112)
    at javaposse.jobdsl.dsl.AbstractDslScriptLoader$_runScripts_closure1.doCall(AbstractDslScriptLoader.groovy:59)
    at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScripts(AbstractDslScriptLoader.groovy:46)
    at javaposse.jobdsl.dsl.AbstractDslScriptLoader$runScripts$0.callCurrent(Unknown Source)

But if you add single quotes:

branch('$GIT_BRANCH')

then you will get your job XML file generated correctly:

<!-- 1. myjob -->
<project>
    <actions></actions>
    <description></description>
    <keepDependencies>false</keepDependencies>
    <properties>
        <hudson.model.ParametersDefinitionProperty>
            <parameterDefinitions>
                <hudson.model.StringParameterDefinition>
                    <name>GIT_BRANCH</name>
                    <defaultValue>master</defaultValue>
                    <description>master cert dev</description>
                </hudson.model.StringParameterDefinition>
            </parameterDefinitions>
        </hudson.model.ParametersDefinitionProperty>
    </properties>
    <canRoam>false</canRoam>
    <disabled>false</disabled>
    <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
    <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
    <triggers></triggers>
    <concurrentBuild>false</concurrentBuild>
    <builders></builders>
    <publishers></publishers>
    <buildWrappers></buildWrappers>
    <logRotator>
        <daysToKeep>100</daysToKeep>
        <numToKeep>-1</numToKeep>
        <artifactDaysToKeep>-1</artifactDaysToKeep>
        <artifactNumToKeep>-1</artifactNumToKeep>
    </logRotator>
    <assignedNode>master</assignedNode>
    <scm class='hudson.plugins.git.GitSCM'>
        <userRemoteConfigs>
            <hudson.plugins.git.UserRemoteConfig>
                <url>git@github.deere.com:ABC/XYZ.git</url>
            </hudson.plugins.git.UserRemoteConfig>
        </userRemoteConfigs>
        <branches>
            <hudson.plugins.git.BranchSpec>
                <name>$GIT_BRANCH</name>
            </hudson.plugins.git.BranchSpec>
        </branches>
        <configVersion>2</configVersion>
        <doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations>
        <gitTool>Default</gitTool>
    </scm>
</project>

Here is job DSL I used in the sandbox:

git_url = "git@github.deere.com:ABC/XYZ.git" 
jenkins_node = "master"
freeStyleJob('myjob') {
  logRotator(numToKeep = 100)
  parameters {
    stringParam("GIT_BRANCH", "master" , "master cert dev")   
  }

  label(jenkins_node)
  scm {
    git {
      remote { url(git_url) }
      branch('$GIT_BRANCH')  
      extensions { }
    }
  }
}

Now when you run a job generated from this DSL it will ask you for GIT_BRANCH parameter and the value you pass will be used to set up the branch.

Jenkins Pipeline – Pass Artifact URL between stages

My usecase is to build a Java job , deploy a tar.gz.zip to nexus and pass on this artifact URL to further stages.

I am using the below command in a script that does other validation:

mvn -B clean deploy -U package deploy:deploy -DskipNexusStagingDeployMojo=true -DaltDeploymentRepository=dev-snapshots::default::https://<myrepo.com>

Below would be my stages:

stage('publish'){    
  //push to Nexus  
 }
stage('processing'){    
 // get the artifact url from above step
}

I don’t want to use “archiveartifacts” as I am already storing the artifacts, I do not want to archive it. I just need the URL.

So far , all I could manage was to get the entire output of the deploy to a text file.

sh "deploy.sh > deploy.txt"

However ,new File(deploy.txt) does not work with Pipelines as groovy gets executed on master and file is created on slaves. And readfile(‘deploy.txt’) does not take any regex. So I am not able to parse the file to get the artifact url.

Is there any better way to get the artifact url from publish to processing stage in pipeline?

Solution:

What about storing value in a variable during publish stage and reading this variable during processing stage? Consider following Jenkins pipeline example:

def artifactUrl = ''

pipeline {
    agent any

    stages {
        stage('Build') { 
            steps {
                script {
                   artifactUrl = 'test'
                }
            }
        }

        stage('Publish') {
            steps {
                echo "Current artifactUrl is '${artifactUrl}'"
            }
        }
    }
}

When I run it I get following output:

[Pipeline] node
Running on Jenkins in /var/jenkins_home/workspace/test-pipeline
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Build)
[Pipeline] script
[Pipeline] {
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Publish)
[Pipeline] echo
Current artifactUrl is 'test'
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

Of course there is an open question how you get your artifact URL, but if you only can get it from your publish command then passing it between stages shouldn’t be a problem.

how do I return the body if an httpRequest in the Jenkins DSL?

I have a step that calls a remote URL successfully using the httpRequest step but, I don’t know how to use the body that is returned.

I have set logResponseBody: true but I don’t get any output of the body in the console log.

Solution:

httpRequest plugins returns a response object that exposes methods like e.g.

  • Stirng getContent() – response body as String
  • int getStatus() – HTTP status code

You can use JsonSlurper class to parse your response to a JSON object (if the response you are getting back from the request is JSON type). Consider following exemplary pipeline:

import groovy.json.JsonSlurper

pipeline {
    agent any 
    stages {
        stage('Build') { 
            steps {
                script {
                    def response = httpRequest 'https://dog.ceo/api/breeds/list/all'
                    def json = new JsonSlurper().parseText(response.content)

                    echo "Status: ${response.status}"

                    echo "Dogs: ${json.message.keySet()}"
                }
            }
        }
    }
}

In this example we are connecting to open JSON API (https://dog.ceo/api/breeds/list/all) and we display with echo method two things: HTTP status and a list of all dogs in this JSON response. If you run this pipeline in Jenkins you will see something like that in the console log:

[Pipeline] node
Running on Jenkins in /var/jenkins_home/workspace/test-pipeline
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Build)
[Pipeline] script
[Pipeline] {
[Pipeline] httpRequest
HttpMethod: GET
URL: https://dog.ceo/api/breeds/list/all
Sending request to url: https://dog.ceo/api/breeds/list/all
Response Code: HTTP/1.1 200 OK
Success code from [100‥399]
[Pipeline] echo
Status: 200
[Pipeline] echo
Dogs: [affenpinscher, african, airedale, akita, appenzeller, basenji, beagle, bluetick, borzoi, bouvier, boxer, brabancon, briard, bulldog, bullterrier, cairn, chihuahua, chow, clumber, collie, coonhound, corgi, dachshund, dane, deerhound, dhole, dingo, doberman, elkhound, entlebucher, eskimo, germanshepherd, greyhound, groenendael, hound, husky, keeshond, kelpie, komondor, kuvasz, labrador, leonberg, lhasa, malamute, malinois, maltese, mastiff, mexicanhairless, mountain, newfoundland, otterhound, papillon, pekinese, pembroke, pinscher, pointer, pomeranian, poodle, pug, pyrenees, redbone, retriever, ridgeback, rottweiler, saluki, samoyed, schipperke, schnauzer, setter, sheepdog, shiba, shihtzu, spaniel, springer, stbernard, terrier, vizsla, weimaraner, whippet, wolfhound]
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

Hope it helps.

How to access the inner fields in a json file in Jenkins pipeline using Groovy

{
  "Product": [{
  "flm": [{
       "101": [{
            "value": "R36.0 flm",
            "revision": ["111","11br"]
        }]
        "101.1": [{
            "value": "R36.0 flm",
            "revision": ["111","11br","11we"]
        }]
        "202": [{
            "value": "R37.0 flm",
            "revision": ["111"]
        }]
        "301": [{
            "value": "R38.0 flm",
            "revision": ["222"]
        }]
  }]
  "cod": [{
       "101": [{
            "value": "R36.0 cod",
            "revision": ["111"]
        }]
        "202": [{
            "value": "R37.0 cod",
            "revision": ["111"]
        }]
        "301": [{
            "value": "R38.0 cod",
            "revision": ["222"]
        }]
  }]
  "lsp": [{
       "101": [{
            "value": "R36.0 lsp",
            "revision": ["111","11br"]
        }]
        "202": [{
            "value": "R37.0 lsp",
            "revision": ["111"]
        }]
        "301": [{
            "value": "R38.0 lsp",
            "revision": ["222"]
        }]
  }]
  "urm": [{
       "101": [{
            "value": "R36.0 urm",
            "revision": ["111","11br"]
        }]
        "202": [{
            "value": "R37.0 urm",
            "revision": ["111"]
        }]
        "301": [{
            "value": "R38.0 urm",
            "revision": ["222"]
        }]
    }]

   }]

  }

I want to print/access the value/revision fields in the json file using groovy and compare if it matches my input (“11br” ,R36.0 lsp ) if product is (lsp and 101). I can only reach till 101 and later i am not sure how to extract further values. Any help is appreciated

Solution:

You can use JsonSlurper.parseText(json) for that – it will produce a map of maps that you can traverse and extract interesting values. In your case it is important to mention that you have to deal with lists of objects (usually they contain only one object), so traversing will produce lists of lists etc. In this case Groovy’s .flatten() method is very helpful. Consider following script:

import groovy.json.JsonSlurper

def json = '''
{
  "Product": [
    {
      "flm": [
        {
          "101": [
            {
              "value": "R36.0 flm",
              "revision": [
                "111",
                "11br"
              ]
            }
          ],
          "101.1": [
            {
              "value": "R36.0 flm",
              "revision": [
                "111",
                "11br",
                "11we"
              ]
            }
          ],
          "202": [
            {
              "value": "R37.0 flm",
              "revision": [
                "111"
              ]
            }
          ],
          "301": [
            {
              "value": "R38.0 flm",
              "revision": [
                "222"
              ]
            }
          ]
        }
      ],
      "cod": [
        {
          "101": [
            {
              "value": "R36.0 cod",
              "revision": [
                "111"
              ]
            }
          ],
          "202": [
            {
              "value": "R37.0 cod",
              "revision": [
                "111"
              ]
            }
          ],
          "301": [
            {
              "value": "R38.0 cod",
              "revision": [
                "222"
              ]
            }
          ]
        }
      ],
      "lsp": [
        {
          "101": [
            {
              "value": "R36.0 lsp",
              "revision": [
                "111",
                "11br"
              ]
            }
          ],
          "202": [
            {
              "value": "R37.0 lsp",
              "revision": [
                "111"
              ]
            }
          ],
          "301": [
            {
              "value": "R38.0 lsp",
              "revision": [
                "222"
              ]
            }
          ]
        }
      ],
      "urm": [
        {
          "101": [
            {
              "value": "R36.0 urm",
              "revision": [
                "111",
                "11br"
              ]
            }
          ],
          "202": [
            {
              "value": "R37.0 urm",
              "revision": [
                "111"
              ]
            }
          ],
          "301": [
            {
              "value": "R38.0 urm",
              "revision": [
                "222"
              ]
            }
          ]
        }
      ]
    }
  ]
}
'''

def root = new JsonSlurper().parseText(json)
def lsp101 = root.Product.lsp.'101'.flatten()

def value = lsp101.value.first()
def revisions = lsp101.revision.flatten()

def expectedValue = 'R36.0 lsp'
def expectedRevision = '11br'

assert expectedValue == value && expectedRevision in revisions

It extracts value and a list of revisions for path $.Product.lsp.101 and compares with expected values. Hope it helps understanding how can you work with JSON in Groovy. For more information and examples don’t hesitate to visit Groovy manual page that describes how to work with JSON in details – http://groovy-lang.org/json.html

Groovy script for Jenkins: execute HTTP request without 3rd party libraries

I need to create a Groovy post build script in Jenkins and I need to make a request without using any 3rd party libraries as those can’t be referenced from Jenkins.

I tried something like this:

def connection = new URL( "https://query.yahooapis.com/v1/public/yql?q=" +
    URLEncoder.encode(
            "select wind from weather.forecast where woeid in " + "(select woeid from geo.places(1) where text='chicago, il')",
            'UTF-8' ) )
    .openConnection() as HttpURLConnection

// set some headers
connection.setRequestProperty( 'User-Agent', 'groovy-2.4.4' )
connection.setRequestProperty( 'Accept', 'application/json' )

// get the response code - automatically sends the request
println connection.responseCode + ": " + connection.inputStream.text

but I also need to pass a JSON in the POST request and I’m not sure how I can do that. Any suggestion appreciated.

Solution:

Executing POST request is pretty similar to a GET one, for example:

import groovy.json.JsonSlurper

// POST example
try {
    def body = '{"id": 120}'
    def http = new URL("http://localhost:8080/your/target/url").openConnection() as HttpURLConnection
    http.setRequestMethod('POST')
    http.setDoOutput(true)
    http.setRequestProperty("Accept", 'application/json')
    http.setRequestProperty("Content-Type", 'application/json')

    http.outputStream.write(body.getBytes("UTF-8"))
    http.connect()

    def response = [:]    

    if (http.responseCode == 200) {
        response = new JsonSlurper().parseText(http.inputStream.getText('UTF-8'))
    } else {
        response = new JsonSlurper().parseText(http.errorStream.getText('UTF-8'))
    }

    println "response: ${response}"

} catch (Exception e) {
    // handle exception, e.g. Host unreachable, timeout etc.
}

There are two main differences comparing to GET request example:

  1. You have to set HTTP method to POST

    http.setRequestMethod('POST')
    
  2. You write your POST body to outputStream:

    http.outputStream.write(body.getBytes("UTF-8"))
    

    where body might be a JSON represented as string:

    def body = '{"id": 120}'
    

Eventually it’s good practice to check what HTTP status code returned: in case of e.g. HTTP 200 OK you will get your response from inputStream while in case of any error like 404, 500 etc. you will get your error response body from errorStream.