How can a jenkins plugin get the value of a configuration setting? - jenkins

I'm creating a Jenkins plugin which is a post-build action. I want the plugin to read the value of the "Root POM" field in the job configuration page. I've been looking through the Javadocs for hudson.model.AbstractBuild and trying getBuildVariables(), getEnvironment() etc. but I don't see anything relevant.
I guess as a last resort I could configure my plugin to prompt the user for the root pom, but the problem is that management wants a plugin that can be deployed automatically on every build without any action on the user's part.

Do you mean you want a plugin to read the configuration of another plugin (the maven one)? If so, I believe you should use something like
Jenkins.getInstance().getDescriptor(RequiredDesc.class);
Your required class might be hudson/maven/Maven3Builder depending on what you are trying to do.
Discussion
Update
I was wrong. This seems to work for me:
if (build instanceof hudson.maven.MavenModuleSetBuild) {
try {
hudson.maven.MavenModuleSetBuild b = (hudson.maven.MavenModuleSetBuild) build;
hudson.EnvVars envVars = b.getEnvironment(listener);
String rootPOM = b.getProject().getRootPOM(envVars);
listener.getLogger().println("rootPOM: " + rootPOM);
} catch (Exception e) {
listener.getLogger().println("ERROR: " + e.getMessage());
}
}

Related

Is it possible to use build user vars plugin in a Jenkins shared library?

