Using Environment Variables in GoCD

Accessing environment variables in tasks

Every task in GoCD is provided with a set of environment variables, as a part of the context, when it is run. Depending on the kind of process used in the task, environment variables are accessed differently. Presented below are some common usage scenarios, with the assumption that a job has been configured with an environment variable called ENV_VAR_1, with the value VALUE_1.

1. Using an environment variable in a custom command on Unix/Linux

A very common use case for environment variables is to use them as arguments for a custom command (“exec task” in GoCD). Assuming that you want to pass the environment variable ENV_VAR_1 to the ls command, you might be tempted to try something like this:

Figure 1: Wrong usage of environment variable

Figure 1: Wrong usage of environment variable in custom command task (Will not work)

When run, it will end with a message like this:

Figure 2: Result of wrong usage of environment variable

Figure 2: Result of wrong usage of environment variable in custom command task

As you can see, the environment variable, $ENV_VAR_1 was passed in literally to the command ls and was not interpolated. What is happening here is that GoCD is directly executing the command and passing in the parameters, without involving a shell like bash or sh in the middle. When a command such as ls $ENV_VAR_1 is executed from the command-line, the shell process is the one that interpolates the environment variable and replaces it with its value, so that the ls command does not see it.

So, we need to do the same here. The correct way to invoke this, so that the interpolation of the environment variable works is like this:

Figure 3: Correct usage of environment variable

Figure 3: Correct usage of environment variable in custom command task

When run, it will end with a message like this:

Figure 4: Result of correct usage of environment variable

Figure 4: Result of correct usage of environment variable in custom command task

Even though the command failed in this example, the value of the environment variable was interpolated. You can replace ls with some other command, but the concept remains the same.

2. Using an environment variable in a custom command on Windows

This is easier than using it in a shell script because, on Windows GoCD agents, commands are executed by wrapping them in cmd /c. So, environment variables get interpolated automatically. So, with a configuration such as this:

Figure 5: Usage of environment variable on Windows

Figure 5: Usage of environment variable on Windows

When run, it will end with a message like this:

Figure 6: Result of usage of environment variable on Windows

Figure 8: Result of usage of environment variable on Windows

Similarly, it works when used in a batch file (say, “env_var.cmd”), with content such as this:

  1. echo Environment variable ENV_VAR_1 is: %ENV_VAR_1%

Notice that, unlike on Unix/Linux, the way to access an environment variable on Windows is to use %, instead of $.

3. Using an environment variable in a shell-script - On Unix/Linux

Using an environment variable inside a shell-script is not special at all. You can directly use it, as you would any environment variable. For instance, a shell-script with this content, will work when executed normally:

  1. #!/bin/sh
  2. echo "Value of environment variable ENV_VAR_1 is: $ENV_VAR_1"

This works when executed directly, with a config such as this:

Figure 9: Usage of environment variable in a shell-script

Figure 9: Usage of environment variable in a shell-script

When run, it will end with a message like this:

Figure 10: Result of usage of environment variable in a shell-script

Figure 10: Result of usage of environment variable in a shell-script

4. Using an environment variable in a ruby script

Again, using an environment variable inside a ruby script is not special at all. This has been mentioned here, just to show that scripts written in different languages have to use different mechanisms to access environment variables. A ruby script such as this works as expected:

  1. #!/usr/bin/env ruby
  2. puts "Environment variable ENV_VAR_1 has the value: #{ENV['ENV_VAR_1']}"

Standard GoCD environment variables

The examples above mention a custom environment variable set at the job level. However, there are some standard environment variables available during every job run, set by GoCD. They are:

Environment VariableDescriptionExample contents
GOSERVER_URLBase URL for the GoCD server (including the context root)https://127.0.0.1:8154/go
GO_ENVIRONMENT_NAMEThe name of the current environment. This is only set if the environment is specified. Otherwise the variable is not set.Development
GO_PIPELINE_NAMEName of the current pipeline being runmain
GO_PIPELINE_COUNTERHow many times the current pipeline has been run.2345
GO_PIPELINE_LABELLabel for the current pipeline. By default, this is set to the pipeline count (this can be set to a custom pipeline label)1.1.2345
GO_STAGE_NAMEName of the current stage being rundev
GO_STAGE_COUNTERHow many times the current stage has been run1
GO_JOB_NAMEName of the current job being runlinux-firefox
GO_TRIGGER_USERUsername of the user that triggered the build. This will have one of three possible values
  • anonymous - if there is no security
  • username of the user, who triggered the build
  • changes, if SCM changes auto-triggered the build
  • timer, if the pipeline is triggered at a scheduled time
