Search code examples
jsonjenkinsgroovy

Jenkins pipeline readJSON will read boolean false as null


Let say I have a JSON file myfile.json with this content:

{
    "vm": {
        "MyVal1": false,
        "MyVal2": true,
        "MyVal3": "some string",
    }
}

And my Jenkins pipeline looks like this:

pipeline {
    agent any

    options {
        ansiColor('xterm')
    }

    stages {
        stage('Parse VM details') {
            steps {
                echo "Read VM JSON file"
                script {
                    def props = readJSON file: 'myfile.json'
                    if (props['vm'].get("MyVal1") && (props['vm'].get("MyVal1") == true || props['vm'].get("MyVal1") == false)) {
                        env.MYVAL1 = props['vm'].get("MyVal1")
                    //} else {
                    //    env.VM_ERRORMSG = "MyVal1 is not a boolean."
                    }
                    if (props['vm'].get("MyVal2") && (props['vm'].get("MyVal2") == true || props['vm'].get("MyVal2") == false))
                        env.MYVAL2 = props['vm'].get("MyVal2")
                    //} else {
                    //    env.VM_ERRORMSG = "MyVal2 is not a boolean."
                    }
                    if (props['vm'].get("MyVal3")) {
                        env.MYVAL3 = props['vm'].get("MyVal3")
                    } else {
                        env.VM_ERRORMSG = "MyVal3 is not defined or empty"
                    }
                    echo "MyVal1 will be: ${env.MYVAL1}"
                    echo "MyVal2 will be: ${env.MYVAL2}"
                    echo "MyVal3 will be: ${env.MYVAL3}"
                    if (env.VM_ERRORMSG) {
                        echo "${env.VM_ERRORMSG}"
                    }
                }
            }
        }
    }
}

When I run the pipeline, I got this results:

[Pipeline] echo
MyVal1 will be: null
[Pipeline] echo
MyVal2 will be: true
[Pipeline] echo
MyVal3 will be: some string

So for MyVal2, I get back the boolean as true, but for MyVal1, it is always null, whatever I try. I tried env.MYVAL1 = toBoolean(props['vm'].get("MyVal1")) but it did not help.

Let say the JSON file is not too flexible, so I need to solve it in the Jenkins side. How could I make MyVal1 to appear as boolean even if it is false?

UPDATE:

As suggested in the comments, I found the reason why I get null instead of false. It is because during the testing, it does not enter into the if statement. If I change the corresponding lines in pipeline to:

if (props['vm'].get("MyVal1")) {
    env.MYVAL1 = props['vm'].get("MyVal1")
}
if (props['vm'].get("MyVal2"))
    env.MYVAL2 = props['vm'].get("MyVal2")
}

then still not enter in MyVal1, while in MyVal2, it enters. I don't understand the reason why it works this way, as I don't understand how else could I test that the variable is defined and not empty. If somebody knows the reason and/or have some suggestion to achive my goal, I open for them. :)


Solution

  • your "is boolean" validation is incorrect

    consider the following code which corresponds to if statement in the question:

    def x = false
    if( x && (x==false || x==true) ){
      println "OK"
    }
    

    it will never print "OK" because x = false and first part of the if requires x to be true.

    if( x && (x==false || x==true) ){
      //^ this requires x to be true or groovy "truth"
      println "OK"
    }
    

    the statement in updated question also not correct to validate if there is a value

    if( x ){
      //^ this still requires x to be true or groovy "truth"
      println "OK"
    }
    

    more about groovy truth: https://groovy-lang.org/semantics.html#the-groovy-truth


    so, to resolve an issue - it's better to rework if as this:

    if( x==true || x==false ) {...}
    

    or like this:

    if( x instanceof Boolean ) {...}
    

    and finally, the way you are getting properties could be simplified:

    if( props?.vm?.MyVal1 instanceof Boolean ){ 
      env.MYVAL1=props.vm.MyVal1
    } else {
      env.VM_ERRORMSG="MyVal1 is not a boolean" 
    }