Unable to Create New file in Jenkins Pipeline - jenkins

I am trying to create New file in Jenkins Pipeline , by getting error.
error:
java.io.FileNotFoundException: /var/lib/jenkins/workspace/Pipeline-Groovy/test.txt (No such file or directory)
But when i am executing below commands without pipeline , It's created new file
def newFile = new File("/var/lib/jenkins/workspace/test/test.txt")
newFile.append("hello\n")
println newFile.text
If i use same code in Pipeline getting above error
pipeline {
agent any
options {
buildDiscarder(logRotator(numToKeepStr: '5'))
timestamps()
}
stages {
stage('Demo1-stage') {
steps {
deleteDir()
script {
def Jobname = "${JOB_NAME}"
echo Jobname
}
}
}
stage('Demo-2stage') {
steps {
script {
def workspace = "${WORKSPACE}"
echo workspace
def newFile = new File("/var/lib/jenkins/workspace/Pipeline-Groovy/test.txt")
newFile.createNewFile()
sh 'ls -lrt'
}
}
}
}
}

It looks like your folder is not present. Do not give absolute path while creating the file unless it is a requirement. I see that in your case, you need a file in workspace. Always use the ${WORKSPACE} to get the current work directory.
def newFile = new File("${WORKSPACE}/test.txt")
newFile.createNewFile()

Related

How to integrate Jenkins pipeline jobs and pass dynamic variables using Groovy?

I want to integrate Jenkins jobs using Groovy by passing dynamic variables based on the projects for which the job is triggered.
Can anyone please suggest on how to proceed with this?
Looks like you would like to persist data between two jenkins jobs or two runs of the same jenkins job. In both cases, I was able to do this using files. you can use write file to do it using groovy or redirection operator (>) to just use bash.
In first job, you can write to the file like so.
node {
// write to file
writeFile(file: 'variables.txt', text: 'myVar:value')
sh 'ls -l variables.txt'
}
In second job, you can read from that file and empty the contents after you read it.
stage('read file contents') {
// read from the file
println readFile(file: 'variables.txt')
}
The file can be anywhere on the filesystem. Example with a file created in /tmp folder is as follows. You should be able to run this pipeline by copy-pasting.
node {
def fileName = "/tmp/hello.txt"
stage('Preparation') {
sh 'pwd & rm -rf *'
}
stage('write to file') {
writeFile(file: fileName, text: "myvar:hello", encoding: "UTF-8")
}
stage('read file contents') {
println readFile(file: fileName)
}
}
You could also use this file as a properties file and update a property that exists and append ones that don't . A quick sample code to do that looks like below.
node {
def fileName = "/tmp/hello.txt"
stage('Preparation') {
sh 'pwd & rm -rf *'
}
stage('write to file') {
writeFile(file: fileName, text: "myvar:hello", encoding: "UTF-8")
}
stage('read file contents') {
println readFile(file: fileName)
}
// Add property
stage('Add property') {
if (fileExists(fileName)) {
existingContents = readFile(fileName)
}
newProperty = "newvar:newValue"
writeFile(file: fileName, text: existingContents + "\n" + newProperty)
println readFile(file: fileName)
}
}
You could easily delete a line that has a property if you would like to get rid of it

Read data in jenkinsfile from xml file created in current workspace

