16

What would be the way to determine the current OS a Jenkins pipeline is running?

Context: I'm building a shared Jenkins pipeline script that should run on all platforms (windows, OSX, linux) and execute something different in each platform.

I tried something like:

import org.apache.commons.lang.SystemUtils

if (SystemUtils.IS_OS_WINDOWS){
   bat("Command")
}
if (SystemUtils.IS_OS_MAC){
   sh("Command")
}
if (SystemUtils.IS_OS_LINUX){
   sh("Command")
}

But even it is running on windows or mac node it always goes into the SystemUtils.IS_OS_LINUX branch

I tried a quick pipeline like this.

node('windows ') {
     println ('## OS ' + System.properties['os.name'])
}
node('osx ') {
     println ('## OS ' + System.properties['os.name'])
}
node('linux') {
     println ('## OS ' + System.properties['os.name'])
}

Each node get correctly run in a machine with the correct OS but all of them print ## OS Linux

any ideas?

Thanks Fede

FedeN
  • 386
  • 1
  • 2
  • 10

5 Answers5

21

Assuming you have Windows as your only non-unix platform, you can use the pipeline function isUnix() and uname to check on which Unix OS you're on:

def checkOs(){
    if (isUnix()) {
        def uname = sh script: 'uname', returnStdout: true
        if (uname.startsWith("Darwin")) {
            return "Macos"
        }
        // Optionally add 'else if' for other Unix OS  
        else {
            return "Linux"
        }
    }
    else {
        return "Windows"
    }
}
fedterzi
  • 1,105
  • 7
  • 17
  • I initially appreciated this solution but after I found some problems calling it outside of a pipeline. See my [anser](https://stackoverflow.com/a/61009397/213871) – ceztko Apr 03 '20 at 10:04
16

As far as I know Jenkins only differentiates between windows and unix, i.e. if on windows, use bat, on unix/mac/linux, use sh. So you could use isUnix(), more info here, to determine if you're on unix or windows, and in the case of unix use sh and @Spencer Malone's answer to prope more information about that system (if needed).

Jon S
  • 15,846
  • 4
  • 44
  • 45
  • Thanks [@Jon S](https://stackoverflow.com/users/7509826/jon-s), that's the best answer and works perfectly. – FedeN May 29 '17 at 23:22
4

I initially used @fedterzi answer but I found it problematic because it caused the following crash:

org.jenkinsci.plugins.workflow.steps.MissingContextVariableException: Required context class hudson.Launcher is missing

when attempting to call isUnix() outside of a pipeline (for example assigning a variable). I solved by relying on traditional Java methods to determine Os:

def getOs(){
    String osname = System.getProperty('os.name');
    if (osname.startsWith('Windows'))
        return 'windows';
    else if (osname.startsWith('Mac'))
        return 'macosx';
    else if (osname.contains('nux'))
        return 'linux';
    else
        throw new Exception("Unsupported os: ${osname}");
}

This allowed to call the function in any pipeline context.

ceztko
  • 14,736
  • 5
  • 58
  • 73
  • Can you show a complete example of a working pipeline using this method? I cannot makes this work – jpsecher Apr 15 '21 at 15:06
  • Just declare it outside of the pipeline and call it. [Here](https://stackoverflow.com/a/65182715/213871) is an example of calling a function with a return in a pipeline. – ceztko Apr 15 '21 at 15:50
  • 1
    Thanks, now I just need to figure out how to handle `Scripts not permitted to use staticMethod java.lang.System` – jpsecher Apr 16 '21 at 13:42
  • Good point: depending on the permissions of the users that run the pipeline you may have some restrictions on the ability to run arbitrary scripts. I may actually have similar restrictions to yours in my setup but I solve this problem by using jenkins [shared libraries](https://www.jenkins.io/doc/book/pipeline/shared-libraries/), which is not exactly trivial to add and requires administrator permissions. Best would be find a supported way to retrieve system properties in .jenkins, which I hope it exists. – ceztko Apr 16 '21 at 16:20
  • This is wrong. The `System.getProperty('os.name')` will be executed on the Jenkins controller, not the node. We need to use a function like `sh` that will be executed on the node. – Chris Suszyński Jul 17 '23 at 12:32
  • @ChrisSuszyński good point. This answer was good for me since I didn't use controller/node mode (I still don't). Be sure to post your answer if you manage to create a functionality that works for nodes too. – ceztko Jul 18 '23 at 08:36
3

The workaround I found for this is

try{
   sh(script: myScript, returnStdout: true)
 }catch(Exception ex) {
    //assume we are on windows
   bat(script: myScript, returnStdout: true)
 }

Or a little bit more elegant solution without using the try/catch is to use the env.NODE_LABELS. Assuming you have all the nodes correctly labelled you can write a function like this

def isOnWindows(){
    def os = "windows"
    def List nodeLabels  = NODE_LABELS.split()
    for (i = 0; i <nodeLabels.size(); i++) 
    {
        if (nodeLabels[i]==os){
        return true
        }
   }
    return false
 }

and then

if (isOnWindows()) {
    def osName = bat(script: command, returnStdout: true)   
} else {
    def osName = sh(script: command, returnStdout: true)
}
FedeN
  • 386
  • 1
  • 2
  • 10
0

Using Java classes is probably not the best approach. I'm pretty sure that unless it's a jenkins / groovy plugin, those run on the master Jenkins JVM thread. I would look into a shell approach, such as the one outlined here: https://stackoverflow.com/a/8597411/5505255

You could wrap that script in a shell step to get the stdout like so:

def osName = sh(script: './detectOS', returnStdout: true)

to call a copy of the script being outlined above. Then just have that script return the OS names you want, and branch logic based on the osName var.

Community
  • 1
  • 1
Spencer Malone
  • 1,449
  • 12
  • 12
  • 1
    Hi @spencer-malone, Thanks for your response, but that does not work. `sh()` only works on linux and mac, if that is called in a Windows host it fails with: ` : java.io.IOException: Cannot run program "nohup" (in directory "C:\hudson\workspace\UT_jenkins_pipeline-5OP3ADAIV7CDIC63NI2TISW764YRHIQ2D5YCXCVKLV2UJ32W5XNA"): CreateProces` . – FedeN May 29 '17 at 05:07
  • Sorry, should have specified that msys is probably required. – Spencer Malone May 30 '17 at 12:24