The input directive on a stage allows you to prompt for input, using
the input step. ..
(cit. Pipeline Syntax, Jenkins User Documentation https://jenkins.io/doc/book/pipeline/syntax/#input)
So is input actually a directive, or a step? How to understand phrase "using
the input step"
Pipeline used here (extract):
stage('StageName') {
when { environment name: 'VAR1', value: 'true' }
steps {
input {
message: "press OK to continue"
}
dir('doithere') {
git url: gitcoord[0], branch: gitcoord[1], credentialsId: gitcoord[2]
cmd('ls -alh')
}
}
}
Run-time:
WorkflowScript: 336: Expected a step # line 336, column 34.
message: "press OK to continue"
^
In declarative pipeline, you have to put it directly below the stage level ("directive"). Then it is in the form input { .. }.
In scripted pipelines (or script blocks in declarative pipelines), it exists as a normal step. The syntax then is input(..):
stage('StageName') {
when { environment name: 'VAR1', value: 'true' }
steps {
dir('doithere') {
git url: gitcoord[0], branch: gitcoord[1], credentialsId: gitcoord[2]
cmd('ls -alh')
input(message: "press OK to continue")
cmd('rm -rf *')
}
}
}
Below one worked for me:
pipeline {
agent any
stages {
stage('stage1') {
input {
message "press OK to continue"
}
steps {
sh "mkdir dir1"
dir("dir1") {
sh "echo 'Hello'"
}
}
}
}
}
Related
I know how to request for the user input for the whole pipeline using parameters directive. Now i want to be able to request for the user input inside a specific stage and be able to access that value inside the stage. Here's my pipeline:
pipeline {
agent none
stages {
stage('Stage 1') {
when{
beforeAgent true
expression {
timeout (time: 30, unit: "SECONDS"){
input message: 'Should we continue?', ok: 'Yes',
parameters:[[
$class: 'ChoiceParameterDefinition',
choices: ['Stable release', 'SNAPSHOT'],
description: 'Which Version?',
name: 'version'
]]
}
return true
}
}
agent any
steps {
echo 'Checking dependencies ...'
echo "${params}"
}
}
}
}
In this pipeline I'm able to prompt the user to choose between Stable release and SNAPSHOT inside Stage 1 stage. However I'm not able to access this variable using ${params.version}. Any ideas how to solve this?
I managed to work around the problem and read the input chosen by user as in the following pipeline:
def version //define a global variable for the whole pipeline.
pipeline {
agent none
stages {
stage('Stage 1') {
when{
beforeAgent true
expression {
timeout (time: 30, unit: "SECONDS"){
//Assign the variable here.
version = input message: 'Should we continue?', ok: 'Yes',
parameters:[[
$class: 'ChoiceParameterDefinition',
choices: ['Stable release', 'SNAPSHOT'],
description: 'Which Version?',
name: 'v'
]]
}
return true
}
}
agent any
steps {
// And finally access it.
echo "${version}"
}
}
}
}
I think i dont get how matrix builds work. When i set some variable in some stage depending on which node i run, then on rest of the stage sometimes this variable is set as it should and sometimes it gets values from other nodes (axes). In example below its like job which runs on ub18-1 sometimes has VARIABLE1='Linux node' and sometimes is VARIABLE1='Windows node'. Or gitmethod sometimes it is created from LinuxGitInfo and sometimes WindowsGitInfo.
Source i based on
https://jenkins.io/doc/book/pipeline/syntax/#declarative-matrix
Script almost exactly the same as real one
#Library('firstlibrary') _
import mylib.shared.*
pipeline {
parameters {
booleanParam name: 'AUTO', defaultValue: true, description: 'Auto mode sets some parameters for every slave separately'
choice(name: 'SLAVE_NAME', choices:['all', 'ub18-1','win10'],description:'Run on specific platform')
string(name: 'BRANCH',defaultValue: 'master', description: 'Preferably common label for entire group')
booleanParam name: 'SONAR', defaultValue: false, description: 'Scan and gateway'
booleanParam name: 'DEPLOY', defaultValue: false, description: 'Deploy to Artifactory'
}
agent none
stages{
stage('BuildAndTest'){
matrix{
agent {
label "$NODE"
}
when{ anyOf{
expression { params.SLAVE_NAME == 'all'}
expression { params.SLAVE_NAME == env.NODE}
}}
axes{
axis{
name 'NODE'
values 'ub18-1', 'win10'
}
}
stages{
stage('auto mode'){
when{
expression { return params.AUTO }
}
steps{
echo "Setting parameters for each slave"
script{
nodeLabelsList = env.NODE_LABELS.split()
if (nodeLabelsList.contains('ub18-1')){
println("Setting params for ub18-1");
VARIABLE1 = 'Linux node'
}
if (nodeLabelsList.contains('win10')){
println("Setting params for Win10");
VARIABLE1 = 'Windows node'
}
if (isUnix()){
gitmethod = new LinuxGitInfo(this,env)
} else {
gitmethod = new WindowsGitInfo(this, env)
}
}
}
}
stage('GIT') {
steps {
checkout scm
}
}
stage('Info'){
steps{
script{
sh 'printenv'
echo "branch: " + env.BRANCH_NAME
echo "SLAVE_NAME: " + env.NODE_NAME
echo VARIABLE1
gitinfo = new GitInfo(gitmethod)
gitinfo.init()
echo gitinfo.author
echo gitinfo.id
echo gitinfo.msg
echo gitinfo.buildinfo
}
}
}
stage('install'){
steps{
sh 'make install'
}
}
stage('test'){
steps{
sh 'make test'
}
}
}
}
}
}
}
Ok i solved the problem by defining variables maps with node/slave names as keys. Some friend even suggested to define variables in yml/json file in repository and parse them. Maybe i will, but so far this works well
example:
before the pipelines
def DEPLOYmap = [
'ub18-1': false,
'win10': true
]
in stages
when {
equals expected: true, actual: DEPLOYmap[NODE]
}
I am trying to create a pipeline where there are multiple triggers for it - cron, pull request opened and manual. Hence, I wanted to visualize it accordingly.
This is my code with no triggers applied.
pipeline {
agent any
environment {
CI = 'true'
TRIGGER = 'PULL_REQUEST'
}
stages {
stage('Trigger')
{
parallel{
stage('Daily') {
when {
environment name: 'TRIGGER', value: 'DAILY'
}
steps {
sh 'echo "daily build"'
}
}
stage('Pull Request') {
when {
environment name: 'TRIGGER', value: 'PULL_REQUEST'
}
steps {
sh 'echo "pull request trigger"'
}
}
stage('Manual') {
when {
environment name: 'TRIGGER', value: 'MANUAL'
}
steps {
sh 'echo "Manual"'
}
}
}
}
stage('Build') {
steps {
sh 'echo "build step"'
}
}
stage('Test') {
steps {
sh 'echo "test step"'
}
}
stage('Deliver for development') {
when {
environment name: 'CI', value: 'true'
}
steps {
sh 'echo "delivery for development"'
input message: 'Finished using the web site? (Click "Proceed" to continue)'
sh 'echo proceeded'
}
}
stage('Deploy for production') {
when {
environment name: 'CI', value: 'false'
}
steps {
sh 'echo "deploy for production"'
input message: 'Finished using the web site? (Click "Proceed" to continue)'
sh 'echo proceeded'
}
}
}
}
I am able to achieve this with the above code :
Now, my objective is to put the triggers in those parallel stages - Daily, Pull Request and Manual. However, I am not able to do so, as trigger is for the complete pipeline and perhaps expected to appear only once in the pipeline. How can I achieve this effect?
These 3 parallel triggers will set some environment variables which will be used in further stages to modify the pipeline flow accordingly, depending on the type of trigger.
I would like to set the build name and description from a Jenkins Declarative Pipeline, but can't find the proper way of doing it. I tried using an environment bracket after the pipeline, using a node bracket in an agent bracket, etc. I always get syntax error.
The last version of my Jenkinsfile goes like so:
pipeline {
stages {
stage("Build") {
steps {
echo "Building application..."
bat "%ANT_HOME%/bin/ant.bat clean compile"
currentBuild.name = "MY_VERSION_NUMBER"
currentBuild.description = "MY_PROJECT MY_VERSION_NUMBER"
}
}
stage("Unit Tests") {
steps {
echo "Testing (JUnit)..."
echo "Testing (pitest)..."
bat "%ANT_HOME%/bin/ant.bat run-unit-tests"
}
}
stage("Functional Test") {
steps {
echo "Selenium..."
}
}
stage("Performance Test") {
steps {
echo "JMeter.."
}
}
stage("Quality Analysis") {
steps {
echo "Running SonarQube..."
bat "%ANT_HOME%/bin/ant.bat run-sonarqube-analysis"
}
}
stage("Security Assessment") {
steps {
echo "ZAP..."
}
}
stage("Approval") {
steps {
echo "Approval by a CS03"
}
}
stage("Deploy") {
steps {
echo "Deploying..."
}
}
}
post {
always {
junit '/test/reports/*.xml'
}
failure {
emailext attachLog: true, body: '', compressLog: true, recipientProviders: [[$class: 'CulpritsRecipientProvider'], [$class: 'DevelopersRecipientProvider']], subject: '[JENKINS] MY_PROJECT build failed', to: '...recipients...'
}
success {
emailext attachLog: false, body: '', compressLog: false, recipientProviders: [[$class: 'DevelopersRecipientProvider']], subject: '[JENKINS] MY_PROJECT build succeeded', to: '...recipients...'
}
}
}
Error is:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 11: Expected a step # line 11, column 5.
currentBuild.name = "MY_VERSION_NUMBER"
^
WorkflowScript: 12: Expected a step # line 12, column 5.
currentBuild.description = "MY_PROJECT MY_VERSION_NUMBER"
^
Ideally, I'd like to be able to read MY_PROJECT and MY_VERSION_NUMBER from the build.properties file, or from the Jenkins build log. Any guidance about that requirement would be appreciated as well.
UPDATE
Based on the answer I had below, the following worked:
stage("Build") {
steps {
echo "Building application..."
bat "%ANT_HOME%/bin/ant.bat clean compile"
script {
def props = readProperties file: 'build.properties'
currentBuild.displayName = "v" + props['application.version']
}
}
Now the build version is automatically set during the pipeline by reading the build.properties file.
I think this will do what you want. I was able to do it inside a script block:
pipeline {
stages {
stage("Build"){
steps {
script {
currentBuild.displayName = "The name."
currentBuild.description = "The best description."
}
... do whatever.
}
}
}
}
The script is kind of an escape hatch to get out of a declarative pipeline. There is probably a declarative way to do it but i couldn't find it. And one more note. I think you want currentBuild.displayName instead of currentBuild.name In the documentation for Jenkins globals I didn't see a name property under currentBuild.
If you want to set build name to a job from a parameter, you can use
currentBuild.displayName = "${nameOfYourParameter}".
Make sure you use double quotes instead of single quotes.
Job Configuration
Build job with parameter
Build History
REFERENCE: How to set build name in Pipeline job?
I am creating a sample jenkins pipeline, here is the code.
pipeline {
agent any
stages {
stage('test') {
steps {
sh 'echo hello'
}
}
stage('test1') {
steps {
sh 'echo $TEST'
}
}
stage('test3') {
if (env.BRANCH_NAME == 'master') {
echo 'I only execute on the master branch'
} else {
echo 'I execute elsewhere'
}
}
}
}
this pipeline fails with following error logs
Started by user admin
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 15: Not a valid stage section definition: "if (env.BRANCH_NAME == 'master') {
echo 'I only execute on the master branch'
} else {
echo 'I execute elsewhere'
}". Some extra configuration is required. # line 15, column 9.
stage('test3') {
^
WorkflowScript: 15: Nothing to execute within stage "test3" # line 15, column 9.
stage('test3') {
^
But when i execute the following example from this url, it executes successfully and print the else part.
node {
stage('Example') {
if (env.BRANCH_NAME == 'master') {
echo 'I only execute on the master branch'
} else {
echo 'I execute elsewhere'
}
}
}
The only difference i can see is that in the working example there is no stages but in my case it has.
What is wrong here, can anyone please suggest?
your first try is using declarative pipelines, and the second working one is using scripted pipelines. you need to enclose steps in a steps declaration, and you can't use if as a top-level step in declarative, so you need to wrap it in a script step. here's a working declarative version:
pipeline {
agent any
stages {
stage('test') {
steps {
sh 'echo hello'
}
}
stage('test1') {
steps {
sh 'echo $TEST'
}
}
stage('test3') {
steps {
script {
if (env.BRANCH_NAME == 'master') {
echo 'I only execute on the master branch'
} else {
echo 'I execute elsewhere'
}
}
}
}
}
}
you can simplify this and potentially avoid the if statement (as long as you don't need the else) by using "when". See "when directive" at https://jenkins.io/doc/book/pipeline/syntax/. you can also validate jenkinsfiles using the jenkins rest api. it's super sweet. have fun with declarative pipelines in jenkins!
It requires a bit of rearranging, but when does a good job to replace conditionals above. Here's the example from above written using the declarative syntax. Note that test3 stage is now two different stages. One that runs on the master branch and one that runs on anything else.
stage ('Test 3: Master') {
when { branch 'master' }
steps {
echo 'I only execute on the master branch.'
}
}
stage ('Test 3: Dev') {
when { not { branch 'master' } }
steps {
echo 'I execute on non-master branches.'
}
}
If you wanted to create a condition to execute only a stage based on expression you can use keyword when
stage ('test3'){
when { expression { return env.BRANCH_NAME == 'master'} }
steps {
echo 'I only execute on the master branch.'
}
}
}
With the expression key word you can add any condition.
e.g. if stage is dependent on generated file in workspace.
stage ('File Dependent stage'){
when { expression { return fileExists ('myfile') } }
steps {
echo "file exists"
}
}
}
if ( params.build_deploy == '1' ) {
println "build_deploy 是 ${params.build_deploy}"
jobB = build job: 'k8s-core-user_deploy', propagate: false, wait: true, parameters: [
string(name:'environment', value: "${params.environment}"),
string(name:'branch_name', value: "${params.branch_name}"),
string(name:'service_name', value: "${params.service_name}"),
]
println jobB.getResult()
}