Cant use changeset in JenkinsFile script - jenkins

I have a problem with a step in my jenkinsfile script. I am trying to use when changeset to determine if a particular set of files has changed as I want to only build when certain files are changed. I added this step to call a separate build job if the files are changed.
stage('File check') {
when { changeset "**/files"}
steps {
build 'Build and deploy'
}
}
However I get an error
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 5: Unknown conditional changeset. Valid conditionals are: allOf, anyOf, branch, environment, expression, not # line 5, column 21.
when { changeset "**/files"}
What am I missing? Is it a problem with my version of Jenkins/groovy? Im using Jenkins ver. 2.73.3.

Here is what works for me:
String projectDirectory = "terraform"
String changesetPathRegex = "**/${projectDirectory}/**"
stage('Build Dockerfile') {
when { changeset changesetPathRegex }
steps {
dir(projectDirectory) {
sh 'terraform plan'
}
}
}
Should look in the current repo's "terraform" folders and do the things if it sees a change there.

Related

Jenkins: unable to access the artifacts on the initial run

My setup: main node runs on Linux and an agent on Windows. I want to compile a library on an agent, archive those artifacts and copy them on the main node to create a release togather with the Linux compiled binaries.
This is my Jenkinsfile:
pipeline {
agent none
stages {
stage('Build-Windows') {
agent {
dockerfile {
filename 'docker/Dockerfile-Windows'
label 'windows'
}
}
steps {
bat "tools/ci/build.bat"
archiveArtifacts artifacts: 'build_32/bin/mylib.dll'
}
}
}
post {
success {
node('linux') {
copyArtifacts filter: 'build_32/bin/mylib.dll', flatten: true, projectName: '${JOB_NAME}', target: 'Win32'
}
}
}
}
My problem is, when I run this project for the first time, I get the following error
Unable to find project for artifact copy: mylib
But when I comment the copyArtifacts block and rerun the project, it is successful and I have artifacts vivible in the project overview. After this I can reenable the copyArtifacts and then the artifacts will be copied as expected.
How to configure the pipeline so it can access the artifacts on the initial run?
The copyArtifacts capability is usually used to copy artifacts between different builds and not between agents on the same build. Instead, to achieve what you want you can use the stash and unstash keywords which are designed exactly for passing artifacts from different agents in the same pipeline execution:
stash: Stash some files to be used later in the build.
Saves a set of files for later use on any node/workspace in the same Pipeline run. By default, stashed files are discarded at the end of a pipeline run
unstash: Restore files previously stashed.
Restores a set of files previously stashed into the current workspace.
In your case it can look like:
pipeline {
agent none
stages {
stage('Build-Windows') {
agent {
dockerfile {
filename 'docker/Dockerfile-Windows'
label 'windows'
}
}
steps {
bat "tools/ci/build.bat"
// dir is used to control the path structure of the stashed artifact
dir('build_32/bin'){
stash name: "build_artifact" ,includes: 'mylib.dll'
}
}
}
}
post {
success {
node('linux') {
// dir is used to control the output location of the unstash keyword
dir('Win32'){
unstash "build_artifact"
}
}
}
}

Jenkins pipeline, how can I copy artifact from previous build to current build?

In Jenkins Pipeline, how can I copy the artifacts from a previous build to the current build?
I want to do this even if the previous build failed.
Stuart Rowe also recommended to me on the Pipeline Authoring Sig Gitter channel that I look at the Copy Artifact Plugin, but also gave me some sample Jenkins Pipeline syntax to use.
Based on the advice that he gave, I came up with this fuller Pipeline example
which copies the artifacts from the previous build into the current build,
whether the previous build succeeded or failed.
pipeline {
agent any;
stages {
stage("Zeroth stage") {
steps {
script {
if (currentBuild.previousBuild) {
try {
copyArtifacts(projectName: currentBuild.projectName,
selector: specific("${currentBuild.previousBuild.number}"))
def previousFile = readFile(file: "usefulfile.txt")
echo("The current build is ${currentBuild.number}")
echo("The previous build artifact was: ${previousFile}")
} catch(err) {
// ignore error
}
}
}
}
}
stage("First stage") {
steps {
echo("Hello")
writeFile(file: "usefulfile.txt", text: "This file ${env.BUILD_NUMBER} is useful, need to archive it.")
archiveArtifacts(artifacts: 'usefulfile.txt')
}
}
stage("Error") {
steps {
error("Failed")
}
}
}
}
Suppose you want a single file to from previous build, you can even use curl to place file in workspace before mvn invocation.
stage('Copy csv') {
steps {
sh "mkdir -p ${env.WORKSPACE}/dump"
sh "curl http://<jenkins-url>:<port>/job/<job-folder>/job/<job-name>/job/<release>/lastSuccessfulBuild/artifact/dump/sample.csv/*view*/ -o ${env.WORKSPACE}/dump/sample.csv"
}
}
Thanks,
Ashish
You Can Use Copy Artifact Plugin
For configuration visit https://wiki.jenkins.io/display/JENKINS/Copy+Artifact+Plugin

My jenkinsfile does not compile anymore when trying to add a post build action

My jenkinsfile does not compile anymore when trying to add a POST action. This last one should be displayed to the jenkins console output at the end of build.
Part I is about my jenkinsfile code for which builds are done well.
Part II is the patch added to part I for which any builds fail.
I want to integrate part I and part II to get the expected output described hereafter but integration fails whatever how insertion is made.
I have tried a lot of thing and i'm stucked now, so any help will be appreciate.
// Part I : my base code
node {
def mvnHome
stage('Preparation') {
git 'https://github.com/jglick/simple-maven-project-with- tests.git'
// Get the Maven tool.
// ** NOTE: This 'M3' Maven tool must be configured
// ** in the global configuration.
mvnHome = tool 'M3'
}
stage('Build') {
// Run the maven build
if (isUnix()) {
sh "'${mvnHome}/bin/mvn' -Dmaven.test.failure.ignore clean package"
} else {
bat(/"${mvnHome}\bin\mvn" -Dmaven.test.failure.ignore clean package/)
}
}
stage('Results') {
junit '**/target/surefire-reports/TEST-*.xml'
archiveArtifacts 'target/*.jar'
}
}
// Part II : code to add to the previous code
post {
always {
echo 'I have finished and deleting workspace'
// deleteDir()
}
success {
echo 'Job succeeeded!
}
unstable {
echo 'I am unstable :/'
}
failure {
echo 'I failed :('
}
changed {
echo 'Things were different before...'
}
}
output expected in the console output : 'Job succeeeded! or I am unstable :/ or 'I failed :(' ... depending on the jenkins build status and always clean the workspace before each new build
Actual result is the error message from the console output :
java.lang.NoSuchMethodError: No such DSL method 'post' found among steps [archive, bat, build, catchError, checkout, deleteDir, dir ......
You are mixing up scripted and declarative pipeline syntax. post is part of declarative, but you use the scripted variant (no pipeline, but node steps).
You have to use try/catch.
See the documentation.

Multiple Jenkinsfiles, One Agent Label

I have a project which has multiple build pipelines to allow for different types of builds against it (no, I don't have the ability to make one build out of it; that is outside my control).
Each of these pipelines is represented by a Jenkinsfile in the project repo, and each one must use the same build agent label (they need to share other pieces of configuration as well, but it's the build agent label which is the current problem). I'm trying to put the label into some sort of a configuration file in the project repo, so that all the Jenkinsfiles can read it.
I expected this to be simple, as you don't need this config data until you have already checked out a copy of the sources to read the Jenkinsfile. As far as I can tell, it is impossible.
It seems to me that a Jenkinsfile cannot read files from SCM until the project has done its SCM step. However, that's too late: the argument to agent{label} is read before any stages get run.
Here's a minimal case:
final def config
pipeline {
agent none
stages {
stage('Configure') {
agent {
label 'master'
}
steps {
checkout scm // we don't need all the submodules here
echo "Reading configuration JSON"
script { config = readJSON file: 'buildjobs/buildjob-config.json' }
echo "Read configuration JSON"
}
}
stage('Build and Deploy') {
agent {
label config.agent_label
}
steps {
echo 'Got into Stage 2'
}
}
}
}
When I run this, I get:
java.lang.NullPointerException: Cannot get property 'agent_label' on null object I don't get either of the echoes from the 'Configure' stage.
If I change the label for the 'Build and Deploy' stage to 'master', the build succeeds and prints out all three echo statements.
Is there any way to read a file from the Git workspace before the agent labels need to be set?
Please see https://stackoverflow.com/a/52807254/7983309. I think you are running into this issue. label is unable to resolve config.agent_label to its updated value. Whatever is set in the first line is being sent to your second stage.
EDIT1:
env.agentName = ''
pipeline {
agent none
stages {
stage('Configure') {
agent {
label 'master'
}
steps {
script {
env.agentName = 'slave'
echo env.agentName
}
}
}
stage('Finish') {
steps {
node (agentName as String) { println env.agentName }
script {
echo agentName
}
}
}
}
}
Source - In a declarative jenkins pipeline - can I set the agent label dynamically?

Jenkins Pipeline Wipe Out Workspace

We are running Jenkins 2.x and love the new Pipeline plugin. However, with so many branches in a repository, disk space fills up quickly.
Is there any plugin that's compatible with Pipeline that I can wipe out the workspace on a successful build?
Like #gotgenes pointed out with Jenkins Version. 2.74, the below works, not sure since when, maybe if some one can edit and add the version above
cleanWs()
With, Jenkins Version 2.16 and the Workspace Cleanup Plugin, that I have, I use
step([$class: 'WsCleanup'])
to delete the workspace.
You can view it by going to
JENKINS_URL/job/<any Pipeline project>/pipeline-syntax
Then selecting "step: General Build Step" from Sample step and then selecting "Delete workspace when build is done" from Build step
The mentioned solutions deleteDir() and cleanWs() (if using the workspace cleanup plugin) both work, but the recommendation to use it in an extra build step is usually not the desired solution. If the build fails and the pipeline is aborted, this cleanup-stage is never reached and therefore the workspace is not cleaned on failed builds.
=> In most cases you should probably put it in a post-built-step condition like always:
pipeline {
agent any
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
post {
always {
cleanWs()
}
}
}
You can use deleteDir() as the last step of the pipeline Jenkinsfile (assuming you didn't change the working directory).
In fact the deleteDir function recursively deletes the current directory and its contents. Symbolic links and junctions will not be followed but will be removed.
To delete a specific directory of a workspace wrap the deleteDir step in a dir step.
dir('directoryToDelete') {
deleteDir()
}
Using the following pipeline script:
pipeline {
agent { label "master" }
options { skipDefaultCheckout() }
stages {
stage('CleanWorkspace') {
steps {
cleanWs()
}
}
}
}
Follow these steps:
Navigate to the latest build of the pipeline job you would like to clean the workspace of.
Click the Replay link in the LHS menu.
Paste the above script in the text box and click Run
I used deleteDir() as follows:
post {
always {
deleteDir() /* clean up our workspace */
}
}
However, I then had to also run a Success or Failure AFTER always but you cannot order the post conditions.
The current order is always, changed, aborted, failure, success and then unstable.
However, there is a very useful post condition, cleanup which always runs last, see https://jenkins.io/doc/book/pipeline/syntax/
So in the end my post was as follows :
post {
always {
}
success{
}
failure {
}
cleanup{
deleteDir()
}
}
Hopefully this may be helpful for some corner cases
If you have used custom workspace in Jenkins then deleteDir() will not delete #tmp folder.
So to delete #tmp along with workspace use following
pipeline {
agent {
node {
customWorkspace "/home/jenkins/jenkins_workspace/${JOB_NAME}_${BUILD_NUMBER}"
}
}
post {
cleanup {
/* clean up our workspace */
deleteDir()
/* clean up tmp directory */
dir("${workspace}#tmp") {
deleteDir()
}
/* clean up script directory */
dir("${workspace}#script") {
deleteDir()
}
}
}
}
This snippet will work for default workspace also.
Using the 'WipeWorkspace' extension seems to work as well. It requires the longer form:
checkout([
$class: 'GitSCM',
branches: scm.branches,
extensions: scm.extensions + [[$class: 'WipeWorkspace']],
userRemoteConfigs: scm.userRemoteConfigs
])
More details here: https://support.cloudbees.com/hc/en-us/articles/226122247-How-to-Customize-Checkout-for-Pipeline-Multibranch-
Available GitSCM extensions here: https://github.com/jenkinsci/git-plugin/tree/master/src/main/java/hudson/plugins/git/extensions/impl
For Jenkins 2.190.1 this works for sure:
post {
always {
cleanWs deleteDirs: true, notFailBuild: true
}
}
pipeline {
agent any
tools {nodejs "node"}
environment {
}
parameters {
string(name: 'FOLDER', defaultValue: 'ABC', description: 'FOLDER', trim: true)
}
stages {
stage('1') {
steps{
}
}
stage("2") {
steps {
}
}
}
post {
always {
echo "Release finished do cleanup and send mails"
deleteDir()
}
success {
echo "Release Success"
}
failure {
echo "Release Failed"
}
cleanup {
echo "Clean up in post work space"
cleanWs()
}
}
}
We make sure we are working with a clean workspace by using a feature of the git plugin. You can add additional behaviors like 'Clean before checkout'. We use this as well for 'Prune stale remote-tracking branches'.
In my case, I want to clear out old files at the beginning of the build, but this is problematic since the source code has been checked out.
My solution is to ask git to clean out any files (from the last build) that it doesn't know about:
sh "git clean -x -f"
That way I can start the build out clean, and if it fails, the workspace isn't cleaned out and therefore easily debuggable.
Cleaning up : Since the post section of a Pipeline is guaranteed to run at the end of a Pipeline’s execution, we can add some notification or other steps to perform finalization, notification, or other end-of-Pipeline tasks.
pipeline {
agent any
stages {
stage('No-op') {
steps {
sh 'ls'
}
}
}
post {
cleanup {
echo 'One way or another, I have finished'
deleteDir() /* clean up our workspace */
}
}
}
Currently both deletedir() and cleanWs() do not work properly when using Jenkins kubernetes plugin, the pod workspace is deleted but the master workspace persists
it should not be a problem for persistant branches, when you have a step to clean the workspace prior to checkout scam. It will basically reuse the same workspace over and over again: but when using multibranch pipelines the master keeps the whole workspace and git directory
I believe this should be an issue with Jenkins,
any enlightenment here?
I usually use this:
post {
success {
cleanWs()
}
}

Resources