Jenkins copy files error after docker npm build - jenkins-pipeline

I have a script similar to this:
pipeline {
agent {
docker {
label 'dev'
image 'node:12-alpine'
args '-p 3000:3000'
}
}
environment {
HOME = '.'
}
stages {
stage('clone repo') {
steps {
git(
url: '...',
credentialsId: '...',
branch: 'master'
)
}
}
stage('install dependency packages') {
steps {
sh 'npm install'
}
}
stage('build prod ready enviroment') {
steps {
sh 'npm run build'
}
}
stage('deploy') {
agent { node { label 'dev' } }
steps {
sh "cp -rf ./build/* /opt/www_folder/"
}
}
}
}
Now everything works fine except deploy stage which just hangs up building process. If I run only last stage (deploy) separately without other stages it works fine. I think there is a conflict with a docker agent but I don't know how to fix it.

I'm not sure if it is the best answer but I managed to fix my problem with this script:
pipeline {
agent none
environment {
HOME = '.'
}
stages {
stage('clone repo') {
agent { node { label 'dev' } }
steps {
git(
url: '...',
credentialsId: '...',
branch: 'master'
)
}
}
stage('install and build') {
agent {
docker {
label 'dev'
image 'node:12-alpine'
args '-p 3000:3000'
}
}
steps {
sh 'npm install'
sh 'npm run build'
}
}
stage('deploy') {
agent { node { label 'dev' } }
steps {
sh "rm -rf /opt/www_folder/*"
sh "cp -rf ./build/* /opt/www_folder/"
}
}
}
}

Related

Jenkins declarative when condition to check if a variable is NULL

I want to skip Build stage if AMI already exists using declarative syntax.
stage('Build') {
environment {
AMI = sh(returnStdout: true, script: 'aws ec2 describe-images').trim()
}
when {
expression { AMI = null }
}
steps {
sh 'packer build base.json -machine-readable'
}
}
But when I'm running this pipeline I get groovy.lang.MissingPropertyException: No such property: AMI for class: groovy.lang.Binding
At the same time scripted pipeline works perfectly fine
stage('Build') {
steps {
script {
env.AMI = sh(returnStdout: true, script: 'aws ec2 describe-images').trim()
if (env.AMI == '') {
sh 'packer build base.json -machine-readable'
}
}
}
}
}
I'd really love to switch to the declarative pipelines just stuck with this condition. Any help is really appreciated. Thanks
I tried a lot things without any luck
when {
expression {
return AMI.isEmpty()
}
}
when {
not {
expression {
AMI == ''
}
}
when {
not {
expression { env.AMI }
}
}
Nothing works. I suspect it is somehow related to env variable association through sh
You can do something like this.
pipeline {
agent any
stages {
stage('Build') {
when {
expression {
return isAMIAvailable()
}
}
steps {
sh 'packer build base.json -machine-readable'
}
}
}
}
def isAMIAvailable() {
AMI = sh(returnStdout: true, script: 'aws ec2 describe-images').trim()
return AMI == null
}
With #ycr help I was able to build it!
Just in case here is the whole thing
pipeline {
agent any
environment {
ENV = 'dev'
}
stages {
stage('Build') {
when { not { expression { return isAMIAvailable() } } }
steps {
sh 'packer build base.json -machine-readable'
}
}
}
}
def isAMIAvailable() {
AMI = sh(returnStdout: true, script: "aws ec2 describe-images --owners self --filters 'Name=name,Values=base-${ENV}-1' --query 'Images[*].[Name]' --output text").trim()
if (AMI == '') {
return AMI == null
}
return AMI
}

Jenkins pipeline and conditional stages

I want add a condition on all stages:
pipeline {
agent { label 'unix' }
options {
buildDiscarder(logRotator(numToKeepStr: '5', artifactNumToKeepStr: '5'))
}
when {branch 'master' }
stages {
}
}
I find any workaround with add when on each steps but I looking for a solution with only one when
stage('master-branch-stuff') {
when {
branch 'master'
}
steps {
echo 'run this stage - ony if the branch = master branch'
}
}
It can be done this way
declarative pipeline
pipeline {
agent any;
stages {
stage('build') {
when { branch 'master' }
stages {
stage('compile') {
steps {
echo 'compile'
}
}
stage('test') {
steps {
echo 'test'
}
}
stage('package') {
steps {
echo 'package'
}
}
}
}
}
}
scripted pipeline
def branch
node {
stage('checkout') {
def myScm = checkout scm
branch = myScm['branch']
}
if(branch == 'master') {
stage('compile') {
echo "Compile"
}
stage('test') {
echo "Test"
}
stage('package') {
echo "Package"
}
} else {
echo "don't do anything"
}
}
If you want to use pure declarative pipeline, no.
Per their doc, https://www.jenkins.io/doc/book/pipeline/syntax/#when, when is only allowed "inside a stage directive."
stage {
when { ... }
...
}
However, you can add stages within a script block. So you can do something like
stage {
when { ... }
steps {
script {
stage("scripted stage 1") { ... }
stage("scripted stage 2") { ... }
}
}
}
Keep in mind that everything inside of script (including the stages) will follow scripted pipeline rules

How to pass paramaters to remote script in a Jenkins pipeline

I am working on a declarative jenkins pipeline where I am trying to login to remote host and execute shell script. Below is the sample snippet. I want to know How to pass a parameter to my script.sh script.
#!/bin/bash
echo "argument $1"
below is the pipeline script
hosts = [“x.x.x”, “x.x.x”]
pipeline {
agent { node { label 'docker' } }
parameters {
choice(name: 'stageparam', choices: ['build', 'deploy'], description: ‘xyz’)
string(name: 'Username', defaultValue: ‘abc’, description: 'enter username')
}
stages {
stage('Setup') {
steps {
script {
pom = getPom(effective: false)
}
}
}
stage('Deploy') {
steps {
script {
def targetServers = null
if (stageparam == "deploy") {
targetServers = hosts
}
targetServers.each { server ->
echo "Server : ${server}"
def remote = [:]
remote.name = ‘server’
remote.host = server
remote.user = Username
def pass = passwordParameter description: "Enter password for user ${remote.user} "
remote.password = pass
remote.allowAnyHosts = true
stage('Remote SSH') {
sshPut remote: remote, from: ‘./script.sh', into: '.'
sshScript remote: remote, script: "doc.sh ${Username}"
}
}
}
}
}
}
}
getting below error while executing the script
/home/jenkins/workspace/script.sh Username does not exist.
I have written a simple pipeline script to show the usage of variable in bash script.
Pipeline script:
pipeline {
agent any
parameters {
choice(name: 'stageparam', choices: ['build', 'deploy'], description: 'enter stageparam')
string(name: 'USERNAME', defaultValue: 'abc', description: 'enter username')
}
stages {
stage('Git Pull')
{
steps {
checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'gitlab-test', url: 'http://localhost:8076/test-upgrade.git']]])
}
}
stage('Run the python script') {
steps {
sh 'chmod 777 test.py'
sh "python test.py ${env.WORKSPACE}"
}
}
stage('Run the bash script') {
steps {
sh 'chmod 777 run.sh'
sh "./run.sh ${env.USERNAME}"
}
}
}
}
Output:

