Jenkins Active Choice param groovy script and static properties - jenkins

I have a Jenkins Freestyle project with multiple Active Choice Parameters, the groovy scripts use some common constant values (also used at later build steps).
Example:
def constant1 = 'bla'
def constant2 = 'blub'
def constant3 = 'umpf'
def val1 = doSomething("$constant1", "$constant2")
return ["$val1", "$constant3"]
Right now these constant values are hard-coded and duplicated in the groovy scripts.
What is the best way of defining such constants?
Remarks:
I thought about moving the groovy code into a scriptler "library" (not tried yet, no experiences yet)
there will be multiple projects, mostly identical, except some constant values will be different
there are other users and other projects on the same jenkins instance (ideally these shall not "see" my constants)
Ideally the configuration of the constants can be done in the Jenkins GUI
Experimented with
"inject env vars to build process" and "properties content"
"prepare env for the run" and "properties content"
From the perspective of a GUI presentation that would be ideal, but seems not to apply to dynamic params phase yet (?)
I have seen solutions reading a props file (like this) but ideally I would like to configure the values inside Jenkins.
System env vars are not an option.

Related

How to deal with Jenkins error "Library ***expected to contain at least one of src or vars directories"

Working on my 6th or 7th Jenkins script now - and I already noticed they share a bit of code (essentially just the same groovy subroutines over and over again). I wouldn't like to continue with that and rather learn some best practices.
It seems that "Shared Libraries" are the thing to do. (Or is there a better way when you just want to share groovy code, not script steps etc.?)
Those scripts are part of a larger repo (that contains the source of the entire project, including the other scripts), stored in a subfolder Jenkins/Library with this structure:
Jenkins/Library
+- vars
| common_code.groovy
There is only a vars folder, no src. The documentation said
For Shared Libraries which only define Global Variables (vars/), or a Jenkinsfile which only needs a Global Variable, the annotation pattern #Library('my-shared-library') _ may be useful for keeping code concise. In essence, instead of annotating an unnecessary import statement, the symbol _ is annotated.
so I concluded that I wouldn't need a src folder and can do with vars alone.
The library is made available via "Configure Jenkins" > "Global Pipeline Libraries" with SourcePath set to "/Jenkins/Library/" and is brought in with the statement #Library('{name}') _ as first line of the script.
However, when attempting to use the library, I get the error shown in the subject.
What's the problem? (I already searched around and found this instance of the problem, but that doesn't seem to fit for my issue - unless I misunderstood something.)
To specify a name of the library you should set the same name in your jenkins settings:
Name.
An identifier you pick for this library, to be used in the #Library
annotation. An environment variable library.THIS_NAME.version will
also be set to the version loaded for a build (whether that comes from
the Default version here, or from an annotation after the #
separator).
Your '{name}' parameter inside of #Library() means you should add a library with the same name. Because it's not a variable like "${name}" which is not a built in variable and undefined.
If you wish to set up your library with the same name as your jenkins pipleine you could use env.JOB_NAME variable, or check the all environment and pre-defined variables:
println env.getEnvironment()
Or check job parameters only:
println params
Now step-by-step instructions:
Create your library, for example from Git SCM as shown on the screenshot.
Put your library code to the project, e.g: <project_root_folder>/vars/common_code.groovy. You don't need your additional path Jenkins/Library. Also you have named your file in 'snake case' style, which is not usual for groovy:
The vars directory hosts scripts that define global variables
accessible from Pipeline. The basename of each *.groovy file should be
a Groovy (~ Java) identifier, conventionally camelCased.
So your file in 'camel case' should looks CommonCode.groovy.
Write your library code:
// vars/commonCode.groovy
// Define your method
def call() {
// do some stuff
return 'Some message'
}
Write your pipeline. Example of scripted pipeline:
#!/usr/bin/env groovy
// yourPipeline.groovy file in your project
#Library('jenkins-shared-library') _
// Get the message from the method in your library
def messageText = commonCode() as String
println messageText
If you wish to define some global variables this answer also may help you.
PS: Using 'vars' folder allows you to load everything from your vars folder once at the same time. If you wish to load dynamically use import from src folder.

Jenkins Extended Choice Parameter associated to multiple environments variable