I'm implementing functionality to expose the triggering user for a Jenkins pipeline to our CD system, so I've grabbed the build user vars plugin: https://plugins.jenkins.io/build-user-vars-plugin/
The way the plugin seems to work is that you wrap the code you need the variables exposed to, like so:
wrap([$class: 'BuildUser']) {
userId = env.BUILD_USER_ID
}
I tried this on a general pipeline and just echoed it out, all was well.
I then tried implementing it in our shared library so that this would happen on all calls to CD, and I'm hitting an error.
wrap([$class: 'BuildUser']) {
jobBuildUrl ="${jobBuildUrl}&USER_ID=${env.BUILD_USER_ID}"
}
[2021-08-19T10:20:22.852Z] hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: com.company.jenkins.pipelines.BuildManager.wrap() is applicable for argument types: (java.util.LinkedHashMap, org.jenkinsci.plugins.workflow.cps.CpsClosure2) values: [[$class:BuildUser], org.jenkinsci.plugins.workflow.cps.CpsClosure2#1c9a210c]
Is there any way to use this plugin code within a shared library? If so how?
I'm lead to believe not, but I thought it was worth the asking. For reference, there is this outstanding issue: https://issues.jenkins.io/browse/JENKINS-44741
Side note, I'm trying to do this without touching everybody's pipelines themselves. If this is impossible with this plugin, I'll probably just implement my own version of it within the shared lib.
That plugin is hard to use and has many issues, one of them is with shared libraries.
Instead just implement it by yourself, it is relatively easy and allows you much more control over the logic of what is done, error handling and which parameters you return.
You can use something like the following:
/**
* Get the last upstream build that triggered the current build
* #return Build object (org.jenkinsci.plugins.workflow.job.WorkflowRun) representing the upstream build
*/
#NonCPS
def getUpstreamBuild() {
def build = currentBuild.rawBuild
def upstreamCause
while (upstreamCause = build.getCause(hudson.model.Cause$UpstreamCause)) {
build = upstreamCause.upstreamRun
}
return build
}
/**
* Get the properties of the build Cause (the event that triggered the build)
* #param upstream If true (Default) return the cause properties of the last upstream job (If the build was triggered by another job or by a chain of jobs)
* #return Map representing the properties of the user that triggered the current build.
* Contains keys: USER_NAME, USER_ID
*/
#NonCPS
def getUserCauseProperties(Boolean upstream = true) {
def build = upstream ? getUpstreamBuild() : currentBuild.rawBuild
def cause = build.getCause(hudson.model.Cause$UserIdCause)
if (cause) {
return ['USER_NAME': cause.userName, 'USER_ID': cause.userId]
}
println "Job was not started by a user, it was ${build.getCauses()[0].shortDescription}"
return [:]
}
I was also not able to use wrap([$class: 'BuildUser']) into groovy method. Therefore I think I found alternative way which seems to do the trick. You may get the username and userid (which might return email, depends on your setup) by just the following:
def build = currentBuild.rawBuild
def cause = build.getCause(hudson.model.Cause.UserIdCause.class)
def userName = cause.getUserName() // or use getUserId()

How to Get a list of job source code management and build for all jobs

I am looking for a way to get a list of build and source code management section in the configuration.
For Example: I have jobs with Testcomplete and SoupUI Pro plug ins, in each jobs, in the configuration section, we input the git repo name, testsuite name, directory etc ...
Currently, I am having to go to each job, click on configuration and get the values I need, would be nice where I can get all this information for all the jobs. I looked in configuration slicing, but it does not have the section I need.
Thank you for your help in advance.
I have not used either plugin you mention, but this crude little groovy script will find every Freestyle job and if it has a gitSCM step, report the primary Git repo url, then for every "Invoke top-level Maven target", report the POM value if set.
Run from <JENKINS_URL>/script or in a Jenkins job with an "Execute System Groovy Script" (not an "Execute Groovy script").
You can modify to find your plugin's builder step and properties. You can get the values by examining <job>/config.xml instead of <job>/configure.
Updated example to specifically include also looking up TestComplete plugin (com.smartbear.jenkins.plugins.testcomplete.TcTestBuilder) values.
Similar approach left to OP for ReadyAPI Functional Testing plugin - (com.smartbear.ready.jenkins.JenkinsSoapUIProTestRunner)
WARNING: soapui-pro-functional-testing:1.6 transmits passwords in clear text. So too does SmartBear's Zephyr products. Does not inspire confidence in a company who's tagline is "quality matters more than ever.... we'll help you get there."
Jenkins.instance.allItems.findAll() {
it instanceof hudson.model.FreeStyleProject
}.each { job ->
if (job.scm instanceof hudson.plugins.git.GitSCM) {
println job.fullName + ' | ' + job.scm.userRemoteConfigs.url[0]
job.builders.findAll() {
it instanceof hudson.tasks.Maven
}.each {step ->
println ' : ' + step?.pom
}
job.builders.findAll() {
it instanceof com.smartbear.jenkins.plugins.testcomplete.TcTestBuilder
}.each {step ->
if (step?.getLaunchType() == 'lcRoutine') {
println ' : ' + step?.getProject() + ' : ' + step?.getUnit() + ' : ' + step?.getRoutine()
}
}
}
}
return
ps: I'm sure there's a cleaner way to iterate but I can't do all the work. Be sure to use the "?" to handle null values

Reactive choice parameter to read from workspace file

I am trying to implement active reactive choice parameter .
In reactive parameter basically I am hard coding the different options based on the active parameter
Below is the sample code
if (Target_Environment.equals("Dev01")) {
return ["test_DEV"]
} else if (Target_Environment.equals("Dev02")) {
return ["test3_DEV02","test2_DEV02"]
} else if (Target_Environment.equals("Dev03")) {
return ["test3_DEV03"]
} else if (Target_Environment.equals("Sit03")) {
return ["test3_SIT03"]
}else if (Target_Environment.equals("PPTE")) {
return ["test3_PPTE"]
}
else {
return ["Please Select Target Environment"]
}
Instead hard coding the choices I want to read from a file in jenkins workspace and show the content as the choices , what would be an ideal way to go with that ?
The readFile is not working under return function
I am also trying with extended choice parameter but
there I am passing a property file with filename however how can I pass the property file with if else condition
I'm not 100% sure if this is accurate. But I would expect that you can't read from the job workspace in a parameter like that because workspaces are created after a build (see below error message).
So if you create the job with no previous builds, there will be no workspace file to read from?
Whenever I have seen that parameter type used in the past, they usually read from a file on the server instead of the workspace.
Error message from Jenkins jobs that have no previous builds:
Error: no workspace
A project won't have any workspace until at least one build is performed.
Run a build to have Jenkins create a workspace.

Jenkins plugin - how to get currently executing job?

I am building a jenkins pipeline plugin (methods to be invoked from a pipeline) and need to get retrieve information about the currently running job, which invoked my methods.
There are a couple of questions I found talking about it, for example here - Jenkins Plugin How to get Job information.
Yet I can't figure out how to use this information. I do have access to the Jenkins instance, but don't have any info about the current project, job, build, etc. How can I get hold of that info?
Note, this is a pipeline steps plugin, there is no perform method in it.
Ok, after search, I finally found the answer in the most obvious of all places - documentation for writing pipeline steps plugins and the corresponding API documentation.
The way to do it is from the Execution class. Inside it, just call getContext(), which returns StepContext, which then has .get method to get the rest of the things you need:
public class MyExecution extends SynchronousNonBlockingStepExecution<ReturnType> {
...
#Override
protected ReturnType run() throws Exception {
try {
StepContext context = getContex();
// get currently used workspace path
FilePath path = context.get(FilePath.class);
//get current run
Run run = context.get(Run.class);
// ... and so on ...
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
...
}

grails: guidance on writing scripts, esp for calling existing database-migration scripts

My requirement is to invoke some processing from a Jenkins build server, to determine whether the domain model has changed since the last build. I've come to the conclusion that the way forward is to write a script that will invoke a sequence of existing scripts from the db-migration plugin. Then I can invoke it in the step that calls test-app and war.
I've looked in the Grails doc, and at some of the db-migration scripts, and I find I'm stuck - have no idea where to start trying things. I'd be really grateful if someone could point me at any suitable sources. BTW, I'm a bit rusty in Grails. Started to teach myself two years ago via proof of concept project, which lasted 6 months. Then it was back to Eclipse rich client work. That might be part of my problem, though I never go involved in scripts.
One thing I need in the Jenkins evt is to get hold of the current SVN revision number being used for the build. Suggestions welcome.
Regards, John
Create a new script by running grails create-script scriptname. The database-migration plugins scripts are configured to be easily reused. There are is a lot of shared code in _DatabaseMigrationCommon.groovy and each script defines one target with a unique name. So you can import either the shared script or any standalone script (or multiple scripts) and call the targets like they're methods.
By default the script generated by create-script "imports" the _GrailsInit script via includeTargets << grailsScript("_GrailsInit") and you can do the same, taking advantage of the magic variables that point at installed plugins' directories:
includeTargets << new File("$databaseMigrationPluginDir/scripts/DbmGenerateChangelog.groovy")
If you do this you can remove the include of _GrailsInit since it's already included, but if you don't that's fine since Grails only includes files once.
Then you can define your target and call any of the plugin's targets. The targets cannot accept parameters, but you can add data to the argsMap (this is a map Grails creates from the parsed commandline arguments) to simulate user-specified args. Note that any args passed to your script will be seen by the database-migration plugin's scripts since they use the same argsMap.
Here's an example script that just does the same thing as dbm-generate-changelog but adds a before and after message:
includeTargets << new File("$databaseMigrationPluginDir/scripts/DbmGenerateChangelog.groovy")
target(foo: "Just calls dbmGenerateChangelog") {
println 'before'
dbmGenerateChangelog()
println 'after'
}
setDefaultTarget foo
Note that I renamed the target from main to foo so it's unique, in case you want to call this from another script.
As an example of working with args, here's a modified version that specifies a default changelog name if none is provided:
println 'before'
if (!argsMap.params) {
argsMap.params = ['foo2.groovy']
}
dbmGenerateChangelog()
println 'after'
Edit: Here's a fuller example that captures the output of dbm-gorm-diff to a string:
includeTargets << new File("$databaseMigrationPluginDir/scripts/_DatabaseMigrationCommon.groovy")
target(foo: "foo") {
depends dbmInit
def configuredSchema = config.grails.plugin.databasemigration.schema
String argSchema = argsMap.schema
String effectiveSchema = argSchema ?: configuredSchema ?: defaultSchema
def realDatabase
boolean add = false // booleanArg('add')
String filename = null // argsList[0]
try {
printMessage "Starting $hyphenatedScriptName"
ByteArrayOutputStream baos = new ByteArrayOutputStream()
def baosOut = new PrintStream(baos)
ScriptUtils.executeAndWrite filename, add, dsName, { PrintStream out ->
MigrationUtils.executeInSession(dsName) {
realDatabase = MigrationUtils.getDatabase(effectiveSchema, dsName)
def gormDatabase = ScriptUtils.createGormDatabase(dataSourceSuffix, config, appCtx, realDatabase, effectiveSchema)
ScriptUtils.createAndPrintFixedDiff(gormDatabase, realDatabase, realDatabase, appCtx, diffTypes, baosOut)
}
}
String xml = new String(baos.toString('UTF-8'))
def ChangelogXml2Groovy = classLoader.loadClass('grails.plugin.databasemigration.ChangelogXml2Groovy')
String groovy = ChangelogXml2Groovy.convert(xml)
// do something with the groovy or xml here
printMessage "Finished $hyphenatedScriptName"
}
catch (e) {
ScriptUtils.printStackTrace e
exit 1
}
finally {
ScriptUtils.closeConnection realDatabase
}
}
setDefaultTarget foo

Resources