Keywords: Jenkins | Groovy | Environment Variables
Abstract: This article provides an in-depth exploration of creating environment variables in Jenkins through Groovy scripts, specifically focusing on version number processing scenarios. It details implementation methods for Jenkins 1.x and 2.x versions, including the use of ParametersAction class, security parameter settings, and system property configurations. Through code examples and step-by-step explanations, it helps readers understand core concepts and avoid common pitfalls.
In Jenkins automated build processes, dynamically creating environment variables is a common requirement, particularly when handling parameters like version numbers. This article will use a specific scenario as an example: extracting the first two numerical parts from an input version number and storing them as a new environment variable. We will conduct a thorough analysis of Groovy script implementation methods and explore compatibility issues across different Jenkins versions.
Problem Analysis and Initial Attempt
The user attempted to use the following Groovy code to extract the first two numerical parts from the environment variable currentversion:
def env = System.getenv()
def version = env['currentversion']
def m = version =~ /\d{1,2}/
env = ['miniVersion': m[0].m[1]]
This code has several critical issues: First, it attempts to directly modify the env variable, but this only changes the local variable reference rather than the actual system environment variables. Second, the approach of directly concatenating after regex matching is not robust enough and doesn't consider version number separator handling. Most importantly, creating persistent environment variables in Jenkins requires specific API calls.
Jenkins 1.x Solution
For Jenkins 1.x versions, the correct implementation method is using the ParametersAction class. The following code demonstrates the complete solution:
import hudson.model.*
def env = System.getenv()
def version = env['currentversion']
def m = version =~ /\d{1,2}/
def minVerVal = m[0] + "." + m[1]
def pa = new ParametersAction([
new StringParameterValue("miniVersion", minVerVal)
])
Thread.currentThread().executable.addAction(pa)
The core logic of this code is as follows: First, match the numerical parts of the version number through regular expressions, then concatenate the first two matches using a period. Next, create a StringParameterValue object to encapsulate the variable name and value, and finally add it to the current build task through ParametersAction.
After successful addition, this variable can be directly used in subsequent build steps:
echo miniVersion=%miniVersion%
The output will display content similar to miniVersion=12.34. It's important to note that this method requires using "System Groovy Script" rather than the ordinary "Groovy Plugin", as the former executes on the Master node with higher privileges.
Jenkins 2.x Security Restrictions and Solutions
Due to security hardening measures in Jenkins 2.x versions, the above method may not work properly. The May 2016 security advisory introduced restrictions on undefined parameters to prevent potential security vulnerabilities.
A short-term solution is to restore the old behavior by setting system properties:
java -Dhudson.model.ParametersAction.keepUndefinedParameters=true -jar jenkins.war
Or more securely, specify allowed parameter names:
java -Dhudson.model.ParametersAction.safeParameters=miniVersion,FOO,BAR -jar jenkins.war
In Groovy scripts, these properties can be set as follows:
System.setProperty("hudson.model.ParametersAction.keepUndefinedParameters", "true")
System.setProperty("hudson.model.ParametersAction.safeParameters", "miniVersion,FOO,BAR")
It's important to note that the keepUndefinedParameters=true setting poses security risks and is only recommended as a temporary solution.
Alternative Implementation Methods
In addition to the main methods described above, other implementation approaches are worth considering. One concise approach is:
import hudson.model.*
def build = Thread.currentThread().executable
def pa = new ParametersAction([
new StringParameterValue("FOO", "BAR")
])
build.addAction(pa)
This method directly obtains the current build object and adds parameters, making the logic clearer. In subsequent Windows batch steps, the variable can be accessed through the !FOO! syntax.
Advanced Usage of ParametersAction Constructor
For situations requiring finer control, the ParametersAction class provides a constructor that accepts additional safe parameter lists:
def pa = new ParametersAction([new StringParameterValue("FOO", foo)], ["FOO"])
This approach explicitly specifies which parameters are safe, aligning with Jenkins 2.x security best practices. By examining the Jenkins source code, we can see that this constructor is specifically designed for handling security parameter validation.
Best Practices Summary
In practical applications, it's recommended to follow these principles: First, always prioritize using Jenkins' official APIs over directly manipulating system environment variables. Second, adopt appropriate implementation strategies for different Jenkins versions, particularly paying attention to security restrictions in 2.x versions. Third, for version number processing, consider using more robust regular expressions, such as /\d+(?:\.\d+)*/ to match various version number formats. Finally, consider encapsulating variable creation logic as reusable functions or shared libraries to improve code maintainability.
Through the detailed analysis in this article, readers should gain a comprehensive understanding of various methods for creating environment variables in Jenkins using Groovy and their applicable scenarios. Proper implementation of this functionality will significantly enhance the flexibility and configurability of build processes.