Implement script-id for multibranch with default.

Main feature to use multibranch with defaults project type is
build configuration mode with default groovy script
stored in global Jenkins store provided by config-file provider
plugin. Options "script-id" and "sandbox" fully implements this
feature.

Besides both project type support "script-path" and "script-id"
mode. It may be convenient to switch mode without changing project
type in order to save project history.

Change-Id: I4cd62e69c9abe7d8fc2e0dfdbe25d8b07ddf51c5
This commit is contained in:
Rotaru Sergey 2020-06-09 15:21:07 +03:00
parent 6c55bc7821
commit ff0ecac7c6
5 changed files with 150 additions and 16 deletions

View File

@ -60,10 +60,18 @@ Plugins required:
(default '-1, forever')
* **script-path** (`str`): Path to Jenkinsfile, relative to workspace.
(default 'Jenkinsfile')
* **script-id** (`str`): Script id from the global Jenkins script store
provided by the config-file provider plugin. Mutually exclusive with
**script-path** option.
* **sandbox** (`bool`): This option is strongly recommended if the
Jenkinsfile is using load to evaluate a groovy source file from an
SCM repository. Usable only with **script-id** option. (default 'false')
Job examples:
.. literalinclude:: /../../tests/multibranch/fixtures/multibranch_defaults.yaml
.. literalinclude:: /../../tests/multibranch/fixtures/multibranch_defaults_id_mode.yaml
.. literalinclude:: /../../tests/multibranch/fixtures/multibranch_defaults_path_mode.yaml
.. literalinclude:: /../../tests/multibranch/fixtures/multi_scm_full.yaml
@ -85,8 +93,39 @@ logger = logging.getLogger(str(__name__))
class WorkflowMultiBranch(jenkins_jobs.modules.base.Base):
sequence = 0
multibranch_path = "org.jenkinsci.plugins.workflow.multibranch"
multibranch_defaults_path = "org.jenkinsci.pipeline.workflow.multibranch"
jenkins_class = "".join([multibranch_path, ".WorkflowMultiBranchProject"])
jenkins_factory_class = "".join([multibranch_path, ".WorkflowBranchProjectFactory"])
jenkins_factory = {
"script_path": {
"class": "".join([multibranch_path, ".WorkflowBranchProjectFactory"])
},
"script_id": {
"class": "".join(
[
multibranch_defaults_path,
".defaults.PipelineBranchDefaultsProjectFactory",
]
),
"plugin": "pipeline-multibranch-defaults",
},
}
@staticmethod
def _factory_opts_check(data):
sandbox = data.get("sandbox", None)
script_id = data.get("script-id", None)
script_path = data.get("script-path", None)
if script_id and script_path:
error_msg = "script-id and script-path are mutually exclusive options"
raise JenkinsJobsException(error_msg)
elif not script_id and sandbox:
error_msg = (
"Sandbox mode is applicable only for multibranch with defaults"
"project type used with script-id option"
)
raise JenkinsJobsException(error_msg)
def root_xml(self, data):
xml_parent = XML.Element(self.jenkins_class)
@ -268,28 +307,50 @@ class WorkflowMultiBranch(jenkins_jobs.modules.base.Base):
# Factory #
###########
factory = XML.SubElement(
xml_parent, "factory", {"class": self.jenkins_factory_class}
)
self._factory_opts_check(data)
if data.get("script-id"):
mode = "script_id"
fopts_map = (
("script-id", "scriptId", None),
("sandbox", "useSandbox", None),
)
else:
mode = "script_path"
fopts_map = (("script-path", "scriptPath", "Jenkinsfile"),)
factory = XML.SubElement(xml_parent, "factory", self.jenkins_factory[mode])
XML.SubElement(
factory, "owner", {"class": self.jenkins_class, "reference": "../.."}
)
XML.SubElement(factory, "scriptPath").text = data.get(
"script-path", "Jenkinsfile"
)
# multibranch default
helpers.convert_mapping_to_xml(factory, data, fopts_map, fail_required=False)
return xml_parent
class WorkflowMultiBranchDefaults(WorkflowMultiBranch):
jenkins_class = (
"org.jenkinsci.plugins.pipeline.multibranch"
".defaults.PipelineMultiBranchDefaultsProject"
)
jenkins_factory_class = (
"org.jenkinsci.plugins.pipeline.multibranch"
".defaults.PipelineBranchDefaultsProjectFactory"
multibranch_path = "org.jenkinsci.plugins.workflow.multibranch"
multibranch_defaults_path = "org.jenkinsci.plugins.pipeline.multibranch"
jenkins_class = "".join(
[multibranch_defaults_path, ".defaults.PipelineMultiBranchDefaultsProject"]
)
jenkins_factory = {
"script_path": {
"class": "".join([multibranch_path, ".WorkflowBranchProjectFactory"]),
"plugin": "workflow-multibranch",
},
"script_id": {
"class": "".join(
[
multibranch_defaults_path,
".defaults.PipelineBranchDefaultsProjectFactory",
]
)
},
}
def bitbucket_scm(xml_parent, data):

View File

@ -58,6 +58,7 @@
</sources>
<factory class="org.jenkinsci.plugins.pipeline.multibranch.defaults.PipelineBranchDefaultsProjectFactory">
<owner class="org.jenkinsci.plugins.pipeline.multibranch.defaults.PipelineMultiBranchDefaultsProject" reference="../.."/>
<scriptPath>Jenkinsfile</scriptPath>
<scriptId>my-pipeline</scriptId>
<useSandbox>true</useSandbox>
</factory>
</org.jenkinsci.plugins.pipeline.multibranch.defaults.PipelineMultiBranchDefaultsProject>

View File

@ -0,0 +1,9 @@
name: 'demo-multibranch-defaults'
project-type: multibranch-defaults
script-id: my-pipeline
sandbox: true
scm:
- github:
repo: 'foo'
repo-owner: 'johndoe'
credentials-id: 'secret'

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<org.jenkinsci.plugins.pipeline.multibranch.defaults.PipelineMultiBranchDefaultsProject plugin="workflow-multibranch">
<properties/>
<views>
<hudson.model.AllView>
<name>All</name>
<filterExecutors>false</filterExecutors>
<filterQueue>false</filterQueue>
<properties class="hudson.model.View$PropertyList"/>
<owner class="org.jenkinsci.plugins.pipeline.multibranch.defaults.PipelineMultiBranchDefaultsProject" reference="../../.."/>
</hudson.model.AllView>
</views>
<viewsTabBar class="hudson.views.DefaultViewsTabBar"/>
<folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api">
<owner class="org.jenkinsci.plugins.pipeline.multibranch.defaults.PipelineMultiBranchDefaultsProject" reference="../.."/>
</folderViews>
<healthMetrics>
<com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric plugin="cloudbees-folder">
<nonRecursive>false</nonRecursive>
</com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric>
</healthMetrics>
<icon class="jenkins.branch.MetadataActionFolderIcon" plugin="branch-api">
<owner class="org.jenkinsci.plugins.pipeline.multibranch.defaults.PipelineMultiBranchDefaultsProject" reference="../.."/>
</icon>
<orphanedItemStrategy class="com.cloudbees.hudson.plugins.folder.computed.DefaultOrphanedItemStrategy" plugin="cloudbees-folder">
<pruneDeadBranches>true</pruneDeadBranches>
<daysToKeep>-1</daysToKeep>
<numToKeep>-1</numToKeep>
</orphanedItemStrategy>
<triggers/>
<sources class="jenkins.branch.MultiBranchProject$BranchSourceList" plugin="branch-api">
<data>
<jenkins.branch.BranchSource>
<source class="org.jenkinsci.plugins.github_branch_source.GitHubSCMSource" plugin="github-branch-source">
<id>gh-johndoe-foo</id>
<repoOwner>johndoe</repoOwner>
<repository>foo</repository>
<credentialsId>secret</credentialsId>
<traits>
<org.jenkinsci.plugins.github__branch__source.BranchDiscoveryTrait>
<strategyId>1</strategyId>
</org.jenkinsci.plugins.github__branch__source.BranchDiscoveryTrait>
<org.jenkinsci.plugins.github__branch__source.ForkPullRequestDiscoveryTrait>
<strategyId>1</strategyId>
<trust class="org.jenkinsci.plugins.github_branch_source.ForkPullRequestDiscoveryTrait$TrustContributors"/>
</org.jenkinsci.plugins.github__branch__source.ForkPullRequestDiscoveryTrait>
<org.jenkinsci.plugins.github__branch__source.OriginPullRequestDiscoveryTrait>
<strategyId>1</strategyId>
</org.jenkinsci.plugins.github__branch__source.OriginPullRequestDiscoveryTrait>
<jenkins.plugins.git.traits.WipeWorkspaceTrait>
<extension class="hudson.plugins.git.extensions.impl.WipeWorkspace"/>
</jenkins.plugins.git.traits.WipeWorkspaceTrait>
</traits>
</source>
</jenkins.branch.BranchSource>
</data>
<owner class="org.jenkinsci.plugins.pipeline.multibranch.defaults.PipelineMultiBranchDefaultsProject" reference="../.."/>
</sources>
<factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory" plugin="workflow-multibranch">
<owner class="org.jenkinsci.plugins.pipeline.multibranch.defaults.PipelineMultiBranchDefaultsProject" reference="../.."/>
<scriptPath>Jenkinsfile</scriptPath>
</factory>
</org.jenkinsci.plugins.pipeline.multibranch.defaults.PipelineMultiBranchDefaultsProject>