how to configure 2 jenkins pipeline trigger with environment variable - jenkins

I have to pass parameter to a timeTrigger function in jenkins pipelineTrigger, but it's not taking that parameter. I have to schedule 2 builds, one for Dev every 8 hours, other for staging every 12 hours.
Question1: Can I trigger 2 builds this way?
Question2: How to pass parameter to specify environment?
See Code below
environmentParam = ['dev', 'qa', 'stg']
originParam = ['Automatic', 'Manual']
if (env.BRANCH_NAME == "master") {
properties([
[$class : 'ParametersDefinitionProperty',
parameterDefinitions:
[
[$class : 'ChoiceParameterDefinition',
choices : environmentParam.join('\n'),
description: 'Environment to run the Integration tests',
name : 'environment'
],
[$class : 'ChoiceParameterDefinition',
choices : originParam.join('\n'),
description: 'The execution of this job was Automatic or Manual',
name : 'origin'
]
]
],
pipelineTriggers(
[
[
$class: 'TimerTrigger', spec: 'H */12 * * *', environment: 'stg'
],
[
$class: 'TimerTrigger', spec: 'H */8 * * *', environment: 'dev'
]
]
),
disableConcurrentBuilds()
])
}
above code is not taking up environment, it is only triggering second entry in pipelineTriggers, not both. :-(

Answer for Questions 1: No, you cannot do it now.
The properties will be set to the jenkins job (config.xml) when pipeline script is executed. Therefore if multiple time trigger is not supported in normal jenkins job, your script will no work as expected as well.
Please execute it and check the jenkins job configuraion and config.xml to understand the result.
Suggestion
Change your solution in another logic (if it is still 8 & 12 hours)
trigger your job to run every 4 hours
keep both choice parameters.
try to have some logical check in steps to run the different stage in different time.

i think you'll have a better time if you create either two or three build plans instead of one.
if you created two, there would be one for dev and one for staging, and they would each have their own trigger and do the appropriate deployment.
if you had three, there would be one (let's call it the "deployment" build plan) that did deployments and that took an TARGET_ENVIRONMENT parameter or similar (with value dev or stg). The other two would have the triggers and they would each call the deployment build plan to do the actual work. you can call another build plan from a Jenkinsfile like this:
build job: 'deployment', parameters: [string(name: 'TARGET_ENVIRONMENT', value: 'dev')]

Related

How to pass choice parameter to call a job inside jenkins pipeline

How can I pass choice parameters for the downstream job when called inside a stage in the jenkins pipeline?
I tried the below solutions but none worked:
stage('build job') {
steps{
script{
build job: 'test',
parameters: [
choice(choices: "option1\noption2\noption3\n", description: '', name: 'choiceParam')
]
}
}
}
fails with java.lang.UnsupportedOperationException: no known implementation of class hudson.model.ParameterValue is using symbol ‘choice’
Tried these as well:
parameters:
[
[$class: 'ChoiceParameterValue', name: 'choiceParam', value: "1\n\2\n3\n"],
]
fails with java.lang.UnsupportedOperationException: no known implementation of class hudson.model.ParameterValue is named ChoiceParameterValue
I actually want to pass the choice parameter as a build parameter like "$choiceParam" for value so that I can just update the jenkins job configuration instead of always updating the values in the pipeline script
Can someone please help me with this
Thanks
When you are building a job via the Build step, you are kicking it off so you need to have "selected" a value.
In this instance you would pass in the desired 'String' choice. Not a list of choices. i.e. "1"
We create our list of params and then pass that in. So: our current job has these input params:
choice(name: 'ENV', choices: product, description: 'Env'),
choice(name: 'ENV_NO', choices: envParams(product), description: 'Env No'),
We pass these downstream by setting them:
List<ParameterValue> newParams = [
new StringParameterValue('ENV', params.ENV),
new StringParameterValue('ENV_NO', params.ENV_NO),
]
build(job: "job", parameters: newParams, propagate: false)

Jenkins - trigger multi-branch pipeline on multiple upstream change

I'm kind of new to Jenkins, I'd like to setup Jenkins trigger for the following case, successful build of either projA or projB should trigger build of projC, I'm using declarative Jenkins syntax, and projA..C are multi-branch projects.
projA --> projC
projB --> projC
I follow the example of #2 from Jenkins: Trigger Multi-branch pipeline on upstream change and setup projC to be triggered on projA (or projB), but not sure the syntax for projC to be triggered either on projA or projB.
In addition, is it possible to pass values from projA and projB to projC as part of the triggering mechanism? What's the syntax if possible.
Any help is appreciated.
This is the code:
pipeline {
agent any
parameters {
string(name: 'MY_BRANCH_NAME', defaultValue: '${env.BRANCH_NAME}', description: 'pass branch value')
string(name: 'MY_VERSION', defaultValue: '1.23', description: 'My version')
}
stages {
stage('Build in dev') {
steps {
echo 'Building dev..'
}
}
}
}
I think you need to look at this from the other way around. Don't think of C looking for A or B to complete. Think of A or B triggering C if they succeed.
In your A and B projects, if you consider the build to be successful by whatever your criteria is, use the build step to trigger C.
If you want to pass simple values to C, make C a parameterized build and pass the parameters in the build step.
post{
success{
build job: 'C', parameters: [booleanParam(name: 'bool1', value: true), string(name: 'foo', value: 'bar')], quietPeriod: 10
}
}

Initialize Jenkins with Pipeline Job

I am building Jenkins with a Dockerfile, and during the Docker build I would like to have Jenkins pre-configured with a set of jobs. I find this works well with Jobs DSL, where jobs are seeded, but I have yet to preconfigure the "Pipeline" DSL. Given the direction of Jenkins and use of Jenkisfile, Pipeline, etc, I think there must be some way to allow Jenkins to automatically run with a set of jobs that were built using the Pipeline approach
Example Pipeline:
pipeline {
agent {
label 'cft'
}
parameters {
string(name: 'StackName', defaultValue: 'cft-stack', description: 'The name to give the CFT stack.')
string(name: 'KeyName', defaultValue: 'ACCOUNT', description: 'The account key to use for encryption.')
string(name: 'VpcId', defaultValue: 'vpc-1234', description: 'The VPC to assign to the cluster resources.')
string(name: 'SubnetID', defaultValue: 'subnet-1234, subnet-6789', description: 'The subnet(s) to assign to the cluster resources.')
stages {
stage('Build') {
steps {
s3Download(file:'cft.yaml'
, bucket:'cft-resources'
, path:'cft.yaml'
, force:true)
cfnUpdate(stack:"${params.StackName}"
, file:"cft.yaml"
, params:[
"SnapshotId=${params.SnapshotId}",
"KeyName=${params.KeyName}",
"VpcId=${params.VpcId}"
]
, timeoutInMinutes: 20
)
}
}
}
post {
failure {
echo 'FAILURE'
cfnDelete(stack:"${params.StackName}")
}
}
}
Dockerfile:
COPY ./groovy/*.groovy /usr/share/jenkins/ref/init.groovy.d/
Pipeline's Groovy files differ from the Groovy code that can be executed to configure Jenkins. You can't add pipelines the way you're trying to do.
Your options include
copy the XML file for the job definition (pointing to your repo, as the pipeline should be in the Jenkinsfile in the repo)
create a job using Groovy and configure it (not really practicable IMHO)
use JobDSL (again, with XML as starting point) to specify your Jenkins jobs. An example for automatically adding this can be found in tknerr/jenkins-pipes-infra.

Jenkins 2 Pipelines - How to model a continuous delivery pipeline

I am completely new to Jenkins 2 pipelines.
I had played with Jenkins 1 pipelines with the following view:
You could start a certain stage directly, let's say that I could choose to start running from the release stage, skipping Test.
I have a pretty simple Jenkins 2 pipeline definition:
stage('Preparation'){
echo """
Preparing
something
"""
}
stage('Greeting') {
parallel 'hello1':{
node{
echo 'hello world 1'
}
}, 'hello2':{
node{
echo 'hello world 2'
}
}
}
In the pipeline page I have "Build now" which runs all stages starting from Preparation.
My questions are:
How can I run the stage I prefer? For instance Greeting instead of starting from Preparation?
How do you define the dependencies between stages? I mean the stage called after another one completes
Is there a way to limit the stages that a certain user can start? Imagine that I only want a specific user to launch the Greeting stage.
How do you setup manual stages?
UPDATE: The real goal behind my questions is the modelling of a continuous delivery pipeline like the following with Jenkins 2 pipelines:
Build stage --> AUTO --> Acceptance Stage --> MANUAL --> Production Stage
--> MANUAL --> QA Stage
This is the behaviour I want:
Build Stage (any user can start it) when it finishes it triggers automatically the Acceptance Stage. This one can't be lauched manually, only automatically after succesfully finishing the Build Stage.
From Acceptance Stage I need that only authorized users can manually trigger QA Stage and Production Stage.
The business flow would be: a developer hits Build Stage, its code is built and packaged. Acceptance Stage begins, using the packaged code to run a bunch of automated tests.
At this point, when Acceptance Stage has finished OK, two things can happen:
Maybe QA Stage is needed to run more tests (Cucumber, manual, etc.). Some some authorized user would fire this stage.
When the product owner is happy, he can decice to launch the Production Stage to deploy the code in a production environment.
I am struggling to model this with Jenkins 2 pipelines.
There is no direct answer to some of your questions but they can be achieved with some additional coding. While certain people might find some other way to achieve but let me try with what I have in my mind:
1) How can I run the stage I prefer? For instance Greeting instead of starting from Preparation?
This could be achieved by adding a Boolean parameter FASTFORWARD_TO_GREETING and than using the value provided while executing build to manipulate the flow of your build. So your code will now look like :
if (FASTFORWARD_TO_GREETING == 'false') {
stage('Preparation'){
echo """
Preparing
something
"""
}
}
stage('Greeting') {
parallel 'hello1':{
node{
echo 'hello world 1'
}
}, 'hello2':{
node{
echo 'hello world 2'
}
}
}
2) How do you define the dependencies between stages? I mean the stage called after another one completes
Stages are executed serially, so if a stage is defined first it'll be started and completed first before moving to the next stage. However in parallel step this does not hold true, as all the steps will be executed in parallel. So in your example code the dependency you have defined is that stage "Preparation" will be executed first and than only "hello1" and "hello2" step will be executed in parallel. However there is no guarantee as to which "hello world1" or "hello world 2" would be printed.
3) Is there a way to limit the stages that a certain user can start? Imagine that I only want a specific user to launch the Greeting stage.
You can have an manual approval step just before some stage. For example, in your code you want stage Preparation to be executed and than you want it to go with manual approval before executing stage Greeting, your code will look something like this:
stage('Preparation'){
echo """
Preparing
something
"""
}
stage concurrency: 1, name: 'approve-greeting'
input id: 'greeting-deploy', message: 'Proceed to Greeting?', ok: 'Deploy'
stage('Greeting') {
parallel 'hello1':{
node{
echo 'hello world 1'
}
}, 'hello2':{
node{
echo 'hello world 2'
}
}
}
What will happen after this is when you execute the build the stage preparation will get executed but after that the job would wait for a manual approval to proceed. In the Jenkins Pipeline view the stage would be called "approve-greeting" and it'll wait until someone approves the build by clicking on it in the view.
4) How do you setup manual stages?
I believe this is answered in answer 3?
Please let me know in case you need further information/explanation.
EDIT:: Please find the further answers below:
Build Stage (any user can start it) when it finishes it triggers
automatically the Acceptance Stage.
Clearly Both the Build Stage and Acceptance Stage will be defined as normal stage in Jenkins pipeline. So your code would be simple like :
node {
//define any variable here
// Get source code from repo using checkout to directory say stackoverflow
// Get source code from repo for acceptance test using checkout to directory say stackoverflow-test
//Define any tool like Maven etc. location if required.
dir('stackoverflow') {
stage name: 'build'
//Do required steps
}
dir('stackoverflow-test') {
stage name: 'Acceptance'
//Do required steps here
}
At this point, when Acceptance Stage has finished OK, two things can
happen:
Maybe QA Stage is needed to run more tests (Cucumber, manual, etc.).
Some some authorized user would fire this stage.
When the product owner is happy, he can decide to launch the Production Stage to deploy the code in a production environment.
This you can do by having input option so after the above piece of code you could now write:
stage 'promotion'
def userInput = input(
id: 'userInput', message: 'Let\'s promote?', parameters: [
[$class: 'BooleanParameterDefinition', defaultValue: false, description: 'Production', name: 'prod'],
[$class: 'BooleanParameterDefinition', defaultValue: false, description: 'ManualQA', name: 'qa']
])
echo ("Env: "+userInput['prod'])
echo ("Target: "+userInput['qa'])
Than you can take the value from above and manipulate the flow again. Like :
If the value of prod is true than proceed to Production stage,
If the value of qa is true than proceed to QA-Manual stage much like my above example code of FASTFORWARD_TO_GREETING.
EDIT 2
Further answering questions on the comment section:
1) How or where do I specify parameters like FASTFORWARD_TO_GREETING
Parameters like FASTFORWARD_TO_GREETING will be defined as Job level parameter
2) In the promotion stage you have to choose between ManualQA and
Production. If the user chooses ManualQA it runs that Stage skipping
Production. After it I want the user to be promted if he wants to
promote to production stage. If you could provide a full definition of
the pipeline it'd be great.
This you could manipulate after MaualQA stage with another input step but this time with only one parameter. So after stage Promotion, there would be stage ManualQA and than after that this below input step:
def userInput1 = input(
id: 'userInput', message: 'Let\'s promote?', parameters: [
[$class: 'BooleanParameterDefinition', defaultValue: false, description: 'Production', name: 'prod']
])
3) How can I determine if a user has permissions to run a stage or
not. Ideally I would like to do it based on roles
I am not sure about how to do it with roles but I believe anyone with administrator access or running that job would have access to run/approve that stage, but I am not 100% sure if it could be somehow modified.
This is a full continuous delivery pipeline built with the indications I got from the accepted anwer:
node{
def user
def userInput
def mvnHome = tool 'M3'
wrap([$class: 'BuildUser']) {
user = env.BUILD_USER_ID
}
stage('Commit Stage'){
echo 'Downloading from Git...'
git 'https://github.com/codependent/spring-nio-rest.git'
'Building project...'
sh "${mvnHome}/bin/mvn clean install -DskipTests"
}
stage('Acceptance Stage') {
echo """
Getting image from Nexus...OK
Deploying image...OK
Executing tests...OK
"""
userInput = input(id: 'userInput', message: 'Select the next stage:', parameters: [
[$class: 'BooleanParameterDefinition', defaultValue: false, description: 'Run QA tests', name: 'QA'],
[$class: 'BooleanParameterDefinition', defaultValue: false, description: 'Run performance tests', name: 'performance']
])
}
if(userInput['QA']){
stage('QA Stage') {
echo """
Getting image from Nexus...OK
Deploying image...OK
Executing QA tests...OK
"""
}
}
if(userInput['performance']){
stage('Performance Stage') {
echo """
Getting image from Nexus...OK
Deploying image...OK
Executing Performance tests...OK
"""
}
}
stage('Production Stage') {
input message: 'Are you sure you want to deploy to Production?', submitter: 'codependent'
echo 'Deploying to Production...OK'
}
}

How can I trigger another job from a jenkins pipeline (jenkinsfile) with GitHub Org Plugin?

How can I trigger build of another job from inside the Jenkinsfile?
I assume that this job is another repository under the same github organization, one that already has its own Jenkins file.
I also want to do this only if the branch name is master, as it doesn't make sense to trigger downstream builds of any local branches.
Update:
stage 'test-downstream'
node {
def job = build job: 'some-downtream-job-name'
}
Still, when executed I get an error
No parameterized job named some-downtream-job-name found
I am sure that this job exists in jenkins and is under the same organization folder as the current one. It is another job that has its own Jenkinsfile.
Please note that this question is specific to the GitHub Organization Plugin which auto-creates and maintains jobs for each repository and branch from your GitHub Organization.
In addition to the above mentioned answers: I wanted to start a job with a simple parameter passed to a second pipeline and found the answer on http://web.archive.org/web/20160209062101/https://dzone.com/refcardz/continuous-delivery-with-jenkins-workflow
So i used:
stage ('Starting ART job') {
build job: 'RunArtInTest', parameters: [[$class: 'StringParameterValue', name: 'systemname', value: systemname]]
}
First of all, it is a waste of an executor slot to wrap the build step in node. Your upstream executor will just be sitting idle for no reason.
Second, from a multibranch project, you can use the environment variable BRANCH_NAME to make logic conditional on the current branch.
Third, the job parameter takes an absolute or relative job name. If you give a name without any path qualification, that would refer to another job in the same folder, which in the case of a multibranch project would mean another branch of the same repository.
Thus what you meant to write is probably
if (env.BRANCH_NAME == 'master') {
build '../other-repo/master'
}
You can use the build job step from Jenkins Pipeline (Minimum Jenkins requirement: 2.130).
Here's the full API for the build step: https://jenkins.io/doc/pipeline/steps/pipeline-build-step/
How to use build:
job: Name of a downstream job to build. May be another Pipeline job, but more commonly a freestyle or other project.
Use a simple name if the job is in the same folder as this upstream Pipeline job;
You can instead use relative paths like ../sister-folder/downstream
Or you can use absolute paths like /top-level-folder/nested-folder/downstream
Trigger another job using a branch as a param
At my company many of our branches include "/". You must replace any instances of "/" with "%2F" (as it appears in the URL of the job).
In this example we're using relative paths
stage('Trigger Branch Build') {
steps {
script {
echo "Triggering job for branch ${env.BRANCH_NAME}"
BRANCH_TO_TAG=env.BRANCH_NAME.replace("/","%2F")
build job: "../my-relative-job/${BRANCH_TO_TAG}", wait: false
}
}
}
Trigger another job using build number as a param
build job: 'your-job-name',
parameters: [
string(name: 'passed_build_number_param', value: String.valueOf(BUILD_NUMBER)),
string(name: 'complex_param', value: 'prefix-' + String.valueOf(BUILD_NUMBER))
]
Trigger many jobs in parallel
Source: https://jenkins.io/blog/2017/01/19/converting-conditional-to-pipeline/
More info on Parallel here: https://jenkins.io/doc/book/pipeline/syntax/#parallel
stage ('Trigger Builds In Parallel') {
steps {
// Freestyle build trigger calls a list of jobs
// Pipeline build() step only calls one job
// To run all three jobs in parallel, we use "parallel" step
// https://jenkins.io/doc/pipeline/examples/#jobs-in-parallel
parallel (
linux: {
build job: 'full-build-linux', parameters: [string(name: 'GIT_BRANCH_NAME', value: env.BRANCH_NAME)]
},
mac: {
build job: 'full-build-mac', parameters: [string(name: 'GIT_BRANCH_NAME', value: env.BRANCH_NAME)]
},
windows: {
build job: 'full-build-windows', parameters: [string(name: 'GIT_BRANCH_NAME', value: env.BRANCH_NAME)]
},
failFast: false)
}
}
Or alternatively:
stage('Build A and B') {
failFast true
parallel {
stage('Build A') {
steps {
build job: "/project/A/${env.BRANCH}", wait: true
}
}
stage('Build B') {
steps {
build job: "/project/B/${env.BRANCH}", wait: true
}
}
}
}
The command build in pipeline is there to trigger other jobs in jenkins.
Example on github
The job must exist in Jenkins and can be parametrized.
As for the branch, I guess you can read it from git
Use build job plugin for that task in order to trigger other jobs from jenkins file.
You can add variety of logic to your execution such as parallel ,node and agents options and steps for triggering external jobs. I gave some easy-to-read cookbook example for that.
1.example for triggering external job from jenkins file with conditional example:
if (env.BRANCH_NAME == 'master') {
build job:'exactJobName' , parameters:[
string(name: 'keyNameOfParam1',value: 'valueOfParam1')
booleanParam(name: 'keyNameOfParam2',value:'valueOfParam2')
]
}
2.example triggering multiple jobs from jenkins file with conditionals example:
def jobs =[
'job1Title'{
if (env.BRANCH_NAME == 'master') {
build job:'exactJobName' , parameters:[
string(name: 'keyNameOfParam1',value: 'valueNameOfParam1')
booleanParam(name: 'keyNameOfParam2',value:'valueNameOfParam2')
]
}
},
'job2Title'{
if (env.GIT_COMMIT == 'someCommitHashToPerformAdditionalTest') {
build job:'exactJobName' , parameters:[
string(name: 'keyNameOfParam3',value: 'valueOfParam3')
booleanParam(name: 'keyNameOfParam4',value:'valueNameOfParam4')
booleanParam(name: 'keyNameOfParam5',value:'valueNameOfParam5')
]
}
}

Resources