Some time ago I tried to connect jenkins and gerrit and send cppcheck output from jenkins to gerrit as comment:
I installed proper patches for jenkins and gerrit(that is ok it's work)
In jekinsfile I'm tried to run cppckeck and save it's output to xml file(it's works)
Problem is here that when I'm trying to read xml file, and I have information that there is no such file. I see that script have different root catalog(i groovy I printed dir). I think code with my experimental jenkinsfile explain problem:
pipeline {
agent any
stages {
stage('Example') {
steps {
gerritReview labels: [Verified: 0]
sh 'pwd'
sh 'cppcheck --enable=all --inconclusive --xml --xml-version=2 *.c* 2> cppcheck.xml'
script {
def parser = new XmlParser()
def doc = parser.parse("cppcheck.xml"); // No xml file here because script {}
// is run in different place
}
}
}
post {
always {
gerritReview score: 1
step([$class: 'CppcheckPublisher', pattern: 'cppcheck.xml', ignoreBlankFiles: false, treshold: "0"])
}
} }
How to load this file. Or I'm doing it's all wrong?(I mean integration gerrit with jenkins who purpose is to run cppcheck and cpplint and show results in gerrit).
If the file is in your repo, you need to check out the repo first
https://www.jenkins.io/doc/pipeline/steps/workflow-scm-step/
pipeline {
agent any
stages {
stage('Example') {
steps {
checkout scm // ADD THIS LINE
gerritReview labels: [Verified: 0]
sh 'pwd'
sh 'cppcheck --enable=all --inconclusive --xml --xml-version=2 *.c* 2> cppcheck.xml'
script {
def parser = new XmlParser()
def doc = parser.parse("cppcheck.xml");
}
}
}
post {
always {
gerritReview score: 1
step([$class: 'CppcheckPublisher', pattern: 'cppcheck.xml', ignoreBlankFiles: false, treshold: "0"])
}
}
}

How to list all directories from within directory in jenkins pipeline script

I want to get all directories present in particular directory from jenkins pipeline script.
How can we do this?
If you want a list of all directories under a specific directory e.g. mydir using Jenkins Utility plugin you can do this:
Assuming mydir is under the current directory:
dir('mydir') {
def files = findFiles()
files.each{ f ->
if(f.directory) {
echo "This is directory: ${f.name} "
}
}
}
Just make sure you do NOT provide glob option. Providing that makes findFiles to return file names only.
More info: https://jenkins.io/doc/pipeline/steps/pipeline-utility-steps/
I didn't find any plugin to list folders, so I used sh/bat script in pipeline, and also this will work irrespective of operating system.
pipeline {
stages {
stage('Find all fodlers from given folder') {
steps {
script {
def foldersList = []
def osName = isUnix() ? "UNIX" : "WINDOWS"
echo "osName: " + osName
echo ".... JENKINS_HOME: ${JENKINS_HOME}"
if(isUnix()) {
def output = sh returnStdout: true, script: "ls -l ${JENKINS_HOME} | grep ^d | awk '{print \$9}'"
foldersList = output.tokenize('\n').collect() { it }
} else {
def output = bat returnStdout: true, script: "dir \"${JENKINS_HOME}\" /b /A:D"
foldersList = output.tokenize('\n').collect() { it }
foldersList = foldersList.drop(2)
}
echo ".... " + foldersList
}
}
}
}
}
I haven't tried this, but I would look at the findFiles step provided by the Jenkins Pipeline Utility Steps Plugin and set glob to an ant-style directory patter, something like '**/*/'
If you just want to log them, use
sh("ls -A1 ${myDir}")
for Linux/Unix. (Note: that's a capital letter A and the number one.)
Or, use
bat("dir /B ${myDir}")
for Windows.
If you want the list of files in a variable, you'll have to use
def dirOutput = sh("ls -A1 ${myDir}", returnStdout: true)
or
def dirOutput = bat("dir /B ${myDir}", returnStdout: true)
and then parse the output.
Recursively getting all the Directores within a directory.
pipeline {
agent any
stages {
stage('Example') {
steps {
script {
def directories = getDirectories("$WORKSPACE")
echo "$directories"
}
}
}
}
}
#NonCPS
def getDirectories(path) {
def dir = new File(path)
def dirs = []
dir.traverse(type: groovy.io.FileType.DIRECTORIES, maxDepth: -1) { d ->
dirs.add(d)
}
return dirs
}
A suggestion for the very end of Jenkinsfile:
post {
always {
echo '\n\n-----\nThis build process has ended.\n\nWorkspace Files:\n'
sh 'find ${WORKSPACE} -type d -print'
}
}
Place the find wherever you think is better. Check more alternatives at here

Jenkins Declarative Pipeline: How to inject properties

I have Jenkins 2.19.4 with Pipeline: Declarative Agent API 1.0.1. How does one use readProperties if you cannot define a variable to assign properties read to?
For example, to capture SVN revision number, I currently capture it with following in Script style:
```
echo "SVN_REVISION=\$(svn info ${svnUrl}/projects | \
grep Revision | \
sed 's/Revision: //g')" > svnrev.txt
```
def svnProp = readProperties file: 'svnrev.txt'
Then I can access using:
${svnProp['SVN_REVISION']}
Since it is not legal to def svnProp in Declarative style, how is readProperties used?
You can use the script step inside the steps tag to run arbitrary pipeline code.
So something in the lines of:
pipeline {
agent any
stages {
stage('A') {
steps {
writeFile file: 'props.txt', text: 'foo=bar'
script {
def props = readProperties file:'props.txt';
env['foo'] = props['foo'];
}
}
}
stage('B') {
steps {
echo env.foo
}
}
}
}
Here I'm using env to propagate the values between stages, but it might be possible to do other solutions.
The Jon S answer requires granting script approval because it is setting environment variables. This is not needed when running in same stage.
pipeline {
agent any
stages {
stage('A') {
steps {
writeFile file: 'props.txt', text: 'foo=bar'
script {
def props = readProperties file:'props.txt';
}
sh "echo $props['foo']"
}
}
}
}
To define general vars available to all stages, define values for example in props.txt as:
version=1.0
fix=alfa
and mix script and declarative Jenkins pipeline as:
def props
def VERSION
def FIX
def RELEASE
node {
props = readProperties file:'props.txt'
VERSION = props['version']
FIX = props['fix']
RELEASE = VERSION + "_" + FIX
}
pipeline {
stages {
stage('Build') {
echo ${RELEASE}
}
}
}

How do you load a groovy file and execute it

I have a jenkinsfile dropped into the root of my project and would like to pull in a groovy file for my pipeline and execute it. The only way that I've been able to get this to work is to create a separate project and use the fileLoader.fromGit command. I would like to do
def pipeline = load 'groovy-file-name.groovy'
pipeline.pipeline()
If your Jenkinsfile and groovy file in one repository and Jenkinsfile is loaded from SCM you have to do:
Example.Groovy
def exampleMethod() {
//do something
}
def otherExampleMethod() {
//do something else
}
return this
JenkinsFile
node {
def rootDir = pwd()
def exampleModule = load "${rootDir}#script/Example.Groovy "
exampleModule.exampleMethod()
exampleModule.otherExampleMethod()
}
If you have pipeline which loads more than one groovy file and those groovy files also share things among themselves:
JenkinsFile.groovy
def modules = [:]
pipeline {
agent any
stages {
stage('test') {
steps {
script{
modules.first = load "first.groovy"
modules.second = load "second.groovy"
modules.second.init(modules.first)
modules.first.test1()
modules.second.test2()
}
}
}
}
}
first.groovy
def test1(){
//add code for this method
}
def test2(){
//add code for this method
}
return this
second.groovy
import groovy.transform.Field
#Field private First = null
def init(first) {
First = first
}
def test1(){
//add code for this method
}
def test2(){
First.test2()
}
return this
You have to do checkout scm (or some other way of checkouting code from SCM) before doing load.
Thanks #anton and #Krzysztof Krasori, It worked fine if I combined checkout scm and exact source file
Example.Groovy
def exampleMethod() {
println("exampleMethod")
}
def otherExampleMethod() {
println("otherExampleMethod")
}
return this
JenkinsFile
node {
// Git checkout before load source the file
checkout scm
// To know files are checked out or not
sh '''
ls -lhrt
'''
def rootDir = pwd()
println("Current Directory: " + rootDir)
// point to exact source file
def example = load "${rootDir}/Example.Groovy"
example.exampleMethod()
example.otherExampleMethod()
}
Very useful thread, had the same problem, solved following you.
My problem was: Jenkinsfile -> call a first.groovy -> call second.groovy
Here my solution:
Jenkinsfile
node {
checkout scm
//other commands if you have
def runner = load pwd() + '/first.groovy'
runner.whateverMethod(arg1,arg2)
}
first.groovy
def first.groovy(arg1,arg2){
//whatever others commands
def caller = load pwd() + '/second.groovy'
caller.otherMethod(arg1,arg2)
}
NB: args are optional, add them if you have or leave blank.
Hope this could helps further.
In case the methods called on your loaded groovy script come with their own node blocks, you should not call those methods from within the node block loading the script. Otherwise you'd be blocking the outer node for no reason.
So, building on #Shishkin's answer, that could look like
Example.Groovy
def exampleMethod() {
node {
//do something
}
}
def otherExampleMethod() {
node {
//do something else
}
}
return this
Jenkinsfile
def exampleModule
node {
checkout scm // could not get it running w/o checkout scm
exampleModule = load "script/Example.Groovy"
}
exampleModule.exampleMethod()
exampleModule.otherExampleMethod()
Jenkinsfile using readTrusted
When running a recent Jenkins, you will be able to use readTrusted to read a file from the scm containing the Jenkinsfile without running a checkout - or a node block:
def exampleModule = evaluate readTrusted("script/Example.Groovy")
exampleModule.exampleMethod()
exampleModule.otherExampleMethod()

Resources