Add multibranch project-type

This work was based on original work done by
Joshua Harlow on top of older code from:
https://github.com/abnamrocoesd/jenkins-job-builder/

Credit is due to `Joost van der Griendt` for doing this
work. This builds on his work in that repo, and adjusts it
so that it can get merged into upstream and released
as a fully supported job type.

SCM implementation is different than than normal SCM module,
supporting: BitBucket, git, and GitHub in this initial
patch.

Change-Id: If50a54d282dd7d901c16edb9fe04874bdd83c9ef
Co-Authored-By: Joshua Harlow <jxharlow@godaddy.com>
Co-Authored-By: Sorin Sbarnea <ssbarnea@redhat.com>
Co-Authored-By: Thanh Ha <zxiiro@linux.com>
Signed-off-by: Sorin Sbarnea <ssbarnea@redhat.com>
Signed-off-by: Thanh Ha <zxiiro@linux.com>
Signed-off-by: Sorin Sbarnea <ssbarnea@redhat.com>
This commit is contained in:
Joost van der Griendt 2016-11-28 14:35:55 -08:00 committed by Sorin Sbarnea
parent 89506addb7
commit efc5fbe0fd
23 changed files with 1088 additions and 0 deletions

View File

@ -0,0 +1,7 @@
.. _project_multibranch:
Multibranch Pipeline Project
============================
.. automodule:: project_multibranch
:members:

View File

