Specifying a GitHub project URL in a Jenkins Multibranch pipeline - jenkins

I'm trying to specify the GithubProjectProperty in a Jenkins Multibranch pipeline. I've been unsuccessful attempting to set an entry in the option block to control this value.
The pipeline syntax snippet generator suggests:
properties([
$class: 'GithubProjectProperty',
displayName: '',
projectUrlStr: 'https://myServer/myOrg/myRepo'
])
None of the following appear to work:
1) Try to put the properties directly in the options block
options {
// Set the URL for the GitHub project option
properties([
$class: 'GithubProjectProperty',
displayName: '',
projectUrlStr: 'https://myServer/myOrg/myRepo'
])
}
ERROR: The ‘properties’ section has been renamed as of version 0.8. Use ‘options’ instead
2) Remove the properties keyword but leave the option in the options block
options {
// Set the URL for the GitHub project option
[
$class: 'GithubProjectProperty',
displayName: '',
projectUrlStr: 'https://myServer/myOrg/myRepo'
]
}
ERROR: Options cannot be defined as maps
3) Treat the GitHubProjectProperty as if it can be instantiated (like office365ConnectorWebhooks)
options {
// Set the URL for the GitHub project option
GithubProjectProperty('https://myServer/myOrg/myRepo')
}
ERROR: Invalid option type "GithubProjectProperty". Valid option types: [authorizationMatrix, buildDiscarder, catchError, checkoutToSubdirectory, disableConcurrentBuilds, disableResume, durabilityHint, newContainerPerStage, office365ConnectorWebhooks, overrideIndexTriggers, parallelsAlwaysFailFast, preserveStashes, quietPeriod, rateLimitBuilds, retry, script, skipDefaultCheckout, skipStagesAfterUnstable, timeout, waitUntil, warnError, withContext, withCredentials, withEnv, ws]
4) Treat the GitHubProjectProperty as if it can be instantiated but inside a script block (because script is supposed to be valid according to attempt #3)
options {
script {
// Set the URL for the GitHub project option
GithubProjectProperty('https://myServer/myOrg/myRepo')
}
}
ERROR: Options definitions cannot have blocks
The office-365-connector-plugin is a working plugin that is supported in the options block of a Jenkinsfile. I compared its code with the github-plugin source on GitHub and noticed the following line:
#Extension
public static final class DescriptorImpl extends JobPropertyDescriptor {
The code is lacking a #Symbol directive that the office365ConnectorWebhooks appears to provide in its code:
#Extension
#Symbol("office365ConnectorWebhooks")
public final class WebhookJobPropertyDescriptor extends JobPropertyDescriptor {
Is there some special syntax to use to add the GitHub URL to a multibranch pipeline or does that plugin just not support managing it through a Jenkinsfile?

The ability to specify options in a pipeline using a Jenkinsfile requires a Symbol. There is a proposed fix in the Jenkins github-plugin that adds the necessary Symbol directive but it is not currently part of the plugin as of version 1.30.0.
See: https://issues.jenkins-ci.org/browse/JENKINS-62339
It's possible for a developer to build their own updated plugin in the meantime by updating the following file:
src/main/java/com/coravy/hudson/plugins/github/GithubProjectProperty.java in the source found at: https://github.com/jenkinsci/github-plugin
Add the Symbol:
import org.jenkinsci.Symbol;
...
#Extension
#Symbol("githubProjectProperty")
public static final class DescriptorImpl extends JobPropertyDescriptor {
...
And for good measure, make sure the code specifies the correct function signature for newInstance:
#Override
public JobProperty<?> newInstance(#Nonnull StaplerRequest req, JSONObject formData)
throws Descriptor.FormException {
The updated plugin may be installed by a Jenkins admin using the Advanced option in the Plugin Manager to upload an .hpi file from outside the central plugin repository

I had the same problem and was able to solve it with:
options{
githubProjectProperty(displayName: '', projectUrlStr: 'your_project_url')
}

Related

Add Jenkins Shared Libraries with classes reference in a Jenkinsfile dynamically

I have constructed a Shared Library in which I want to have class definitions, below is the example shared lib code.
package api
class api implements Serializable {
private final Map data
private final DSL steps
api(Map data, DSL steps) {
this.data = data
this.steps = steps
}
}
I have placed this class definition in a shared library git repo, with the path api/src/api/api.groovy. I am importing the shared library using the following step at the top of my jenkinsfile, outside any node or pipeline directive:
library identifier: 'api#master', retriever: modernSCM(
scm: [
$class: 'GitSCMSource',
credentialsId: '<my-credentials-id>',
remote: '<my-git-remote>',
traits: [gitBranchDiscovery()]
],
libraryPath: 'api/'
)
import api.*
When I use the above class from the shared library it's throwing an exception saying that the class is not found.
WorkflowScript: 75: unable to resolve class api
# line 75, column 29.
api foo = new api(env.data, steps)
^
at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:309)
at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:981)
at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:626)
at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:575)
at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:323)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:293)
at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox$Scope.parse(GroovySandbox.java:163)
at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.doParse(CpsGroovyShell.java:142)
at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.reparse(CpsGroovyShell.java:127)
at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.parseScript(CpsFlowExecution.java:562)
at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.start(CpsFlowExecution.java:514)
at org.jenkinsci.plugins.workflow.job.WorkflowRun.run(WorkflowRun.java:336)
at hudson.model.ResourceController.execute(ResourceController.java:107)
at hudson.model.Executor.run(Executor.java:449)
Finished: FAILURE
As i read in the doccument that loading library dynamically does not import classes directly to the pipeline's classpath.
So need a little help to get this class into my job execution.
Note: I have tested it and it's working when adding the global libraries under jenkins global settings, however i want this library setting to be dynamic from jenkins file.