changes
GO_DEPENDENCY_LABEL${pipeline name or material name}The label of the upstream pipeline (when using dependent pipelines). Non alphanumeric characters are replaced with underscores (““). For example, upstream pipeline “pipeline-foo” becomes: GO_DEPENDENCY_LABEL_PIPELINE_FOO. In case material name is specified, for example material “foo” becomes: GO_DEPENDENCY_LABEL_FOO1.0.3456
GO_DEPENDENCY_LOCATOR${pipeline name}The locator of the upstream pipeline (when using dependent pipelines), which can be used to create the URL for RESTful API callsupstream/1.0.3456/dev/1
GOREVISIONThe current source control revision being run (when using only one material)123
GO_REVISION${material name or dest}If you are using more than one material in your pipeline, the revision for each material is available. The environment variable is named with the material’s “materialName” attribute. If “materialName” is not defined, then “dest” directory is used. Non alphanumeric characters are replaced with underscores (““).123
GO_TO_REVISIONIf the pipeline was triggered with a series of source control revisions(say 121 to 123), then this environment variable has the value of the latest revision (when using only one material). This is always same as GO_REVISION.123
GO_TO_REVISION${material name or dest}If you are using more than one material in your pipeline, the ‘to’ revision for each material is available. The environment variable is named with the material’s “materialName” attribute. If “materialName” is not defined, then “dest” directory is used. Non alphanumeric characters are replaced with underscores (““).123
GO_FROM_REVISIONIf the pipeline was triggered with a series of source control revisions(say 121 to 123), then this environment variable has the value of the oldest revision (when using only one material)121
GO_FROM_REVISION${material name or dest}If you are using more than one material in your pipeline, the ‘from’ revision for each material is available. The environment variable is named with the material’s “materialName” attribute. If “materialName” is not defined, then “dest” directory is used. Non alphanumeric characters are replaced with underscores (““).121
GO_MATERIAL_HAS_CHANGEDA boolean value indicating if the material revision has changed since the previous run (when using only one material)true
GO_MATERIAL${material name or dest}HAS_CHANGEDWhen more than one material is configured for your pipeline, a flag would be available for each of the materials available to denote if the corresponding material’s revision has changed since the previous run. The environment variable is named with the material’s “materialName” attribute. If “materialName” is not defined, then “dest” directory is used. Non alphanumeric characters are replaced with underscores (““).false

Use current revision in a build

It is often useful to use the current version control revision number in your build. For example, you might want to use the svn version number in the name of your binary for tracing purposes. GoCD makes much of this information available to your build scripts as environment variables.

Example usages

One material

For this example, we are going to assume we are using a single Subversion repository for our source control system and we have a job set up to call the ant target “dist”.

  • Add the following target to your ant build.xml
  1. <project name="test-build">
  2. <property environment="env" />
  3. <target name="dist">
  4. <echo message="Building pipeline ${env.GO_PIPELINE_NAME}"
  5. file="deploy-${env.GO_REVISION}.txt" />
  6. </target>
  7. </project>
  • Now, when GoCD runs the ‘my-app’ pipeline on revision 123, the file deploy-123.txt will be created, with the following content:
  1. deploy-123.txt
  2. Building pipeline my-app

Multiple materials

For this example we are going to assume we are using a Subversion repository containing the code and a Mercurial repository containing configuration scripts.

  • Ensure the pipeline materials look like this
  1. <pipeline name="multiple-materials">
  2. <materials>
  3. <svn url="..." dest="code" />
  4. <hg url="..." dest="configuration/latest" />
  5. </materials>
  6. ...
  7. </pipeline>
  • Add the following target to your ant build.xml
  1. <project name="my-app">
  2. <property environment="env" />
  3. <target name="dist">
  4. <echo message="Building pipeline ${env.GO_PIPELINE_NAME}"
  5. file="deploy-${env.GO_REVISION_CODE}.txt" />
  6. <echo message="Configuration version: ${env.GO_REVISION_CONFIGURATION_LATEST}"
  7. file="deploy-${env.GO_REVISION_CODE}.txt"
  8. append="true" />
  9. </target>
  10. </project>
  • Now, when GoCD runs the ‘my-app’ pipeline with the code at revision ‘123’ and the configuration at revision ‘59cab75ccf231b9e338c96cff0f4adad5cb7d335’, the file deploy-123.txt will be created with the following content:
  1. deploy-123.txt
  2. Building pipeline my-app
  3. Configuration version: 59cab75ccf231b9e338c96cff0f4adad5cb7d335

Pass environment variables to a job

You can specify variables for Environments, Pipelines, Stages and Jobs. If a variable is specified more than once, the most specific scope is used. For example if you specify variable FOO=’foo’ for an environment, and FOO=’bar’ for a Job, then the variable will have the value ‘bar’ when the job runs.

Setting variables on an environment

You can add variables to an environment by editing the configuration of the environment. Click on the name of the environment to edit configuration.

Using Environment variables - 图9

You specify variables on an environment in the Config XML by adding an < environmentvariables > section to the environment definition.

  1. <environment name="UAT">
  2. <environmentvariables>
  3. <variable name="FOO">
  4. <value>bar</value>
  5. </variable>
  6. <variable name="MULTIPLE_LINES">
  7. <value>Variable values can have
  8. multiple lines (assuming that your operating system supports this correctly).
  9. </value>
  10. </variable>
  11. <variable name="COMPLEX">
  12. <value><![CDATA[<complex
  13. values>]]>
  14. </value>
  15. </variable>
  16. </environmentvariables>
  17. <agents />
  18. <pipelines />
  19. </environment>

You can add variables for a job by editing the job configuration.

Using Environment variables - 图10

You specify variables on an job in the Config XML by adding an < environmentvariables > section to the job definition.

  1. <job name="my-job">
  2. <environmentvariables>
  3. <variable name="FOO">
  4. <value>bar</value>
  5. </variable>
  6. <variable name="MULTIPLE_LINES">
  7. <value>Variable values can have
  8. multiple lines (assuming that your operating system supports this correctly).
  9. </value>
  10. </variable>
  11. <variable name="COMPLEX">
  12. <value><![CDATA[<complex
  13. values>]]>
  14. </value>
  15. </variable>
  16. </environmentvariables>
  17. ...
  18. </job>