How to access groovy function inside sh in below jenkins pipeline script - groovy

def Greet(name) {
echo "Hello ${name}"
}
pipeline {
agent any
stages {
stage('Test') {
steps {
sh """
Greet('Build Team')
"""
}
}
}
}
I am trying to call 'Greet' function from the stage 'Test' inside the shell . But getting error as
/var/lib/jenkins/workspace/Check1#tmp/durable-ce807c1d/script.sh: line 2: syntax error near unexpected token `'Bob''
Any one let me know how we can call 'Greet' function from the stage 'Test' inside the shell .

Related

Never ending shell command with execSync()

I build VS Code extension
I have wrapper in a class like this
public exec(cmd: string): string {
try {
return execSync(cmd, { cwd: this.workspaceRoot }).toString();
}
catch (e) {
return '' + e;
}
}
If in the code I run
let tags = this.exec('git tag --sort=-v:refname')
I do get a list of tags. Actually, all other commands run also correctly like git status, git config and other. But as soon as I run this.
let res = this.exec(`git push origin ${name}`);
It hangs forever. If I pass wrong tag it stops with error, but if I put correct tag, it suspends. I try to console.log('git push origin ${name}') and then copy result and run that command in a terminal, it runs correctly.
What can be the reason of a such behavior?

Generating Jenkins Pipeline Stages from pytest

Is it possible/is there a plugin to dynamically create jenkins pipeline stages from pytest?
(run pytest in a pipeline, and then every test that pytest runs will create a new stage in the pipeline, so the blue ocean view of the jenkins job will have created stages for all the tests)
I probably could list all the tests that will run, and then run them manually in parallel, something like this:
stage("Run Tests"){
steps {
script {
def tests = sh(script: "pytest tests/ --collect-only", returnStdout: true).trim().split().toList()
// manipulate tests so that I have a dictionary of filename - test name
run_tests = [:]
tests.each { test -> //test[0] is file name and test[1] is test name
run_tests[test[1]] = {
stage(test[1]) {
sh "pytest ${test[0]} -k ${test[1]}"
}
}
}
parallel run_tests
}
}
}
but it would be easier if there was a native way to do this within pytest or within Jenkins
Thank you!

Reading an environment variable set by a test in Jenkins pipeline

Not found any reference to this particular question.
I am looking to find a way to achieve something like this in a Jenkins pipeline which runs our acceptance tests using Protractor and Cucumber.js:
steps {
container('selenium') {
script {
try {
{
//run tests
}
}
catch (err) {
if (env.testFailed == 'true') {
println "A test failure exists - build status updated to failure"
currentBuild.result = 'FAILURE'
error "Test(s) have failed"
}
else {
println "No test failures exist - build status updated to success"
currentBuild.result = 'SUCCESS'
}
}
}
}
}
This would fail the build if the env var of testFailed is 'true'. The reason for this is we are encountering bugs with Protractor-Cucumber framework where if a failed test retries and passes the exit code of the stage is still 1.
So in the After hook of each test I am setting the env var using node.js to true if the Scenario status is failed:
if (scenario.result.status === Status.FAILED) {
process.env.testFailed = 'true';
}
if (scenario.result.status === Status.PASSED) {
process.env.testFailed = 'false';
}
The problem I have found is that the Jenkins pipeline fails to read the env var value in the code block of the catch section. It is always null.
Any ideas?
1) change the After hook to write the true/false flag to a file in sync.
2) read the file in catch block
catch(err) {
testFailed = sh(script:'cat result.flag.txt', returnStdout: true).trim()
if(testFailed == 'true') {
...
}
}
Another option if there is total/passed/failed case number in output of npm test
lines = []
try {
lines = sh(script:'npm test', returnStdout: true).readLines();
}
catch(err) {
size = lines.size()
// parse the last 20 lines to extract fail/pass/total number
for(int i=size-20;i<size;i++) {
line[i]
}
}
WHY IT DOESN'T WORK NOW?
I see that you're running your tests in a container. When you set an environment variable, it's reflected on the scope of your container not the Jenkins master server
WHAT YOU COULD TRY TO DO
This actually depends on how you run the tests, but this should be an option
// run tests here
// you should have a variable for your container
def exit_code = sh(script: "sudo docker inspect ${container.id} --format='{{.State.ExitCode}}'", returnStdout: true)
sh "exit ${exit_code}"
This actually also depends how you start the tests inside the container,
So if you update your answer with this information I could help you

