How does scripted Jenkins Pipeline with Groovy work - groovy

stage('deploy') {
steps {
script {
import java.net.URL;
import java.net.URLConnection;
def serviceURL = ""
if (env.BRANCH_NAME == "master") {
serviceURL="http://myserver:8100/jira/rest/plugins/1.0"
}
if (env.BRANCH_NAME == "develop") {
serviceURL = "http://myserver:8100/jira/rest/plugins/1.0"
}
if(env.BRANCH_NAME.startsWith("release")
{
serviceURL="http://myserver:8100/jira/rest/plugins/1.0"
}
// Request to get token
URL myURL = new URL(serviceURL+"?"+"os_authType=basic");
HttpURLConnection myURLConnection = (HttpURLConnection)myURL.openConnection();
}
This is an extract of my jenkinsfile. It is written in Groovy .
Right now I get this error:
WorkflowScript: 66: expecting ')', found 'URL' # line 66, column 17.
It is complaining about this line:
URL myURL = new URL(serviceURL+"?"+"os_authType=basic");
I do not know why. But one thing I was wondering now.
How does it actually work with imports. I mean normally you have to do
import java.net.URL
How would it actually work with extern libraries which are not part of Java SDK.
Normally you would put them on the classpath. How would that work with jenkinsfile scripted pipeline. So I wonder when you can actually use jenkinsfile with groovy or when to better
create an own project and create job for it and then add it in the jenkinsfile.

You don't have to import java.net.*, groovy imports them by default. https://groovy-lang.org/structure.html#_default_imports.
Your problem is a result of a missing ) in the line:
if(env.BRANCH_NAME.startsWith("release")
it should be
if(env.BRANCH_NAME.startsWith("release"))
The whole script should look like so in idiomatic Groovy:
stage('deploy') {
steps {
script {
String serviceURL
switch(env.BRANCH_NAME)
case 'master':
case 'develop':
serviceURL = "http://myserver:8100/jira/rest/plugins/1.0"
break
case ~/^release.*$/:
serviceURL = "http://myserver:8100/jira/rest/plugins/1.0"
break
default:
throw new Exception( 'Unknown' )
}
// Request to get token
"${serviceURL}?os_authType=basic".toURL().openConnection().with{
if( 200 != responseCode ) return
outputStream.withWriter{ it << jsonInputString }
}
}
}
}
Here the withWriter{} takes care about stream flushing and closing.

Related

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

geb as an additional module using android studio cant find GebConfig.groovy

I get the error Caught: geb.error.NoBaseUrlDefinedException: There is no base URL configured and it was requested.
My main module, i assume is default because its got a green dot at the bottom right, is called app and runs some appium tests.
This module called website(little blue line thing) has a java package called geb where both GebConfig.groovy and my groovy script are located. It's very simple:
package geb;
import geb.Browser
Browser.drive {
go("/some/site")
}
and my config:
package geb
import org.openqa.selenium.chrome.ChromeDriver
import org.openqa.selenium.ie.InternetExplorerDriver
path = 'c:\\drivers\\'
waiting {
timeout = 2
retryInterval = 0.5
preset{
slow{
timeout = 20
retryInterval = 1
}
verySlow{
timeout = 50
}
}
}
environments {
chrome {
drive='chromedriver.exe'
system='webdriver.chrome.driver'
fpath= path+drive
System.setProperty(system,fpath)
driver = { new ChromeDriver() }
}
ie {
drive='IEDriverServer.exe'
system='webdriver.ie.driver'
fpath= path+drive
System.setProperty(system,fpath)
driver = { new InternetExplorerDriver() }
}
}
driver = {new InternetExplorerDriver()}
baseUrl = "http://www.google.com"
reportDir = 'c:\\reports\\'
I have tried manually setting the buildurl to no avail, I've gone through the manual but i couldnt get the classpath set, or atleast when i tried that gave me a whole new set of issues.
What am i doing wrong?

SOAPUI Assertion script writing twice to file

I am writing a groovy script where I am extracting text from a response and writing it to an output file on my system. The problem I encounter is when I run the groovy script that calls the test. The script assertions runs and logs the text twice to the file.
It seems to write to the file just before it leaves the assertion.
I have tried the following:
...
...
if (context.alreadyWritten == null || !context.alreadyWritten) {
inputFile.append (testString+ "\n")
log.info testString
} else {
log.info ('Already written!')
}
I have set the flag (context.alreadyWritten) to false in groovy before I execute the test step.
SOAPUI version : 5.3.0
I see there was an issue previous with Smartbear when appending to file in an assertion script. However the workaround was advised to resolve this:
if (context.alreadyWritten == null || !context.alreadyWritten) {
}
Which does not resolve my issue
When I log the result using log.info I see only one instance of the message been logged.
Any ideas.
Thanks
If you are using Script Assertion, try below:
//Define the file name, change as needed
def fileName = '/path/to/file.xml'
//check if you got the response
if (context.response) {
log.info 'Response available and not empty'
def file = new File(fileName)
if (!context?.alreadySaved) {
file.write(context.response)
context.alreadySaved = true
log.info 'response written to file'
} else {
log.info 'Response already written'
}
} else {
log.info 'there is no response to save'
}

Unable to recognize WORKSPACE as directory using Jenkinsfile/pipline plugin

I am trying to search a file recursively inside a directory hence cannot use findFiles.
I have seen the directories via manually login in to the slave but it cannot be recognized in the code below. When I use isDirectory() it says false hence later while using dir.listFiles() it return null.
Below is the code:
def recursiveFileSearch(File dir, filename, filesPath) {
File[] files = dir.listFiles() // It returns null here as it cannot recognize it as directory
echo "$files"
for (int i=0; i < files.size(); i++) {
if (files[i].isDirectory()) {
recursiveFileSearch(files[i], filename, filesPath)
} else {
if (files[i].getAbsolutePath().contains(filename)) {
filesPath.add(files[i].getAbsolutePath())
return filesPath
}
}
}
return filesPath
}
node('maven') {
git 'https://github.com/rupalibehera/t3d.git'
sh 'mvn clean install'
File currentDir = new File(pwd())
def isdir = currentDir.isDirectory()
println "isdir:${isdir}" // The output here is False
def isexist = currentDir.exists()
println "isexist:${isexist}" // The output here is False
def canread = currentDir.canRead()
println "canread:${canread}" // The output here is False
def filesPath = []
def openshiftYaml = recursiveFileSearch(currentDir, "openshift.yml", filesPath)
}
I am not sure what is going wrong here.
But below are some observations:
When I do File currentDir = new File("."), it returns / and starts reading complete root directory which I don't want and in that also it does not recognize WORKSPACE as directory
It executes well if I run it on Master node, but in my use case it will be always a slave.
I have also checked the permissions of directory the user has read/write/execute permissions.
Any pointers/help is appreciated
Generally, run a sh step to do whatever work you need. You may not use java.io.File or the like from Pipeline script. It does not run on the agent, and is also insecure, which is why any such attempt will be rejected when the sandbox mode is left on (the default).
you are running into the Using File in Pipeline Description problem. I know it all too well. File objects and NIO work fine for breaking up paths, but their isDirectory, exists and other methods run on master as a part of the Jenkinsfile and not on the node. So, all use on master looks great, because the files are in the workspace. All use on a node, fails.
In short, don't do that. Use fileExists(), pwd(), findFiles etc
If you created a shareLibrary and want to use unit tests on the code outside of Jenkins, then you can create a fascade which relies on the script object ('this' from a pipeline)
Class for shared lib
class PipelineUtils implements Serializable {
static def pipelineScript = null;
/**
* Setup this fascade with access to pipeline script methods
* #param jenkinsPipelineScript
* #return
*/
static initialize(def jenkinsPipelineScript) {
pipelineScript = jenkinsPipelineScript
}
/**
* Use pipelineScript object ('this' from pipeline) to access fileExists
* We cannot use Java File objects for detection as the pipeline script runs on master and uses delegation/serialization to
* get to the node. So, File.exists() will be false if the file was generated on the node and that node isn't master.
* https://support.cloudbees.com/hc/en-us/articles/230922128-Pipeline-Using-java-io-File-in-a-Pipeline-description
* #param target
* #return true if path exists
*/
static boolean exists(Path target) {
if (!pipelineScript) {
throw new Exception("PipelineUtils.initialize with pipeline script not called - access to pipeline 'this' required for access to file detection routines")
}
if (! target.parent) {
throw new Exception('Please use absolutePaths with ${env.WORKSPACE}/path-to-file')
}
return pipelineScript.fileExists(target.toAbsolutePath().toString())
}
/**
* Convert workspace relative path to absolute path
* #param path relative path
* #return node specific absolute path
*/
static def relativeWorkspaceToAbsolutePath(String path) {
Path pwd = Paths.get(pipelineScript.pwd())
return pwd.resolve(path).toAbsolutePath().toString()
}
static void echo(def message) {
pipelineScript.echo(message)
}
}
class for tests
class JenkinsStep {
static boolean fileExists(def path) {
return new File(path).exists()
}
static def pwd() {
return System.getProperty("user.dir")
}
static def echo(def message) {
println "${message}"
}
}
usage in jenkins
PipelineUtils.initialize(this)
println PipelineUtils.exists(".")
// calls jenkins fileExists()
usage in unit tests
PipelineUtils.initialize(new JenkinsStep())
println PipelineUtils.exists(".")
// calls File.exists
I found the answer,
for searching any file in your workspace from Jenkinsfile you can use findFiles step,
I did try this but I was passing the incorrect glob for the same. Now I just do
def files = findFiles(glob: '**/openshift.yml') \\ it returns the path of file

Running SoapUI test cases using testRunner

I am working on a SoapUI project where I need to run my test suite using test runner. I am using external groovy scripting for environment variable. The problem I am facing here is whenever I am running test case from test runner its return Workspace as null, which is used in External groovy. So in external groovy I am getting workspace as null causing error [getProjectByname() cannot be invoked on null]. Below is the
constructor of global script where workspace is used
AvengerAPITestManager(String TestProject, String TestSuite, String TestCase,String TestStep)
{
TestName = "AvengerAPITests";
testProject = SoapUI.getWorkspace().getProjectByName(TestProject);
tSuite = testProject.getTestSuiteByName(TestSuite);
tCase = testProject.getTestSuiteByName(TestSuite).getTestCaseByName(TestCase);
tStepName = TestStep.toString();
tStep=testProject.getTestSuiteByName(TestSuite).getTestCaseByName(TestCase).getTestStepByName (TestStep);
}
Above we have user SoapUI.getWorkspace() which is working fine when trying to run from soapUI but whever I m trying to run from testrunner SoapUI.getWorkspace comes out to be null. I even tried passing workspace like I am passing testproject name still it didnt worked.
I tried something like this also
AvengerAPITestManager(Object workspace,String TestProject, String TestSuite, String TestCase, String TestStep)
{
TestName = "AvengerAPITests";
testProject = workspace.getProjectByName(TestProject);
tSuite = testProject.getTestSuiteByName(TestSuite);
tCase = testProject.getTestSuiteByName(TestSuite).getTestCaseByName(TestCase);
tStepName = TestStep.toString();
tStep = testProject.getTestSuiteByName(TestSuite).getTestCaseByName(TestCase).getTestStepByName(TestStep);
}
In the above code I tries passing Workspace object from the test case as I passed Testcase name and all but still I m getting null for workspace. Please tell me how do I deal with the problem.
Here is usefull working example https://github.com/stokito/soapui-junit
You should place your sample-soapui-project.xml to /src/test/resources folder that will expose it to classpath
If you want to use soap ui in external code, try to directly create new test runner with specific project file:
SoapUITestCaseRunner runner = new SoapUITestCaseRunner();
runner.setProjectFile( "src/dist/sample-soapui-project.xml" );
runner.run();
Or if you want to define test execution more precisely, you can use something like this:
WsdlProject project = new WsdlProject( "src/dist/sample-soapui-project.xml" );
TestSuite testSuite = project.getTestSuiteByName( "Test Suite" );
TestCase testCase = testSuite.getTestCaseByName( "Test Conversions" );
// create empty properties and run synchronously
TestRunner runner = testCase.run( new PropertiesMap(), false );
PS: don't forget to import soap ui classes, that you use in your code and put them to classpath.
PPS: If you need just run test cases outside the soap ui and/or automate this process, why not just use testrunner.sh/.bat for the same thing? (here is description of this way: http://www.soapui.org/Test-Automation/functional-tests.html)
I am not sure if this is going to help anyone out there but here is what I did to fix the problem I was having with workspace as null causing error[getProjectByname() cannot be invoked on null] When i run from cmd
try this:
import com.eviware.soapui.model.project.ProjectFactoryRegistry
import com.eviware.soapui.impl.wsdl.WsdlProjectFactory
import com.eviware.soapui.impl.wsdl.WsdlProject
//get the Util project
def project = null
def workspace = testRunner.testCase.testSuite.project.getWorkspace();
//if running Soapui
if (workspace != null) {
project = workspace.getProjectByName("Your Project")
}
//if running in Jenkins/Hudson
else{
project = new WsdlProject("C:\\...\\....\\....\\-soapui-project.xml");
}
if (project.open && project.name == "Your Project") {
def properties = new com.eviware.soapui.support.types.StringToObjectMap()
def testCase = project.getTestSuiteByName("TestSuite 1").getTestCaseByName("TestCase");
if(testCase == null)
{
throw new RuntimeException("Could not locate testcase 'TestCase'! ");
} else {
// This will run everything in the selected project
runner = testCase.run(new com.eviware.soapui.support.types.StringToObjectMap(), false)
}
}
else {
throw new RuntimeException("Could not find project ' Order Id....' !")
}
The above code will run everything in the selected project.

Resources