i have a groovy method that now creates XML files. I have verified it using the groovyConsole. But if i use this snippet in my jenkinsfile, the XML file is not seen to be created in the workspace, although the job completes successfully.
Question: how do i make sure that the XML file is generated in the workspace? I will be using this XML for subsequent stages in the jenkinsfile
Here is how the jenkinsfile looks like:
import groovy.xml.*
node('master') {
deleteDir()
stage('Checkout') {
// checks out the code
}
generateXML("deploy.xml") //This calls the method to generate the XML file
//stage for packaging
//Stage to Publish
//Stage to Deploy
}
#NonCPS
def generateXML(file1) {
println "Generating the manifest XML........"
def workflows = [
[ name: 'A', file: 'fileA', objectName: 'wf_A', objectType: 'workflow', sourceRepository: 'DEV2', folderNames: [ multifolder: '{{multifolderTST}}', multifolder2: '{{multifolderTST2}}' ]],
[ name: 'B', file: 'fileB', objectName: 'wf_B', objectType: 'workflow', sourceRepository: 'DEV2', folderNames: [ multifolder3: '{{multifolderTST3}}', multifolder4: '{{multifolderTST4}}']]
]
def builder = new StreamingMarkupBuilder()
builder.encoding = 'UTF-8'
new File(file1).newWriter() << builder.bind {
mkp.xmlDeclaration()
mkp.declareNamespace(udm :'http://www.w3.org/2001/XMLSchema')
mkp.declareNamespace(powercenter:'http://www.w3.org/2001/XMLSchema')
delegate.udm.DeploymentPackage(version:'$BUILD_NUMBER', application: "informaticaApp"){
delegate.deployables {
workflows.each { item ->
delegate.powercenter.PowercenterXml(name:item.name, file:item.file) {
delegate.scanPlaceholders(true)
delegate.sourceRepository(item.sourceRepository)
delegate.folderNameMap {
item.folderNames.each { name, value ->
it.entry(key:name, value)
}
}
delegate.objectNames {
delegate.value(item.objectName)
}
delegate.objectTypes {
delegate.value(item.objectType)
}
}
}
}
delegate.dependencyResolution('LATEST')
delegate.undeployDependencies(false)
}
}
}
I found the file in the / dir.. As i haven't entered any path in the filewriter.
UPDATE:
this is not the right solution for a distributed env. It appears that the java file io operations only works in master and not in the agent machines.
Related
Among the possible steps one can use in a Jenkins pipeline, there is one with the name step, subtitled General Build Step. https://www.jenkins.io/doc/pipeline/steps/workflow-basic-steps/#step-general-build-step . I need to iterate on calling this step based on the contents of a file. I have created a groovy script to read the file and perform the iteration, but I am not sure how to create the equivalent of my step() in the groovy script. Here is the general format of the step I am trying to perform:
stage ('title') {
steps {
step([
$class: 'UCDeployPublisher',
siteName: 'literal string',
deploy: [
$class: 'com.urbancode.jenkins.plugins.ucdeploy.DeployHelper$DeployBlock',
param1: 'another literal string',
param2: 'yet another string'
]
])
}
}
The script step I have developed looks like this:
steps {
script {
def content = readFile(file:'data.csv', encoding:'UTF-8');
def lines = content.split('\n');
for (line in lines) {
// want to insert equivalent groovy code for the basic build step here
}
}
}
I'm expecting there is probably a trivial answer here. I'm just out of my element in the groovy/java world and I am not sure how to proceed. I have done extensive research, looked at source code for Jenkins, looked at plugins, etc. I am stuck!
Check the following, simply move your UCDeployPublisher to a new function and call that from your loop.
steps {
script {
def content = readFile(file:'data.csv', encoding:'UTF-8');
def lines = content.split('\n');
for (line in lines) {
runUCD(line)
}
}
}
// Groovy function
def runUCD(def n) {
stage ("title $n") {
steps {
step([
$class: 'UCDeployPublisher',
siteName: 'literal string',
deploy: [
$class: 'com.urbancode.jenkins.plugins.ucdeploy.DeployHelper$DeployBlock',
param1: 'another literal string',
param2: 'yet another string'
]
])
}
}
}
This is showing the code related to my comment on the accepted answer
pipeline {
stages {
stage ('loop') {
steps {
script {
... groovy to read/parse file and call runUCD
}
}
}
}
}
def runUCD(def param1, def param2) {
stage ("title $param1") {
step([
....
])
}
}
I'm trying to convert my jenkins pipeline to a shared library since it can be reusable on most of the application. As part of that i have created groovy file in vars folder and kept pipeline in jenkins file in github and able to call that in jenkins successfully
As part of improving this i want to pass params, variables, node labels through a file so that we should not touch jenkins pipeline and if we want to modify any vars, params, we have to do that in git repo itself
pipeline {
agent
{
node
{
label 'jks_deployment'
}
}
environment{
ENV_CONFIG_ID = 'jenkins-prod'
ENV_CONFIG_FILE = 'test.groovy'
ENV_PLAYBOOK_NAME = 'test.tar.gz'
}
parameters {
string (
defaultValue: 'test.x86_64',
description: 'Enter app version',
name: 'app_version'
)
choice (
choices: ['10.0.0.1','10.0.0.2','10.0.0.3'],
description: 'Select a host to be delpoyed',
name: 'host'
)
}
stages {
stage("reading properties from properties file") {
steps {
// Use a script block to do custom scripting
script {
def props = readProperties file: 'extravars.properties'
env.var1 = props.var1
env.var2 = props.var2
}
echo "The variable 1 value is $var1"
echo "The variable 2 value is $var2"
}
In above code,i used pipeline utility steps plugin and able to read variables from extravars.properties file. Is it same way we can do for jenkins parameters also? Or do we have any suitable method to take care of passing this parameters via a file from git repo?
Also is it possible to pass variable for node label also?
=====================================================================
Below are the improvements which i have made in this project
Used node label plugin to pass the node name as variable
Below is my vars/sayHello.groovy file content
def call(body) {
// evaluate the body block, and collect configuration into the object
def pipelineParams= [:]
body.resolveStrategy = Closure.DELEGATE_FIRST
body.delegate = pipelineParams
body()
pipeline {
agent
{
node
{
label "${pipelineParams.slaveName}"
}
}
stages {
stage("reading properties from properties file") {
steps {
// Use a script block to do custom scripting
script {
// def props = readProperties file: 'extravars.properties'
// script {
readProperties(file: 'extravars.properties').each {key, value -> env[key] = value }
//}
// env.var1 = props.var1
// env.var2 = props.var2
}
echo "The variable 1 value is $var1"
echo "The variable 2 value is $var2"
}
}
stage ('stage2') {
steps {
sh "echo ${var1}"
sh "echo ${var2}"
sh "echo ${pipelineParams.appVersion}"
sh "echo ${pipelineParams.hostIp}"
}
}
}
}
}
Below is my vars/params.groovy file
properties( [
parameters([
choice(choices: ['10.80.66.171','10.80.67.6','10.80.67.200'], description: 'Select a host to be delpoyed', name: 'host')
,string(defaultValue: 'fxxxxx.x86_64', description: 'Enter app version', name: 'app_version')
])
] )
Below is my jenkinsfile
def _hostIp = params.host
def _appVersion = params.app_version
sayHello {
slaveName = 'master'
hostIp = _hostIp
appVersion = _appVersion
}
Now Is it till we can improve this?Any suggestions let me know.
Actually my Jenkinsfile looks like this:
#Library('my-libs') _
myPipeline{
my_build_stage(project: 'projectvalue', tag: '1.0' )
my_deploy_stage()
}
I am trying to pass these two variables (project and tag) to my build_stage.groovy, but it is not working.
What is the correct syntax to be able to use $params.project or $params.tag in my_build_stage.groovy?
Please see the below code which will pass parameters.
In your Jenkinsfile write below code:
// Global variable is used to get data from groovy file(shared library file)
def mylibrary
def PROJECT_VALUE= "projectvalue"
def TAG = 1
pipeline{
agent{}
stages{
stage('Build') {
steps {
script {
// Load Shared library Groovy file mylibs.Give your path of mylibs file which will contain all your function definitions
mylibrary= load 'C:\\Jenkins\\mylibs'
// Call function my_build stage and pass parameters
mylibrary.my_build_stage(PROJECT_VALUE, TAG )
}
}
}
stage('Deploy') {
steps {
script {
// Call function my_deploy_stage
mylibrary.my_deploy_stage()
}
}
}
}
}
Create a file named : mylibs(groovy file)
#!groovy
// Write or add Functions(definations of stages) which will be called from your jenkins file
def my_build_stage(PROJECT_VALUE,TAG_VALUE)
{
echo "${PROJECT_VALUE} : ${TAG_VALUE}"
}
def my_deploy_stage()
{
echo "In deploy stage"
}
return this
I am trying to a separate file holding variable for a Jenkins pipeline, this is because it will be used by multiple pipelines. But I can't seem to find the proper way to include it? Or if there's any way to include it?
MapA:
def MapA = [
ItemA: [
Environment: 'envA',
Name: 'ItemA',
Version: '1.0.0.2',
],
ItemB: [
Environment: 'envB',
Name: 'ItemB',
Version: '2.0.0.1',
]
]
return this;
MainScript:
def NodeLabel = 'windows'
def CustomWorkSpace = "C:/Workspace"
// Tried loading it here (Location 1)
load 'MapA'
pipeline {
agent {
node {
// Restrict Project Execution
label NodeLabel
// Use Custom Workspace
customWorkspace CustomWorkSpace
// Tried loading it here (Location 2)
load 'MapA'
}
}
stages {
// Solution
stage('Solution') {
steps {
script {
// Using it here
MapA.each { Solution ->
stage("Stage A") {
...
}
stage("Stage B") {
...
}
// Extract Commit Solution
stage("Stage C") {
...
echo "${Solution.value.Environment}"
echo "${Solution.value.Name}"
echo "${Solution.value.Version}"
}
}
}
}
}
}
}
On Location 1 outside the pipeline and node section: it gave the below error
org.jenkinsci.plugins.workflow.steps.MissingContextVariableException: Required context class hudson.FilePath is missing
Perhaps you forgot to surround the code with a step that provides this, such as: node
On Location 2 inside the node section: it gave the below error
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 7: Expected to find ‘someKey "someValue"’ # line 7, column 14.
load 'MapA'
node {
^
You can achieve your scenario in 2 ways:
#1
If you want you can hardcode the variable in the same Jenkins file and make use of it on your pipeline like below Example :
Jenkinsfile content
def MapA = [
ItemA: [
Environment: 'envA',
Name: 'ItemA',
Version: '1.0.0.2',
],
ItemB: [
Environment: 'envB',
Name: 'ItemB',
Version: '2.0.0.1',
]
]
pipeline {
agent any;
stages {
stage('debug') {
steps {
script {
MapA.each { k, v ->
stage(k) {
v.each { k1,v1 ->
// do your actual task by accessing the map value like below
echo "${k} , ${k1} value is : ${v1}"
}
}
}
}
}
}
}
}
#2
If you would like to keep the variable in a separate groovy file in a gitrepo, it will be like below
Git Repo file and folder structure
.
├── Jenkinsfile
├── README.md
└── var.groovy
var.groovy
def mapA() {
return [
ItemA: [
Environment: 'envA',
Name: 'ItemA',
Version: '1.0.0.2',
],
ItemB: [
Environment: 'envB',
Name: 'ItemB',
Version: '2.0.0.1',
]
]
}
def helloWorld(){
println "Hello World!"
}
return this;
Jenkinsfile
pipeline {
agent any
stages {
stage("iterate") {
steps {
sh """
ls -al
"""
script {
def x = load "${env.WORKSPACE}/var.groovy"
x.helloWorld()
x.mapA().each { k, v ->
stage(k) {
v.each { k1,v1 ->
echo "for ${k} value of ${k1} is ${v1}"
}
} //stage
} //each
} //script
} //steps
} // stage
}
}
How can a file from the current workspace be passed as a parameter to a build job, e.g.:
build job: 'other-project', parameters: [[$class: 'FileParameterValue', ????]]
You can pass the full path of file, you could do:
node('master') {
//Read the workspace path
String path = pwd();
String pathFile = "${path}/exampleDir/fileExample.ext";
//Do whatever you wish with the file path
}
What a nightmare - there is no documentation, looked into jenkins code, etc.. Tried everything
Eventually found out that this doesn't currently work. Here is the jenkins bug.
https://issues.jenkins-ci.org/browse/JENKINS-27413
Linked to from here: http://jenkins-ci.361315.n4.nabble.com/pipeline-build-job-with-FileParameterValue-td4861199.html
You need to pass in a FileParameterValue
http://javadoc.jenkins.io/hudson/model/FileParameterValue.html
This approach assumes you have the file in the current job's workspace.
pipeline
{
agent any
stages {
stage('Pass file type param to build job') {
steps {
script {
def propertiesFilePath = "${env.WORKSPACE}/sample.properties"
build job: 'other-project',
parameters: [[$class: "FileParameterValue", name: "propertiesFile", file: new FileParameterValue.FileItemImpl(new File(propertiesFilePath))]]
}
}
}
}
}
Here the name of the downstream/child job is 'other-project' and the name of the file type parameter in this downstream/child job is 'propertiesFile'.
The type FileParameterValue.FileItemImpl is defined in the class FileParameterValue and is internally used in jenkins to handle FileItem, also adding serialization support to the same.
Now you can use the latest File Parameters plugin to implement it.
Here's a simple example:
test-parent pipeline
pipeline {
agent any
parameters {
base64File(name: 'testFileParent', description: 'Upload file test')
}
stages {
stage('Invoke Child Job') {
steps {
withFileParameter('testFileParent') {
script{
def fileContent = readFile(env.testFileParent)
build(job: 'test-child',
parameters: [base64File(name: 'testFileChild', base64: Base64.encoder.encodeToString(fileContent.bytes))])
}
}
}
}
}
}
test-child pipeline
pipeline {
agent any
parameters {
base64File(name: 'testFileChild', description: 'Upload file test')
}
stages {
stage('Show File') {
steps {
withFileParameter('testFileChild') {
sh("cat $testFileChild")
}
}
}
}
}
It works like this:
Build test-parent pipeline with parameters, start with a test file
test-parent pipeline invokes test-child pipeline with the test file which was uploaded at Step 1
test-child pipeline prints the test file content to console