Build job when certain files have been updated - jenkins

I am writing a Jenkinsfile to do a number of checks on a repo. The check runs everytime a PR has been created. The goal of my check is to make sure that in my PR, 2 particularly files (a.txt) and (b.txt) have been changed.
The issue is that these 2 files always must be changed when a PR is issued and I dont want my developers to forget about updating these files. So I want to write a check that fails the build if these 2 files have not been updated. I tried something like this
stage('Check if file changed'){
when {
allOf {
changeset "a.txt"
changeset "b.txt"
}
}
steps {
// Do something
}
}
But the issue with this is that it wants the change to happen in the commit. A developer could create a PR with one file updated and then add another commit to update the other file but this check will always want both files updated in the latest commit. Can someone suggest a way for me to accomplish what I need ? Also in the above case, it doest fail the build if a file is not updated. It just skips the stage. I want the build to fail. Any suggestions ?
Locally running gives me the following output
git diff --name-status master
M CHANGELOG.md
M Jenkinsfile
I want to use this in my jenkins build but there I get the error
+ git diff --name-status master
fatal: ambiguous argument 'master': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
script returned exit code 128

The pattern you have used in allOf{} inside when{} DSL is wrong. It would be something like this
pipeline {
agent any;
stages {
stage('build') {
when {
allOf{
changeset "README.md"; changeset "README-one.md"
}
}
steps {
echo "from build"
}
}
}
}
note : both changeset has to be seperate with ; not , or space. I can see In Jenkins documentation they have mention , - might be thats a mistake

Related

How to access file from git repo in jenkins pipeline

I'm very new to jenkins. I have a monorepo where I need to check what needs to be build. Created a pipeline element in Jenkins, named it Test and copy pasted a script to do a check what files changed:
def changedFiles = currentBuild.changeSets
.collect { it.getItems() }
.flatten() //Ensures that we look through each commit, not just the first.
.collect { it.getAffectedPaths() }
.flatten()
.toSet() //Ensures uniqueness.
echo("Changed files: ${changedFiles}")
def changedDirectories = changedFiles.collect {
if (it.contains('folder/in/monorepo/project/foo')) { //Code cut for simplicity
return "Foo"
}
return ''
}
.unique()
echo("Changed directories: ${changedDirectories}")
if (changedDirectories.contains("Foo")) {
stage('Foo Build') {
node {
env.NODEJS_HOME = "${tool 'NodeJS'}"
env.PATH="${env.NODEJS_HOME}/bin:${env.PATH}"
dir("folder/in/monorepo/buildscripts/") {
sh 'mybuildscript.sh'
}
}
}
} else {
echo("No Foo Build")
}
The code for loading NodeJS is documentend in the NodeJS plugin.
I installed Jenkins, tried some things and then installed NodeJS plugin and updates for other plugins.
Now, with the updated plugins there is some trouble which basically is related to this: Why does Jenkins creates a subfolder within the workspace#script folder to checkout git code instead of the workspace#script itself?
Instead of cloning into the workspace folder, the git repo gets cloned to folder with a unique id.
This leads to the fact, that my folder like in the command dir("folder/in/monorepo/buildscripts/") is not found or to be more precise: It's created and empty and not the one which is in the git repo because it is executed relative to my empty workspace instead relative to the cloned repo.
My questions are:
Is there a much easier way to achieve what I try? AFAIK I need to implement the search for the folder as in the referenced so question.
Doesn't this security fix from the referenced so question breaks all builds / jenkinsfiles? I mean: Eventually in a pipeline someone wants to call a build script, a build tool or a simple make with the makefile in the repo.
EDIT: I just realised that the only reason why the repo is cloned, is because I use the option "Pipeline script from SCM" with "Lightweight checkout" unchecked. I assume that the intended way would be to use a "Lightweight checkout" to just get the Jenkinsfile and then clone the repo as part of the script. A "Pipeline script" written in the gui, would also never get a clone of the repository.

Jenkins : Build not failing even the code is incorrect syntax wise

I missed one of the semicolon to see the red build on the jenkins, while using the Git
public class SpringbootController {
public void callSerivce() {
System.out.println("to check se changes");
System.out.println("to check se changes")
}
}
but still on the jenkins, it is showing the build is successful.
don't know what exactly i missed,please help
newbie in jenkins
is there anything i need to add in the shell to make it work, right now it is empty.
To sum up the conversation in the comments: in order for Jenkins to build your code you need to tell it how to build your code. By default Jenkins doesn't do anything beyond the SCM checkout on its own.
Since you're building a Java project with Maven you should add a Maven build step after your SCM checkout. You will need the Maven Project Plugin.
In your post-build steps you should add an "Archive the artifacts" step to gather up anything built during your job you want to keep since your workspace will get potentially wiped out next run.

Build Pipeline using a Branch Parameter