How to add Jenkins Plugin to repo with tests written in Jenkins Pipeline Unit?

I'm trying to test simple Jenkinsfile Pipeline using Jenkins Pipeline Unit and I have an issue with plugin ansiColor.
I added plugin to build.gradle file:
dependencies {
[...]
testImplementation 'org.jenkins-ci.plugins:ansicolor:1.0.0'
}
I added option to Jenkinsfile
pipeline {
options {
ansiColor('xterm')
[...]
}
After running "gradle clean test" I received an error:
Test testExamplePipeline FAILED (2.2s)
groovy.lang.MissingMethodException: No signature of method: Jenkinsfile.ansiColor() is applicable for argument types: (String) values: [xterm]
at app//TestExampleJenkinsfile.testExamplePipeline(TestExampleJenkinsfile.groovy:16)
How to correctly add plugin to Jenkins Pipeline Unit test?
PS:
Code is available here:
https://github.com/shinhf/jenkins-jpu-test-example
PS2
I know I can always register method using registerAllowedMethod, but I think it's not resolution:
helper.registerAllowedMethod("ansiColor", [String], null)

Can I write Jenkins custom steps for declarative pipelines in a way that gives me code completion?

I create custom steps like this: https://www.jenkins.io/doc/book/pipeline/shared-libraries/#defining-custom-steps
// vars/buildPlugin.groovy
def call(Map config) {
node {
git url: "https://github.com/jenkinsci/${config.name}-plugin.git"
sh 'mvn install'
mail to: '...', subject: "${config.name} plugin build", body: '...'
}
}
Then it's called like this: buildPlugin name: 'git'
The problem is I don't get any code completion or type info for its parameters.
Is there a Groovy language feature Jenkins supports that would allow me to define the parameters a custom step needs similar to the properties of a class or arguments of a method? I was thinking about using an interface somehow, but doesn't look like Jenkins would support it: https://issues.jenkins.io/browse/JENKINS-27927
I'm using declarative not scripted pipelines.

Trigger Jenkins Job from shared library

This is what I have in my shared library file
build job: 'Job Name',
parameters:
[
string(name: 'ENVIRONMENT', value: 'sit'),
string(name: 'param1', value: 'value1' )
]
It is failing with below error :
hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: build.call() is applicable for argument types: (java.util.LinkedHashMap) values: [[job:**********, parameters:[#string(name=ENVIRONMENT,value=sit), ...]]]
Possible solutions: call(java.lang.Object, java.lang.Object, java.lang.Object), wait(), any(), wait(long), main([Ljava.lang.String;), any(groovy.lang.Closure)
Any help here?
Library classes cannot directly call steps such as sh or git. They can however implement methods, outside of the scope of an enclosing class, which in turn invoke Pipeline steps, for example:
// src/org/foo/Zot.groovy
package org.foo;
def checkOutFrom(repo) {
git url: "git#github.com:jenkinsci/${repo}"
}
return this
Which can then be called from a Scripted Pipeline:
def z = new org.foo.Zot()
z.checkOutFrom(repo)
This approach has limitations; for example, it prevents the declaration of a superclass.
Alternately, a set of steps can be passed explicitly using this to a library class, in a constructor, or just one method:
package org.foo
class Utilities implements Serializable {
def steps
Utilities(steps) {this.steps = steps}
def mvn(args) {
steps.sh "${steps.tool 'Maven'}/bin/mvn -o ${args}"
}
}
When saving state on classes, such as above, the class must implement the Serializable interface. This ensures that a Pipeline using the class, as seen in the example below, can properly suspend and resume in Jenkins.
#Library('utils') import org.foo.Utilities
def utils = new Utilities(this)
node {
utils.mvn 'clean package'
}
If the library needs to access global variables, such as env, those should be explicitly passed into the library classes, or methods, in a similar manner.
Instead of passing numerous variables from the Scripted Pipeline into a library,
package org.foo
class Utilities {
static def mvn(script, args) {
script.sh "${script.tool 'Maven'}/bin/mvn -s ${script.env.HOME}/jenkins.xml -o ${args}"
}
}
The above example shows the script being passed in to one static method, invoked from a Scripted Pipeline as follows:
#Library('utils') import static org.foo.Utilities.*
node {
mvn this, 'clean package'
}
For more info see jenkins shared library documentation: https://jenkins.io/doc/book/pipeline/shared-libraries/
Try adding propagate and wait like below:
build job: 'Job Name', parameters: [ string(name: 'ENVIRONMENT', value: 'sit'), string(name: 'param1', value: 'value1' ) ],propagate: true, wait: true
Ok. So I figured out the problem.
One of the shared file name was build.groovy which was causing conflicts with build pipeline step. Renamed the file and that fixed the issue.

How to import and run 3rd party Jenkins Plugin's extension DSL (githubPullRequest) with Gradle tool locally?

I'm a newbie at Jenkins job-dsl scripting.
I'm working to convert the Jenkins XML configuration to Groovy DSL script using a plugin (https://github.com/AOEpeople/gradle-jenkins-job-dsl-plugin) that uses Gradle tool for building the script and running Unit Test locally.
However, currently, I'm facing an issue with the extension DSL from a 3rd Party Jenkins Plugin (https://github.com/jenkinsci/ghprb-plugin).
triggers {
githubPullRequest {
orgWhitelist("Test")
cron("H/5 * * * *")
extensions {
commitStatus {
completedStatus('SUCCESS', 'Build succeeded.')
completedStatus('FAILURE', 'Build failed.')
}
}
}
}
The script cannot be generated by Gradle because of the issue:
Expected no exception to be thrown, but got 'javaposse.jobdsl.dsl.DslScriptException'
at spock.lang.Specification.noExceptionThrown(Specification.java:119)
at com.aoe.gradle.jenkinsjobdsl.JobScriptsSpec.test DSL script #file.name(JobScriptsSpec.groovy:55)
Caused by: javaposse.jobdsl.dsl.DslScriptException: (PullRequestJobTemplate.groovy, line 59) No signature of method: static org.apache.commons.lang.ClassUtils.isAssignable() is applicable for argument types: ([Ljava.lang.Class;, [Ljava.lang.Class;, java.lang.Boolean) values: [[class com.unified.dsl.templates.PullRequestJobTemplate$_closure1$_closure5$_closure15], ...]
Possible solutions: isAssignable([Ljava.lang.Class;, [Ljava.lang.Class;), isAssignable(java.lang.Class, java.lang.Class)
at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScriptEngine(AbstractDslScriptLoader.groovy:107)
at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScripts_closure1(AbstractDslScriptLoader.groovy:60)
at groovy.lang.Closure.call(Closure.java:414)
at groovy.lang.Closure.call(Closure.java:430)
at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScripts(AbstractDslScriptLoader.groovy:46)
at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScript(AbstractDslScriptLoader.groovy:81)
at com.aoe.gradle.jenkinsjobdsl.JobScriptsSpec.test DSL script #file.name(JobScriptsSpec.groovy:51)
Caused by: groovy.lang.MissingMethodException: No signature of method: static org.apache.commons.lang.ClassUtils.isAssignable() is applicable for argument types: ([Ljava.lang.Class;, [Ljava.lang.Class;, java.lang.Boolean) values: [[class com.unified.dsl.templates.PullRequestJobTemplate$_closure1$_closure5$_closure15], ...]
Possible solutions: isAssignable([Ljava.lang.Class;, [Ljava.lang.Class;), isAssignable(java.lang.Class, java.lang.Class)
at javaposse.jobdsl.plugin.ExtensionPointHelper.findExtensionPoints_closure1(ExtensionPointHelper.groovy:24)
at javaposse.jobdsl.plugin.ExtensionPointHelper.findExtensionPoints(ExtensionPointHelper.groovy:23)
at javaposse.jobdsl.plugin.JenkinsJobManagement.callExtension(JenkinsJobManagement.java:365)
at javaposse.jobdsl.dsl.AbstractExtensibleContext.methodMissing(AbstractExtensibleContext.groovy:17)
at com.unified.dsl.templates.PullRequestJobTemplate.closure1$_closure5(PullRequestJobTemplate.groovy:59)
at com.unified.dsl.templates.PullRequestJobTemplate.closure1$_closure5(PullRequestJobTemplate.groovy)
at javaposse.jobdsl.dsl.ContextHelper.executeInContext(ContextHelper.groovy:16)
at javaposse.jobdsl.dsl.Job.triggers(Job.groovy:568)
at com.unified.dsl.templates.PullRequestJobTemplate$_closure1.doCall(PullRequestJobTemplate.groovy:58)
at groovy.lang.Closure.call(Closure.java:414)
at groovy.lang.Closure.call(Closure.java:430)
at groovy.lang.Closure.call(Closure.java:430)
at javaposse.jobdsl.dsl.JobParent.processItem(JobParent.groovy:114)
at javaposse.jobdsl.dsl.JobParent.freeStyleJob(JobParent.groovy:47)
at com.unified.dsl.base.JobBuilder.build(JobBuilder.groovy:52)
at stage.script.run(script:12)
at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScript(AbstractDslScriptLoader.groovy:124)
at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScriptEngine(AbstractDslScriptLoader.groovy:101)
... 6 more
So the stacktrace you are getting is being generated by the Spock Test that checks to see if the job-dsl script compiles. So you have set up your development environment correctly! Always a good start.
Now all you need to do is setup your local Jenkins runtime to allow the Jenkins XML config file to be generated when it is kicked off by the Spock Test.
Reviewing your job-dsl script I must say it looks good to me. Specifically I compared it to the complete sample job-dsl on the GitHub pull request builder plugin's home page ...
https://wiki.jenkins.io/display/JENKINS/GitHub+pull+request+builder+plugin#GitHubpullrequestbuilderplugin-JobDSLSupport
The key part of the stack trace is this line here
PullRequestJobTemplate.groovy, line 59) No signature of method:
static org.apache.commons.lang.ClassUtils.isAssignable() is applicable
for argument types: ([Ljava.lang.Class;, [Ljava.lang.Class;,
java.lang.Boolean) values: [[class com.unified.dsl.templates.PullRequestJobTemplate$_closure1$_closure5$_closure15], ...]
To me this would indicate that there was still a run-time dependency missing to allow the GH PR Builder plugin job-dsl to run as expected.
Further reviewing the plugin page I note that the following dependencies are variously required and optional ...
credentials (version:1.21)
matrix-project (version:1.6)
build-flow-plugin (version:0.12, optional)
ssh-agent (version:1.3)
structs (version:1.6)
github (version:1.26.0)
git (version:2.4.0)
github-api (version:1.82)
plain-credentials (version:1.1)
job-dsl (version:1.39, optional)
token-macro (version:1.10, optional)
If you add these to the Gradle build then I would say that your XML will be generated.
Don't forget to add these dependencies to the target Jenkins server when you have completed your job-dsl development.

Resources