I just got started on a Jenkins pipeline school assignment. The pipeline structure resides in a library and there is a client module that refers to it, in its Jenkinsfile.
Is it possible to delegate execution to a class in the client module without invoking a script using env (sh or cmd).
I want to invoke a class directly. Does Jenkins maintain classloader isolation b/n library and external module?
Does it explode both client and lib in a common workspace and then load them together?
Or
Can I load a class lazily at runtime? Say, the pipeline in the library knows the client class (startup param or script invocation) and then instantiates it and transfers control to it? Something like an SPI.
App design:
Library ABC with src/vars/resources.
Module X uses #Library('ABC') -Jenkinsfile invokes pipeline in the Library ABC.
Module X structure
src/
package/class1
I am trying to use the GroovyClassLoader to load a groovy src file for class1 in Library script and invoke it. The Jenkins pipeline however, does not permit GroovyClassLoader in the script. How do I whitelist it?
I assume that your Jenkins shared library has the following structure.
ABC
|
|----src/
|----resorces/
|----var/
You can create a Test.groovy file under src
package com.jenkins
class Test {
def execute(def dsl){
dsl.echo "I am inside the Test class"
println("I am also inside the Test class")
}
}
Create a pipeline.groovy under var directory.
An example pipeline.groovy will be
import com.jenkins.Test
def call(final Map parameters = [:]) {
node('master'){
Test.execute(this) //This utilizes the class that you have defined. I
}
}
Now the module can have a Jenkins file with the following content.
#Library('ABC')_
pipeline // This invokes pipeline.groovy
Related
We are currently in the process of setting up a Jenkins shared library to be used for several Java projects. Our file vars/utils.groovy contains the following (simplified) snippet:
def mvn(String mvnCommand) {
// withCredentials(userVarEtc=USER, pwVarEtc=PASS, etc, etc) {
sh "mvn ${mvnCommand} -Duser${USER} -Dpass${PASS} --settings maven_settings.xml"
// }
}
Although above snippet works fine, it requires all Java projects to keep the exact same maven_settings.xml template file in the root of the project. To prevent duplication we would like to add the maven_settings.xml file in the shared library and refer to its shared library path in the groovy method above. Would anyone know how to do this?
I can think of two possible solutions.
Solution 1
Keep the file maven_settings.xml in the resources directory.
shared-library-repository
+--resources/maven_settings.xml
+--vars/utils.groovy
In your shared library method, read this file and write to workspace before calling the maven commands.
def mvn(String mvnCommand) {
def myMavenSettings = libraryResource 'maven_settings.xml'
writeFile file: 'maven_settings.xml', text: myMavenSettings
withCredentials(userVarEtc=USER, pwVarEtc=PASS, etc, etc) {
sh "mvn ${mvnCommand} -Duser${USER} -Dpass${PASS} --settings $WORKSPACE/maven_settings.xml"
}
}
Solution 2
Install the Config File Provider plugin.
Go to Manage Jenkins > Managed files > Add a new Config.
Click Maven settings.xml and then Submit.
Type the name and paste the content in the designated fields.
Rename or copy the file ID and then click Save.
In you shared library method, invoke the plugin step to run maven commands.
def mvn(String mvnCommand) {
configFileProvider([configFile(fileId: '<file_ID>', variable: 'MAVEN_SETTINGS')]) {
withCredentials(userVarEtc=USER, pwVarEtc=PASS, etc, etc) {
sh "mvn ${mvnCommand} -Duser${USER} -Dpass${PASS} --settings $MAVEN_SETTINGS"
}
}
}
We are trying to use some custom helper functions from a .jar library in our Jenkinsfile. To achieve this, we want to use the #Grab annotation from groovy/grape. Our Jenkinsfile looks like this:
#Grab('com.company:jenkins-utils:1.0')
import com.company.jenkinsutils.SomeClass
pipeline {
...
}
When trying to run the pipeline, we get the following error message:
java.lang.RuntimeException: No suitable ClassLoader found for grab
I already tried specifying #GrabConfig(systemClassLoader = true), however to no success. I suppose is has to do with the pipeline scripts running in the sandbox mode? Is there any way to make this work?
Hi I want to create a class in a separate file from my main build.gradle, when I run gradle I get ... Build file: build.gradle line: 2 ... > Could not get Property 'Foo' for root project ...
My files:
// build.gradle
apply from: 'foo.gradle'
println Foo // <- Line 2
// foo.gradle
class Foo {
}
Have a look at the documentation:
You can include the task class directly in the build script. This has the benefit that the task class is automatically compiled and included in the classpath of the build script without you having to do anything. However, the task class is not visible outside the build script, and so you cannot reuse the task class outside the build script it is defined in.
Source
You have 2 options to work around that
like you've found out you can use ext.Foo = Foo inside the foo.gradle
use the buildSrc feature from gradle have a look at this for more information
I want to be able to load a custom class from my pipeline script.
Specifically, I'm looking at having my pipeline script checkout fetch the Jenkinsfile and a number of .groovy files in the same directory (eg classA.groovy, classB.groovy)
I would expect to be able to have my pipeline script simply do a:
import classA
import classB
However, this results in an "Unable to resolve class" error.
I've tried the "pipeline-classpath-step-plugin", but it requires the main pipeline script to call its new step "AddToClassPath" and then load in an additional file which then can import.
Is there some other way to modify (or even to see) the classpath the script is running with?
I am looking for a simple way write short shell scripts that call into jar files.
Having to keep track of (and installing) all those jar files for the runtime classpath partly defeats the purpose using a script (as opposed to building a runnable jar file in Eclipse). I'd like Maven (or something equivalent) to manage this.
Image:
#!/usr/bin/the-cool-shell
use org.apache.commons/lang/3.0.0
use org.json/json
import org.json.*;
new JSONObject("{}");
And this should get the required artifacts from Maven automatically (at basically zero overhead after downloading it for the first time).
What are my options?
If you were using Groovy and Groovy Shell you could be using the Grape infrastructure.
#!/usr/bin/env groovy
#Grab( 'log4j:log4j:1.2.14' )
import org.apache.log4j.Level
import org.apache.log4j.Logger
def logger = Logger.getLogger(GroovyShell.class)
Logger.rootLogger.level = Level.INFO
logger.info 'I am using the Log4j library by using Grape'
As for your exact example this would work:
#!/usr/bin/env groovy
#Grapes([
#Grab('org.apache.commons:commons-lang3:3.0'),
#Grab('org.json:json:20090211')
])
import org.json.*
new JSONObject('{}')
In this case I was using the Groovy syntax but ordinary Java syntax is also fine.
Taken from the Javadoc of #Grapes annotation:
Sometimes we will need more than one grab per class, but we can only add
one annotation type per annotatable node. This class allows for multiple
grabs to be added.
You could try Gradle, it's a build management tool, but it uses Groovy for its build scripts, and it uses the Maven dependency model. So your script could be a Gradle 'build' script, that just did something different than building software.