I seem unable to create a Jenkins Pipeline job that builds a specific branch, where that branch is a build parameter.
Here's some configuration screenshots:
(i've tried with a Git Parameter and a String Parameter, same outcome)
(I've tried $BRANCH_NAME_PARAM, ${BRANCH_NAME_PARAM} and ${env.BRANCH_NAME_PARAM}, same outcome for all variations)
And the build log:
hudson.plugins.git.GitException: Command "git fetch --tags --progress origin +refs/heads/${BRANCH_NAME_PARAM}:refs/remotes/origin/${BRANCH_NAME_PARAM} --prune" returned status code 128:
stdout:
stderr: fatal: Couldn't find remote ref refs/heads/${BRANCH_NAME_PARAM}
at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandIn(CliGitAPIImpl.java:1970)
I'm obviously doing something wrong - any ideas on what?
https://issues.jenkins-ci.org/plugins/servlet/mobile#issue/JENKINS-28447
Appears that its something to do with a lightweight checkout. if i deselect this option in my config, my parameter variables are resolved
a bit more detailed with examples combined with VonC answer
1. Configure extended choice parameter named BRANCH:
specify delimiter
specify groovy script or path to groovy file:
def command = "git ls-remote -h $gitURL"
def proc = command.execute()
proc.waitFor()
if ( proc.exitValue() != 0 ) {
println "Error, ${proc.err.text}"
System.exit(-1)
}
def branches = proc.in.text.readLines().collect {
it.replaceAll(/[a-z0-9]*\trefs\/heads\//, '')
}
return branches.join(",")
2. Set Branches to build: $BRANCH
3. Disable "Lightweight checkout" checkbox in the "Pipeline" secton of Jenkins job configuration:
Otherwise job will fail with following message:"stderr: fatal: Couldn't find remote ref refs/heads/${BRANCH"}"
4. Build with parameter executes groovy script and you will then get a dropdown list of branches
I have tried the above solution but it didn't work for me. I have chosen a slightly different approach. I am posting because it will help someone in future.
Goto configures the pipeline job.
Check the option "This project is parameterized"
Add git paramter.
Note: If it doesn't show the option, please goto manage plugins and install git parameter plugin.
My pipeline Configure looks like
Uncheck lightweight checkout and update the "branch to build" in pipeline section.
Save the configuration.
Each time I had a job based on a branch, I had to put a groovy script with EnvInject plugin in order to remove the ref/heads part of the git branch selected in parameters.
If you keep refs/heads/xxx, Jenkins will look for the branch ref/heads/ref/heads/xxx.

Is there a way to run a pre-checkout step in declarative Jenkins pipelines?

Jenkins declarative pipelines offer a post directive to execute code after the stages have finished. Is there a similar thing to run code before the stages are running, and most importantly, before the SCM checkout?
For example something along the lines of:
pre {
always {
rm -rf ./*
}
}
This would then clean the workspace of my build before the source code is checked out.
pre is a cool feature idea, but doesn't exist yet. skipDefaultCheckout and checkout scm (which is the same as the default checkout) are the keys:
pipeline {
agent { label 'docker' }
options {
skipDefaultCheckout true
}
stages {
stage('clean_workspace_and_checkout_source') {
steps {
deleteDir()
checkout scm
}
}
stage('build') {
steps {
echo 'i build therefore i am'
}
}
}
}
For the moment there are no pre-build steps but for the purpose you are looking for, it can be done in the pipeline job configurarion and also multibranch pipeline jobs, when you define where is your jenkinsfile, choose Additional Behaviours -> Wipe out repository & force clone.
Delete the contents of the workspace before building, ensuring a fully fresh workspace.
If you do not really want to delete everything and save some network usage, you can just use this other option: Additional Behaviours -> Clean before checkout.
Clean up the workspace before every checkout by deleting all untracked files and directories, including those which are specified in .gitignore. It also resets all tracked files to their versioned state. This ensures that the workspace is in the same state as if you cloned and checked out in a brand-new empty directory, and ensures that your build is not affected by the files generated by the previous build.
This one will not delete the workspace but just reset the repository to the original state and pull new changes if there are some.
I use "Prepare an environment for the run / Script Content"

How to check if a pipeline is triggered from a pull request

I'm using Jenkins pipeline to build Pull Requests branches using the GitHub Organization plugin.
I can build them fine, but I want to avoid some steps (such as publishing the artifacts). Checking git's current branch gives me the PR's target since the PR branch is being merged into the target before the build is attempted.
How can I check if the build is being initiated from a PR vs than a regular branch build?
At least on Jenkins 2.16 env.BRANCH_NAME gives the source branch not the target branch. You could do something like:
if (env.BRANCH_NAME == "master") {
sh "./publish.sh"
}
Other env vars that could be useful are the CHANGE_* variables. E.g.,
CHANGE_AUTHOR='me'
CHANGE_ID='6'
CHANGE_TARGET='master'
CHANGE_TITLE='Update README.md'
CHANGE_URL='https://github.com/test-org/test-repo/pull/6'
For documentation on these and more: https://ci.eclipse.org/webtools/env-vars.html/
The env variable CHANGE_ID only exists when the build is triggered from a Pull Request check.
For a multibranch project corresponding to some kind of change request, this will be set to the change ID, such as a pull request number, if supported; else unset.
To specifically detect GitHub pull requests, this can be used:
script {
if (env.BRANCH_NAME == 'master') {
sh 'make'
} else if (env.BRANCH_NAME.startsWith('PR')) {
// do actions for pull request
} else {
// some other branch
}
}
Of course, if you expect to have branches starting with PR on your main repository this wouldn't be reliable. The nice thing about it is that script can be used also in post not just stages, which is useful since when is not allowed in post. If you don't care about that it's worth looking into the when directive. There is some documentation from Cloudbees and Jenkins with some examples.

Resources