jenkinsfile loading local variables in groovy script

Not a lot of experience programming but happy to learn.
Question: Sending jenkinsfile build error data to mattermost works just fine locally in the file, but when loaded as a .groovy script it fails "silently". Any guidance on why / how I can post this information to a channel in a loaded groovy script?
Jenkinsfile
#!groovy
properties([[$class: 'jenkins.model.BuildDiscarderProperty', strategy: [$class: 'LogRotator', numToKeepStr: '5', artifactNumToKeepStr: '5']]])
node('node_name'){
def err = null
currentBuild.result = "SUCCESS"
role_name = "deploy"
try {
timeout(60){
stage "${role_name}"
deleteDir()
checkout scm
sh 'introduce error here'
}
}
catch (error){
err = error
currentBuild.result = "FAILURE"
load "ci/curlBuildFailed.groovy"
}
finally {
if (err){
throw err
}
}
}
curlBuildFailed.groovy
sh "curl -i -X POST -d \'payload={" +
"\"text\": \"${env.JOB_NAME}: ${env.BUILD_URL} - build failed with ${err}!\", " +
"\"username\": \"JenkinsBot\", " +
"\"icon_url\": \"$FAIL_BUILD\"}\' $DEVOPS_NOTIFY_URL "
Running the above produces this:
[cure-deploy] Running shell script
+ introduce error here
/home/jenkins/remote/workspace/blablabla/script.sh: line 2: introduce: command not found
[Pipeline] }
[Pipeline] // dir
[Pipeline] }
[Pipeline] // timeout
[Pipeline] load
[Pipeline] { (ci/curlBuildFailed.groovy)
[Pipeline] }
[Pipeline] // load
[Pipeline] }
[Pipeline] // wrap
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // load
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
ERROR: script returned exit code 127
Finished: FAILURE
Notes:
Dropping the contents of curlBuildFailed.groovy into the same
location as load "ci/curlBuildFailed.groovy" creates the desired
output.
Have narrowed down the culprit to ${err} in
curlBuildFailed.groovy, as soon as I remove that variable it posts
to mattermost just fine.
(We have about 30 ansible roles similar to this one so trying to abstract the duplicate code to a easier to maintain structure)
Have searched around for a few hours and it seems similar to these but I hadn't found a solve yet:
jenkins plain catch blocks
don't think I need a 'returns this;' but who knows
Passing Variables in Jenkinsfile Closure
Thank you for your time!
- Sam
You dont need to use the groovy script to send a message to Mattermost. There is a Jenkins Plugin that helps you to send notification messages to Mattermost. You can follow this link: https://github.com/jenkinsci/mattermost-plugin
After the installation and configuration you can use the mattermostSend to send a notification.
then your pipeline will similar to this:
node('node_name') {def err = null
currentBuild.result = "SUCCESS"
role_name = "deploy"
try {
timeout(60){
stage "${role_name}"
deleteDir()
checkout scm
sh 'introduce error here'
}
}
catch (error){
err = error
currentBuild.result = "FAILURE"
mattermostSend color: 'danger', message: 'Message from Jenkins Pipeline', text: \"${env.JOB_NAME}: ${env.BUILD_URL} - build failed with ${err}!\"
}
finally {
if (err){
throw err
}
}
}

Jenkins groovy security problems

I am trying to get all the files matching a filter. Here is my code:
import static groovy.io.FileType.FILES
node {
try{
stage('get files')
new File('.').eachFileRecurse(FILES) {
if(it.name.endsWith('.nuspec')) {
echo it.Name
}
}
}catch(err) {
echo 'Err: Incremental Build failed with Error: ' + err.toString()
}finally {
}
I get the following error:
Err: Incremental Build failed with Error: org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use new java.io.File java.lang.String
I've checked there are No pending script approvals.
I can't find any option to disable sandboxing.
The script runs fine when I try it in the script console.
How do I allow the script to run on my builds?
Thanks!
https://jenkins.io/doc/pipeline/steps/pipeline-utility-steps/#findfiles-find-files-in-the-workspace
def files = findFiles(glob: '**/*.nuspec')
echo "${files[0].name} ${files[0].path} ${files[0].directory} ${files[0].length} ${files[0].lastModified}"

Resources