Globally declare and reuse node in Jenkinsfile

Is there a way to reuse node in different stage without copy/pasting the agent every time?
I have below agent docker in 5 of my stages, it's making file rather big.
pipeline {
agent {
node {
label 'centos'
}
}
stages {
stage('3rd party Scan') {
when {
beforeAgent true
allOf {
triggeredBy 'TimerTrigger'
branch 'master'
}
}
agent {
docker {
reuseNode true
image NODE_DOCKER_IMAGE
args '-u root'
}
}
steps {
script {
sh 'npm ci'
scan.run_scan();
}
}
}
stage('Install') {
when {
beforeAgent true
not { expression { ... } }
}
agent {
docker {
reuseNode true
image NODE_DOCKER_IMAGE
args '-u root'
}
}
steps {
sh 'git clean -fxd'
sh 'npm ci'
}
}
stage('Version') {
agent {
docker {
reuseNode true
image NODE_DOCKER_IMAGE
args '-u root'
}
}
steps {...
}
}
}
}
A stages clause is valid under stage so this might work:
pipeline {
agent {
node {
label 'centos'
}
}
stages {
stage('All Docker Stages') {
agent {
docker {
image NODE_DOCKER_IMAGE
args '-u root'
}
}
stages {
stage('3rd party Scan') {
when {
beforeAgent true
allOf {
triggeredBy 'TimerTrigger'
branch 'master'
}
}
steps {
script {
sh 'npm ci'
scan.run_scan();
}
}
}
stage('Install') {
when {
beforeAgent true
not { expression { ... } }
}
steps {
sh 'git clean -fxd'
sh 'npm ci'
}
}
stage('Version') {
steps {

Template docker agent in jenkins Declarative pipeline

I have a Jenkinsfile for a declarative pipeline that uses docker agents. A number of the steps use a docker agent and it is a bit repetitive adding the same agent for these steps
e.g.
pipeline {
agent any
stages {
stage('Stage 1') {
steps {
//Do something
}
}
stage('Stage 2') {
agent {
docker { image 'jenkins/jenkins-slave:latest'
reuseNode true
registryUrl 'https://some.registry/'
registryCredentialsId 'git'
args '-v /etc/passwd:/etc/passwd -v /etc/group:/etc/group -e HOME=${WORKSPACE}'
}
}
steps {
//Do something
}
}
stage('Stage 3') {
steps {
//Do something
}
}
stage('Stage 4') {
agent {
docker { image 'jenkins/jenkins-slave:latest'
reuseNode true
registryUrl 'https://some.registry/'
registryCredentialsId 'git'
args '-v /etc/passwd:/etc/passwd -v /etc/group:/etc/group -e HOME=${WORKSPACE}'
}
}
steps {
//Do something
}
}
}
}
Is there any way to template the agent (or write my own) so that I could do something like the following
pipeline {
agent any
stages {
stage('Stage 1') {
steps {
//Do something
}
}
stage('Stage 2') {
agent {
my-docker
}
steps {
//Do something
}
}
stage('Stage 3') {
steps {
//Do something
}
}
stage('Stage 4') {
agent {
my-docker
}
steps {
//Do something
}
}
}
}
So that I do not have to repeatly write the same agent and possibly I can reuse it in all my Dockerfiles

Resources