@ -0,0 +1,508 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2015 Joost van der Griendt <joostvdg@gmail.com>
# Copyright (C) 2018 Sorin Sbarnea <ssbarnea@users.noreply.github.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
The Multibranch Pipeline project module handles creating Jenkins workflow
projects.
You may specify ``multibranch`` in the ``project-type`` attribute of
the :ref:`Job` definition.
Multibranch Pipeline implementantion in JJB is marked as **experimental**
which means that there is no guarantee that its behavior (or configuration)
will not change, even between minor releases.
Plugins required:
* :jenkins-wiki:`Workflow Plugin <Workflow+Plugin>`.
* :jenkins-wiki:`Pipeline Multibranch Defaults Plugin
<Pipeline+Multibranch+Defaults+Plugin>` (optional)
:Job Parameters:
* **scm** (`list`): The SCM definition.
* **bitbucket** (`dict`): Refer to
:func:`~bitbucket_scm <bitbucket_scm>` for documentation.
* **git** (`dict`): Refer to
:func:`~git_scm <git_scm>` for documentation.
* **github** (`dict`): Refer to
:func:`~github_scm <github_scm>` for documentation.
* **periodic-folder-trigger** (`str`): How often to scan for new branches
or pull/change requests. Valid values: 1m, 2m, 5m, 10m, 15m, 20m, 25m,
30m, 1h, 2h, 4h, 8h, 12h, 1d, 2d, 1w, 2w, 4w. (default none)
* **prune-dead-branches** (`bool`): If dead branches upon check should
result in their job being dropped. (default true)
* **number-to-keep** (`int`): How many builds should be kept.
(default '-1, all')
* **days-to-keep** (`int`): For how many days should a build be kept.
(default '-1, forever')
Job examples:
.. literalinclude:: /../../tests/multibranch/fixtures/multibranch_defaults.yaml
.. literalinclude:: /../../tests/multibranch/fixtures/multi_scm_full.yaml
"""
import collections
import logging
import xml.etree.ElementTree as XML
import jenkins_jobs.modules.base
import jenkins_jobs.modules.helpers as helpers
import uuid
from jenkins_jobs.errors import InvalidAttributeError
logger = logging.getLogger(str(__name__))
class WorkflowMultiBranch(jenkins_jobs.modules.base.Base):
sequence = 0
multibranch_path = 'org.jenkinsci.plugins.workflow.multibranch'
jenkins_class = ''.join([multibranch_path, '.WorkflowMultiBranchProject'])
jenkins_factory_class = ''.join(
[multibranch_path, '.WorkflowBranchProjectFactory'])
def root_xml(self, data):
xml_parent = XML.Element(self.jenkins_class)
xml_parent.attrib['plugin'] = 'workflow-multibranch'
XML.SubElement(xml_parent, 'properties')
#########
# Views #
#########
views = XML.SubElement(xml_parent, 'views')
all_view = XML.SubElement(views, 'hudson.model.AllView')
all_view_mapping = [
('', 'name', 'All'),
('', 'filterExecutors', False),
('', 'filterQueue', False),
]
helpers.convert_mapping_to_xml(
all_view, {}, all_view_mapping, fail_required=True)
XML.SubElement(all_view, 'properties', {
'class': 'hudson.model.View$PropertyList'
})
XML.SubElement(all_view, 'owner', {
'class': self.jenkins_class,
'reference': '../../..'
})
XML.SubElement(xml_parent, 'viewsTabBar', {
'class': 'hudson.views.DefaultViewsTabBar'
})
################
# Folder Views #
################
folderViews = XML.SubElement(xml_parent, 'folderViews', {
'class': 'jenkins.branch.MultiBranchProjectViewHolder',
'plugin': 'branch-api',
})
XML.SubElement(folderViews, 'owner', {
'class': self.jenkins_class,
'reference': '../..'
})
##################
# Health Metrics #
##################
hm = XML.SubElement(xml_parent, 'healthMetrics')
hm_path = ('com.cloudbees.hudson.plugins.folder.health'
'.WorstChildHealthMetric')
hm_plugin = XML.SubElement(hm, hm_path, {
'plugin': 'cloudbees-folder',
})
XML.SubElement(hm_plugin, 'nonRecursive').text = 'false'
########
# Icon #
########
icon = XML.SubElement(xml_parent, 'icon', {
'class': 'jenkins.branch.MetadataActionFolderIcon',
'plugin': 'branch-api',
})
XML.SubElement(icon, 'owner', {
'class': self.jenkins_class,
'reference': '../..'
})
########################
# Orphan Item Strategy #
########################
ois_default_strategy = ('com.cloudbees.hudson.plugins.'
'folder.computed.DefaultOrphanedItemStrategy')
ois = XML.SubElement(
xml_parent, 'orphanedItemStrategy', {
'class': ois_default_strategy,
'plugin': 'cloudbees-folder',
}
)
ois_mapping = [
('prune-dead-branches', 'pruneDeadBranches', True, [True, False]),
('days-to-keep', 'daysToKeep', -1),
('number-to-keep', 'numToKeep', -1),
]
helpers.convert_mapping_to_xml(ois, data, ois_mapping)
###########################
# Periodic Folder Trigger #
###########################
triggers = XML.SubElement(xml_parent, 'triggers')
# Valid options for the periodic trigger interval.
pft_map = collections.OrderedDict([
("1m", ("* * * * *", '60000')),
("2m", ("*/2 * * * *", '120000')),
("5m", ("*/5 * * * *", '300000')),
("10m", ("H/6 * * * *", '600000')),
("15m", ("H/6 * * * *", '900000')),
("20m", ("H/3 * * * *", '1200000')),
("25m", ("H/3 * * * *", '1500000')),
("30m", ("H/2 * * * *", '1800000')),
("1h", ("H * * * *", '3600000')),
("2h", ("H * * * *", '7200000')),
("4h", ("H * * * *", '14400000')),
("8h", ("H * * * *", '28800000')),
("12h", ("H H * * *", '43200000')),
("1d", ("H H * * *", '86400000')),
("2d", ("H H * * *", '172800000')),
("1w", ("H H * * *", '604800000')),
("2w", ("H H * * *", '1209600000')),
("4w", ("H H * * *", '2419200000')),
])
pft_val = data.get('periodic-folder-trigger')
if pft_val:
if not pft_map.get(pft_val):
raise InvalidAttributeError(
'periodic-folder-trigger',
pft_val,
pft_map.keys())
pft_path = (
'com.cloudbees.hudson.plugins.folder.computed.'
'PeriodicFolderTrigger')
pft = XML.SubElement(triggers, pft_path, {
'plugin': 'cloudbees-folder'
})
XML.SubElement(pft, 'spec').text = pft_map[pft_val][0]
XML.SubElement(pft, 'interval').text = pft_map[pft_val][1]
###########
# Sources #
###########
sources = XML.SubElement(xml_parent, 'sources', {
'class': 'jenkins.branch.MultiBranchProject$BranchSourceList',
'plugin': 'branch-api',
})
sources_data = XML.SubElement(sources, 'data')
XML.SubElement(sources, 'owner', {
'class': self.jenkins_class,
'reference': '../..',
})
valid_scm = [
'bitbucket',
'git',
'github',
]
for scm_data in data.get('scm', None):
for scm in scm_data:
bs = XML.SubElement(
sources_data, 'jenkins.branch.BranchSource')
if scm == 'bitbucket':
bitbucket_scm(bs, scm_data[scm])
elif scm == 'git':
git_scm(bs, scm_data[scm])
elif scm == 'github':
github_scm(bs, scm_data[scm])
else:
raise InvalidAttributeError('scm', scm_data, valid_scm)
###########
# Factory #
###########
factory = XML.SubElement(xml_parent, 'factory', {
'class': self.jenkins_factory_class,
})
XML.SubElement(factory, 'owner', {
'class': self.jenkins_class,
'reference': '../..'
})
XML.SubElement(factory, 'scriptPath').text = 'Jenkinsfile'
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')
def bitbucket_scm(xml_parent, data):
"""Configure BitBucket scm
Requires the :jenkins-wiki:`Bitbucket Branch Source Plugin
<Bitbucket+Branch+Source+Plugin>`.
:arg str credentials-id: The credential to use to scan BitBucket.
(required)
:arg str repo-owner: Specify the name of the Bitbucket Team or Bitbucket
User Account. (required)
:arg str repo: The BitBucket repo. (required)
Minimal Example:
.. literalinclude::
/../../tests/multibranch/fixtures/scm_bitbucket_minimal.yaml
Full Example:
.. literalinclude::
/../../tests/multibranch/fixtures/scm_bitbucket_full.yaml
"""
source = XML.SubElement(xml_parent, 'source', {
'class': 'com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSource',
'plugin': 'cloudbees-bitbucket-branch-source',
})
source_mapping = [
('', 'id', str(uuid.uuid4())),
('repo-owner', 'repoOwner', None),
('repo', 'repository', None),
]
helpers.convert_mapping_to_xml(
source, data, source_mapping, fail_required=True)
mapping_optional = [
('credentials-id', 'credentialsId', None),
]
helpers.convert_mapping_to_xml(
source, data, mapping_optional, fail_required=False)
XML.SubElement(source, 'traits')
def git_scm(xml_parent, data):
"""Configure Git SCM
Requires the :jenkins-wiki:`Git Plugin <Git+Plugin>`.
:arg str url: The git repo url. (required)
:arg str credentials-id: The credential to use to connect to the GIT repo.
(default '')
:arg bool discover-branches: Discovers branches on the repository.
(default true)
:arg bool ignore-on-push-notifications: If a job should not trigger upon
push notifications. (default false)
Minimal Example:
.. literalinclude:: /../../tests/multibranch/fixtures/scm_git_minimal.yaml
Full Example:
.. literalinclude:: /../../tests/multibranch/fixtures/scm_git_full.yaml
"""
source = XML.SubElement(xml_parent, 'source', {
'class': 'jenkins.plugins.git.GitSCMSource',
'plugin': 'git',
})
source_mapping = [
('', 'id', str(uuid.uuid4())),
('url', 'remote', None),
('credentials-id', 'credentialsId', ''),
]
helpers.convert_mapping_to_xml(
source, data, source_mapping, fail_required=True)
##########
# Traits #
##########
traits_path = 'jenkins.plugins.git.traits'
traits = XML.SubElement(source, 'traits')
if data.get('discover-branches', True):
XML.SubElement(traits, ''.join([traits_path, '.BranchDiscoveryTrait']))
if data.get('ignore-on-push-notifications', False):
XML.SubElement(
traits, ''.join([traits_path, '.IgnoreOnPushNotificationTrait']))
def github_scm(xml_parent, data):
"""Configure GitHub SCM
Requires the :jenkins-wiki:`GitHub Branch Source Plugin
<GitHub+Branch+Source+Plugin>`.
:arg str api-uri: The GitHub API uri for hosted / on-site GitHub. Must
first be configured in Global Configuration. (default GitHub)
:arg str credentials-id: Credentials used to scan branches and pull
requests, check out sources and mark commit statuses. (optional)
:arg str repo-owner: Specify the name of the GitHub Organization or
GitHub User Account. (required)
:arg str repo: The GitHub repo. (required)
:arg str branch-discovery: Discovers branches on the repository.
Valid options: no-pr, only-pr, all, false. (default 'no-pr')
:arg str discover-pr-forks-strategy: Fork strategy. Valid options:
merge-current, current, both, false. (default 'merge-current')
:arg str discover-pr-forks-trust: Discovers pull requests where the origin
repository is a fork of the target repository.
Valid options: contributors, everyone, permission or nobody.
(default 'contributors')
:arg str discover-pr-origin: Discovers pull requests where the origin
repository is the same as the target repository.
Valid options: merge-current, current, both. (default 'merge-current')
Minimal Example:
.. literalinclude::
/../../tests/multibranch/fixtures/scm_github_minimal.yaml
Full Example:
.. literalinclude::
/../../tests/multibranch/fixtures/scm_github_full.yaml
"""
github_path = 'org.jenkinsci.plugins.github_branch_source'
github_path_dscore = 'org.jenkinsci.plugins.github__branch__source'
source = XML.SubElement(xml_parent, 'source', {
'class': ''.join([github_path, '.GitHubSCMSource']),
'plugin': 'github-branch-source',
})
mapping = [
('', 'id', str(uuid.uuid4())),
('repo-owner', 'repoOwner', None),
('repo', 'repository', None),
]
helpers.convert_mapping_to_xml(
source, data, mapping, fail_required=True)
mapping_optional = [
('api-uri', 'apiUri', None),
('credentials-id', 'credentialsId', None),
]
helpers.convert_mapping_to_xml(
source, data, mapping_optional, fail_required=False)
traits = XML.SubElement(source, 'traits')
# no-pr value is assumed if branch-discovery not mentioned.
if data.get('branch-discovery', 'no-pr'):
bd = XML.SubElement(traits, ''.join([
github_path_dscore, '.BranchDiscoveryTrait']))
bd_strategy = {
'no-pr': '1',
'only-pr': '2',
'all': '3',
}
bd_mapping = [
('branch-discovery', 'strategyId', 'no-pr', bd_strategy)
]
helpers.convert_mapping_to_xml(
bd, data, bd_mapping, fail_required=True)
if data.get('discover-pr-forks-strategy', 'merged-current'):
dprf = XML.SubElement(
traits, ''.join([
github_path_dscore, '.ForkPullRequestDiscoveryTrait'
])
)
dprf_strategy = {
'merge-current': '1',
'current': '2',
'both': '3',
}
dprf_mapping = [
('discover-pr-forks-strategy', 'strategyId', 'merge-current',
dprf_strategy)
]
helpers.convert_mapping_to_xml(
dprf, data, dprf_mapping, fail_required=True)
trust = data.get('discover-pr-forks-trust', 'contributors')
trust_map = {
'contributors': ''.join([
github_path,
'.ForkPullRequestDiscoveryTrait$TrustContributors']),
'everyone': ''.join([
github_path,
'.ForkPullRequestDiscoveryTrait$TrustEveryone']),
'permission': ''.join([
github_path,
'.ForkPullRequestDiscoveryTrait$TrustPermission']),
'nobody': ''.join([
github_path,
'.ForkPullRequestDiscoveryTrait$TrustNobody']),
}
if trust not in trust_map:
raise InvalidAttributeError('discover-pr-forks-trust',
trust,
trust_map.keys())
XML.SubElement(dprf, 'trust').attrib['class'] = trust_map[trust]
dpro_strategy = data.get('discover-pr-origin', 'merge-current')
dpro = XML.SubElement(traits, ''.join([
github_path_dscore,
'.OriginPullRequestDiscoveryTrait'
]))
dpro_strategy_map = {
'merge-current': '1',
'current': '2',
'both': '3',
}
if dpro_strategy not in dpro_strategy_map:
raise InvalidAttributeError('discover-pr-origin',
dpro_strategy,
dpro_strategy_map.keys())
if trust not in trust_map:
raise InvalidAttributeError('discover-pr-forks-trust',
trust,
trust_map.keys())
dpro_mapping = [
('discover-pr-origin', 'strategyId', 'merge-current',
dpro_strategy_map)
]
helpers.convert_mapping_to_xml(
dpro, data, dpro_mapping, fail_required=True)

View File

@ -1377,6 +1377,12 @@ class SCM(jenkins_jobs.modules.base.Base):
component_list_type = 'scm'
def gen_xml(self, xml_parent, data):
# multibranch-pipeline scm implementation is incompatible with SCM
if data.get('project-type') in ['multibranch', 'multibranch-defaults']:
logging.debug("SCM Module skipped for multibranch project-type.")
return
scms_parent = XML.Element('scms')
for scm in data.get('scm', []):
self.registry.dispatch('scm', scms_parent, scm)

View File

@ -56,6 +56,8 @@ jenkins_jobs.projects =
freestyle=jenkins_jobs.modules.project_freestyle:Freestyle
matrix=jenkins_jobs.modules.project_matrix:Matrix
maven=jenkins_jobs.modules.project_maven:Maven
multibranch=jenkins_jobs.modules.project_multibranch:WorkflowMultiBranch
multibranch-defaults=jenkins_jobs.modules.project_multibranch:WorkflowMultiBranchDefaults
multijob=jenkins_jobs.modules.project_multijob:MultiJob
pipeline=jenkins_jobs.modules.project_pipeline:Pipeline
workflow=jenkins_jobs.modules.project_workflow:Workflow

View File

@ -41,6 +41,7 @@ from jenkins_jobs.modules import project_externaljob
from jenkins_jobs.modules import project_flow
from jenkins_jobs.modules import project_matrix
from jenkins_jobs.modules import project_maven
from jenkins_jobs.modules import project_multibranch
from jenkins_jobs.modules import project_multijob
from jenkins_jobs.modules import view_list
from jenkins_jobs.modules import view_pipeline
@ -188,6 +189,10 @@ class BaseScenariosTestCase(testscenarios.TestWithScenarios, BaseTestCase):
project = project_flow.Flow(registry)
elif (yaml_content['project-type'] == "multijob"):
project = project_multijob.MultiJob(registry)
elif (yaml_content['project-type'] == "multibranch"):
project = project_multibranch.WorkflowMultiBranch(registry)
elif (yaml_content['project-type'] == "multibranch-defaults"):
project = project_multibranch.WorkflowMultiBranchDefaults(registry) # noqa
elif (yaml_content['project-type'] == "externaljob"):
project = project_externaljob.ExternalJob(registry)

View File

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject 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.workflow.multibranch.WorkflowMultiBranchProject" reference="../../.."/>
</hudson.model.AllView>
</views>
<viewsTabBar class="hudson.views.DefaultViewsTabBar"/>
<folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" 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.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</icon>
<orphanedItemStrategy class="com.cloudbees.hudson.plugins.folder.computed.DefaultOrphanedItemStrategy" plugin="cloudbees-folder">
<pruneDeadBranches>true</pruneDeadBranches>
<daysToKeep>10</daysToKeep>
<numToKeep>10</numToKeep>
</orphanedItemStrategy>
<triggers>
<com.cloudbees.hudson.plugins.folder.computed.PeriodicFolderTrigger plugin="cloudbees-folder">
<spec>H H * * *</spec>
<interval>86400000</interval>
</com.cloudbees.hudson.plugins.folder.computed.PeriodicFolderTrigger>
</triggers>
<sources class="jenkins.branch.MultiBranchProject$BranchSourceList" plugin="branch-api">
<data>
<jenkins.branch.BranchSource>
<source class="com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSource" plugin="cloudbees-bitbucket-branch-source">
<id>1-1-1-1-1</id>
<repoOwner>SANDBOX</repoOwner>
<repository>test</repository>
<credentialsId>secret</credentialsId>
<traits/>
</source>
</jenkins.branch.BranchSource>
<jenkins.branch.BranchSource>
<source class="jenkins.plugins.git.GitSCMSource" plugin="git">
<id>1-1-1-1-1</id>
<remote>https://example.com/jonhndoe/keep-frontend.git</remote>
<credentialsId>secret</credentialsId>
<traits>
<jenkins.plugins.git.traits.BranchDiscoveryTrait/>
</traits>
</source>
</jenkins.branch.BranchSource>
<jenkins.branch.BranchSource>
<source class="org.jenkinsci.plugins.github_branch_source.GitHubSCMSource" plugin="github-branch-source">
<id>1-1-1-1-1</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>
</traits>
</source>
</jenkins.branch.BranchSource>
</data>
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</sources>
<factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
<scriptPath>Jenkinsfile</scriptPath>
</factory>
</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject>

View File

@ -0,0 +1,21 @@
name: 'demo-multibranch-multi-scm-full'
description: 'Workflow demo'
project-type: multibranch
periodic-folder-trigger: 1d
prune-dead-branches: True
number-to-keep: '10'
days-to-keep: '10'
scm:
- bitbucket:
repo-owner: 'SANDBOX'
repo: 'test'
credentials-id: 'secret'
- git:
url: 'https://example.com/jonhndoe/keep-frontend.git'
credentials-id: 'secret'
- github:
repo: 'foo'
repo-owner: 'johndoe'
credentials-id: 'secret'

View File

@ -0,0 +1,60 @@
<?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>1-1-1-1-1</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>
</traits>
</source>
</jenkins.branch.BranchSource>
</data>
<owner class="org.jenkinsci.plugins.pipeline.multibranch.defaults.PipelineMultiBranchDefaultsProject" reference="../.."/>
</sources>
<factory class="org.jenkinsci.plugins.pipeline.multibranch.defaults.PipelineBranchDefaultsProjectFactory">
<owner class="org.jenkinsci.plugins.pipeline.multibranch.defaults.PipelineMultiBranchDefaultsProject" reference="../.."/>
<scriptPath>Jenkinsfile</scriptPath>
</factory>
</org.jenkinsci.plugins.pipeline.multibranch.defaults.PipelineMultiBranchDefaultsProject>

View File

@ -0,0 +1,7 @@
name: 'demo-multibranch-defaults'
project-type: multibranch-defaults
scm:
- github:
repo: 'foo'
repo-owner: 'johndoe'
credentials-id: 'secret'

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject 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.workflow.multibranch.WorkflowMultiBranchProject" reference="../../.."/>
</hudson.model.AllView>
</views>
<viewsTabBar class="hudson.views.DefaultViewsTabBar"/>
<folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" 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.workflow.multibranch.WorkflowMultiBranchProject" 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="com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSource" plugin="cloudbees-bitbucket-branch-source">
<id>1-1-1-1-1</id>
<repoOwner>SANDBOX</repoOwner>
<repository>test</repository>
<credentialsId>secret</credentialsId>
<traits/>
</source>
</jenkins.branch.BranchSource>
</data>
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</sources>
<factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
<scriptPath>Jenkinsfile</scriptPath>
</factory>
</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject>

View File

@ -0,0 +1,7 @@
name: 'demo-multibranch-bitbucket-min'
project-type: multibranch
scm:
- bitbucket:
credentials-id: 'secret'
repo-owner: 'SANDBOX'
repo: 'test'

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject 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.workflow.multibranch.WorkflowMultiBranchProject" reference="../../.."/>
</hudson.model.AllView>
</views>
<viewsTabBar class="hudson.views.DefaultViewsTabBar"/>
<folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" 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.workflow.multibranch.WorkflowMultiBranchProject" 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="com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSource" plugin="cloudbees-bitbucket-branch-source">
<id>1-1-1-1-1</id>
<repoOwner>SANDBOX</repoOwner>
<repository>test</repository>
<traits/>
</source>
</jenkins.branch.BranchSource>
</data>
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</sources>
<factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
<scriptPath>Jenkinsfile</scriptPath>
</factory>
</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject>

View File

@ -0,0 +1,6 @@
name: 'demo-multibranch-bitbucket-min'
project-type: multibranch
scm:
- bitbucket:
repo-owner: 'SANDBOX'
repo: 'test'

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject 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.workflow.multibranch.WorkflowMultiBranchProject" reference="../../.."/>
</hudson.model.AllView>
</views>
<viewsTabBar class="hudson.views.DefaultViewsTabBar"/>
<folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" 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.workflow.multibranch.WorkflowMultiBranchProject" 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="jenkins.plugins.git.GitSCMSource" plugin="git">
<id>1-1-1-1-1</id>
<remote>https://example.com/jonhndoe/keep-frontend.git</remote>
<credentialsId>secret</credentialsId>
<traits>
<jenkins.plugins.git.traits.IgnoreOnPushNotificationTrait/>
</traits>
</source>
</jenkins.branch.BranchSource>
</data>
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</sources>
<factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
<scriptPath>Jenkinsfile</scriptPath>
</factory>
</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject>

View File

@ -0,0 +1,8 @@
name: 'demo-multibranch-git-min'
project-type: multibranch
scm:
- git:
url: 'https://example.com/jonhndoe/keep-frontend.git'
credentials-id: secret
discover-branches: false
ignore-on-push-notifications: true

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject 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.workflow.multibranch.WorkflowMultiBranchProject" reference="../../.."/>
</hudson.model.AllView>
</views>
<viewsTabBar class="hudson.views.DefaultViewsTabBar"/>
<folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" 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.workflow.multibranch.WorkflowMultiBranchProject" 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="jenkins.plugins.git.GitSCMSource" plugin="git">
<id>1-1-1-1-1</id>
<remote>https://example.com/jonhndoe/keep-frontend.git</remote>
<credentialsId/>
<traits>
<jenkins.plugins.git.traits.BranchDiscoveryTrait/>
</traits>
</source>
</jenkins.branch.BranchSource>
</data>
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</sources>
<factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
<scriptPath>Jenkinsfile</scriptPath>
</factory>
</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject>

View File

@ -0,0 +1,5 @@
name: 'demo-multibranch-git-min'
project-type: multibranch
scm:
- git:
url: 'https://example.com/jonhndoe/keep-frontend.git'

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject 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.workflow.multibranch.WorkflowMultiBranchProject" reference="../../.."/>
</hudson.model.AllView>
</views>
<viewsTabBar class="hudson.views.DefaultViewsTabBar"/>
<folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" 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.workflow.multibranch.WorkflowMultiBranchProject" 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>1-1-1-1-1</id>
<repoOwner>example-owner</repoOwner>
<repository>example-repo</repository>
<apiUri>http://example.org/github</apiUri>
<credentialsId>example-credential</credentialsId>
<traits>
<org.jenkinsci.plugins.github__branch__source.BranchDiscoveryTrait>
<strategyId>3</strategyId>
</org.jenkinsci.plugins.github__branch__source.BranchDiscoveryTrait>
<org.jenkinsci.plugins.github__branch__source.ForkPullRequestDiscoveryTrait>
<strategyId>3</strategyId>
<trust class="org.jenkinsci.plugins.github_branch_source.ForkPullRequestDiscoveryTrait$TrustEveryone"/>
</org.jenkinsci.plugins.github__branch__source.ForkPullRequestDiscoveryTrait>
<org.jenkinsci.plugins.github__branch__source.OriginPullRequestDiscoveryTrait>
<strategyId>3</strategyId>
</org.jenkinsci.plugins.github__branch__source.OriginPullRequestDiscoveryTrait>
</traits>
</source>
</jenkins.branch.BranchSource>
</data>
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</sources>
<factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
<scriptPath>Jenkinsfile</scriptPath>
</factory>
</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject>

View File

@ -0,0 +1,12 @@
name: scm-github-full
project-type: multibranch
scm:
- github:
api-uri: http://example.org/github
repo: example-repo
repo-owner: example-owner
credentials-id: example-credential
branch-discovery: all
discover-pr-forks-strategy: both
discover-pr-forks-trust: everyone
discover-pr-origin: both

View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject 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.workflow.multibranch.WorkflowMultiBranchProject" reference="../../.."/>
</hudson.model.AllView>
</views>
<viewsTabBar class="hudson.views.DefaultViewsTabBar"/>
<folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" 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.workflow.multibranch.WorkflowMultiBranchProject" 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>1-1-1-1-1</id>
<repoOwner>johndoe</repoOwner>
<repository>foo</repository>
<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>
</traits>
</source>
</jenkins.branch.BranchSource>
</data>
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</sources>
<factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
<scriptPath>Jenkinsfile</scriptPath>
</factory>
</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject>

View File

@ -0,0 +1,6 @@
name: 'demo-multibranch-github-min'
project-type: multibranch
scm:
- github:
repo: 'foo'
repo-owner: 'johndoe'

View File

@ -0,0 +1,27 @@
#
# Copyright (c) 2018 Sorin Sbarnea <ssbarnea@users.noreply.github.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tests import base
import mock
import os
from jenkins_jobs.modules import project_multibranch
@mock.patch('uuid.uuid4', mock.Mock(return_value='1-1-1-1-1'))
class TestCaseMultibranchPipeline(base.BaseScenariosTestCase):
fixtures_path = os.path.join(os.path.dirname(__file__), 'fixtures')
scenarios = base.get_scenarios(fixtures_path)
default_config_file = '/dev/null'
klass = project_multibranch.WorkflowMultiBranch