I am using in a Test Jenkins configuration the Choice Parameter in order to select the target environment against the tests are running.
Like this:
I use the selected value to pass to the maven test run as selected profile: -Dprofile=${TargetEnv}.
I would like to extend the implementation to make some additional git merge operation before the repository is build and the tests are triggered to run (I don't want to go into detail).
My question is how can I use the "Extended Choice Parameter" Jenkin plugin to have multiple environment variable set when a each choice value.
Example: In case the 'dev' is select then I would like to have two environment variables: targetEnv: qa and lowerEnvBranchName: develop-dev.
Somebody know how is possible to specify this kind of variables?

Creating a Generic Jenkins Deployment Template Pipeline

I would like to define a deployment (CD) template that is capable of wrapping build (CI) jobs of various types. I would like the CD template to be completely ignorant of how the downstream CI job is built.
So far my best solution is to define an auxiliary template which is an attribute of the CD template. This auxiliary template includes a reference to the CI job (via the 'select item' type) and a text attribute 'branch'. I found that for the most part this is enough info to trigger the CI job, but is there a better way to do this?
Ideally I would like to be able to define the CI job's parameters directly in the CD job's configuration without needing to have the auxiliary template middle man.
EDIT:
Here's an example of how I'm calling a downstream build job in a different template:
parameterList = []
parameterList.add(new hudson.model.StringParameterValue('stashRepo', stash))
parameterList.add(new hudson.model.StringParameterValue('branch', branch))
parameterList.add(new hudson.model.StringParameterValue('configDir', configDir))
parameterList.add(new hudson.model.StringParameterValue('jdkVersion', jdkVersion))
build job: configBuildJob.buildJob.getFullName(), parameters: parameterList
The problem with this is the template makes the assumption that these build jobs have these exact parameters. It would be nice to be able to somehow set them in the templates configuration instead, so that I don't have to make assumptions about the downstream jobs in my code.

Can a workflow step access environment variables provided by an EnvironmentContributingAction?

A custom plugin we wrote for an older version of Jenkins uses an EnvironmentContributingAction to provide environment variables to the execution so they could be used in future build steps and passed as parameters to downstream jobs.
While attempting to convert our build to workflow, I'm having trouble accessing these variables:
node {
// this step queries an API and puts the results in
// environment variables called FE1|BE1_INTERNAL_ADDRESS
step([$class: 'SomeClass', parameter: foo])
// this ends up echoing 'null and null'
echo "${env.FE1_INTERNAL_ADDRESS} and ${env.BE1_INTERNAL_ADDRESS}"
}
Is there a way to access the environment variable that was injected? Do I have to convert this functionality to a build wrapper instead?
EnvironmentContributingAction is currently limited to AbstractBuilds, which WorkflowRuns are not, so pending JENKINS-29537 which I just filed, your plugin would need to be modified somehow. Options include:
Have the builder add a plain Action instead, then register an EnvironmentContributor whose buildEnvironmentFor(Run, …) checks for its presence using Run.getAction(Class).
Switch to a SimpleBuildWrapper which defines the environment variables within a scope, then invoke it from Workflow using the wrap step.
Depend on workflow-step-api and define a custom Workflow Step with comparable functionality but directly returning a List<String> or whatever makes sense in your context. (code sample)
Since PR-2975 is merged, you are able to use new interface:
void buildEnvVars(#Nonnull Run<?, ?> run, #Nonnull EnvVars env, #CheckForNull Node node)
It will be used by old type of builds as well.

Jenkins get/set data external to job

Does jenkins have any way to set global properties from a job? We have many such needs for this - but specifically - we have a number of slaves, across unix and windows, and various different permissions locations - so it's not easy to have a connected file system. We have various levels of maturity that we promote through - so for instance, we want to promote some build number to UAT - and then promote whatever number is in UAT to training and so on. So - really, in the "release to uat" - we want to store some idea of which build number was released - and read that from the "release to training" job. At the moment we are hacking it by restricting them to run from the same slave, and writing it to a file, which is very much not ideal.
I may not have totally understood your question but you can perform a lot of work with the built in groovy scripting function in jenkins, including reading parameters from other jobs, and rewriting or initializing the parameters in the current job. You can use parameters like this to record information that can be retrieved on demand by other jobs
For instance you can find the build number of the last successful build of a certain project:
import hudson.model.*
def hif = Hudson.instance
def a = hif.getItems(hudson.model.Project).find{it.displayName.toUpperCase()=='MY_PROJECTNAME'}.getBuilds().findAll{it.result==Result.SUCCESS }.first()
out.println a.number //build number
out.println a.buildVariableResolver.resolve('someVariable')// some parameter used to call a
(you could include any other criteria at this point)
If you want to save information to a parameter that can later be read by another bulid step or another job then you first create the parameter in the job config, then write to it in code like so:
import hudson.model.*
def hif = Hudson.instance
def buildMap = build.getBuildVariables()
buildMap['MySpecialVar']='SomeValue'
setBuildParameters(buildMap)
def setBuildParameters(map) {
def npl = new ArrayList<StringParameterValue>()
for (e in map) {
npl.add(new StringParameterValue(e.key.toString(), e.value.toString()))
}
def newPa = null
def oldPa = build.getAction(ParametersAction.class)
if (oldPa != null) {
build.actions.remove(oldPa)
newPa = oldPa.createUpdated(npl)
} else {
newPa = new ParametersAction(npl)
}
build.actions.add(newPa)
}
Combining these techniques you could for instance:
Save a bunch of information as 'output parameters' in job one
Find the most recent successful instance of job one and read its parameters
If necessary save those parameters to job2's parameter list so they are accessible from other build steps.
OR
If you are happy to use files then you may be able to use the archive plugin, where you would write to a file and then archive it as a post build action. The file would be saved to the master, and you could use the 'copy artifacts from another project' option in the second build to retrieve the file. You can use parameter filters and the techniques above to pick the right build.
Setting an environment variable permanently is entirely dependent on the underlying Operating System.
For example on Windows, the SetX command can be used, however note that SetX only takes affect after the next process is created by the system the inherits from global configuration. So, if you run SetX, and then run another job, it will not notice the change. However if you run SetX, and then restart Jenkins process (from which all child jobs inherit variables), then the other job will notice the change.
Not sure how to set permanent variables in Linux, but a quick Google search returns this answer: https://unix.stackexchange.com/questions/117467/how-to-permanently-set-environmental-variables

Resources