Feat: Add GitHub Organization job type

This adds a job type "githuborg", which creates multibranch pipelines
for all repos in the org that contain the specified Jenkinsfile.

Signed-off-by: Eric Ball <eball@linuxfoundation.org>
Change-Id: I148e2300f3b1ee148b51d25a2a805ed0b5a97862
This commit is contained in:
Eric Ball 2021-07-06 12:12:50 -07:00
parent 0ee4851331
commit a833d1fde6
No known key found for this signature in database
GPG Key ID: 120C6D8DD9D9BC8E
13 changed files with 919 additions and 0 deletions

View File

@ -0,0 +1,7 @@
.. _project_githuborg:
GitHub Organization Project
===========================
.. automodule:: project_githuborg
:members:

View File

@ -0,0 +1,438 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2021 The Linux Foundation
#
# 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 Github Organization project module handles creating Jenkins Github
Organization jobs, which are made up of multibranch pipelines for all
repositories containing the specified Jenkinsfile(s).
You may specify ``githuborg`` in the ``project-type`` attribute of
the :ref:`Job` definition.
Plugins required:
* :jenkins-plugins:`GitHub Branch Source Plugin <github-branch-source>`
:Job Parameters:
* **github-org** (`dict`): Refer to
:func:`github_org <github_org>` 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')
* **script-path** (`str`): Path to Jenkinsfile, relative to workspace.
(default 'Jenkinsfile')
Job examples:
.. literalinclude:: /../../tests/githuborg/fixtures/minimal.yaml
.. literalinclude:: /../../tests/githuborg/fixtures/githuborg-job-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 jenkins_jobs.modules.project_multibranch as multibranch
from jenkins_jobs.modules.scm import git_extensions
from jenkins_jobs.errors import InvalidAttributeError
logger = logging.getLogger(str(__name__))
class GithubOrganization(jenkins_jobs.modules.base.Base):
sequence = 0
jenkins_class = "jenkins.branch.OrganizationFolder"
def root_xml(self, data):
xml_parent = XML.Element(self.jenkins_class)
xml_parent.attrib["plugin"] = "branch-api"
XML.SubElement(xml_parent, "properties")
################
# Folder Views #
################
folderViews = XML.SubElement(
xml_parent,
"folderViews",
{"class": "jenkins.branch.OrganizationFolderViewHolder"},
)
XML.SubElement(folderViews, "owner", {"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"}
)
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]
##############
# Navigators #
##############
navigators = XML.SubElement(xml_parent, "navigators")
navigators_plugin = XML.SubElement(
navigators,
"org.jenkinsci.plugins.github__branch__source.GitHubSCMNavigator",
{"plugin": "github-branch-source"},
)
github_org(navigators_plugin, data.get("github-org"))
###########
# Factory #
###########
fopts_map = [("script-path", "scriptPath", "Jenkinsfile")]
project_factories = XML.SubElement(xml_parent, "projectFactories")
factory = XML.SubElement(
project_factories,
"org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProjectFactory",
{"plugin": "workflow-multibranch"},
)
helpers.convert_mapping_to_xml(factory, data, fopts_map, fail_required=False)
return xml_parent
def github_org(xml_parent, data):
r"""Configure GitHub Organization and SCM settings.
:arg str repo-owner: Specify the name of the GitHub Organization or
GitHub User Account. (required)
:arg str api-uri: The GitHub API uri for hosted / on-site GitHub. Must
first be configured in Global Configuration. (default GitHub)
:arg str branch-discovery: Discovers branches on the repository.
Valid options: no-pr, only-pr, all, false. (default 'no-pr')
:arg list build-strategies: Provides control over whether to build a branch
(or branch like things such as change requests and tags) whenever it is
discovered initially or a change from the previous revision has been
detected. (optional)
Refer to :func:`~build_strategies <project_multibranch.build_strategies>`.
:arg str credentials-id: Credentials used to scan branches and pull
requests, check out sources and mark commit statuses. (optional)
: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, false. (default 'merge-current')
:arg bool discover-tags: Discovers tags on the repository.
(default false)
:arg list head-pr-filter-behaviors: Definition of Filter Branch PR behaviors.
Requires the :jenkins-plugins:`SCM Filter Branch PR Plugin
<scm-filter-branch-pr>`. Refer to
:func:`~add_filter_branch_pr_behaviors <project_multibranch.add_filter_branch_pr_behaviors>`.
:arg str notification-context: Change the default GitHub check notification
context from "continuous-integration/jenkins/SUFFIX" to a custom text,
Requires the :jenkins-plugins:`Github Custom Notification Context SCM
Behaviour <github-scm-trait-notification-context>`.
:arg dict property-strategies: Provides control over how to build a branch
(like to disable SCM triggering or to override the pipeline durability)
(optional)
Refer to :func:`~property_strategies <project_multibranch.property_strategies>`.
:arg bool ssh-checkout: Checkout over SSH.
* **credentials** ('str'): Credentials to use for
checkout of the repo over ssh.
:extensions:
* **clean** (`dict`)
* **after** (`bool`) - Clean the workspace after checkout
* **before** (`bool`) - Clean the workspace before checkout
* **depth** (`int`) - Set shallow clone depth (default 1)
* **disable-pr-notifications** (`bool`) - Disable default github status
notifications on pull requests (default false) (Requires the
:jenkins-plugins:`GitHub Branch Source Plugin
<disable-github-multibranch-status>`.)
* **do-not-fetch-tags** (`bool`) - Perform a clone without tags
(default false)
* **lfs-pull** (`bool`) - Call git lfs pull after checkout
(default false)
* **prune** (`bool`) - Prune remote branches (default false)
* **refspecs** (`list(str)`): Which refspecs to fetch.
* **shallow-clone** (`bool`) - Perform shallow clone (default false)
* **sparse-checkout** (dict)
* **paths** (list) - List of paths to sparse checkout. (optional)
* **submodule** (`dict`)
* **disable** (`bool`) - By disabling support for submodules you
can still keep using basic git plugin functionality and just have
Jenkins to ignore submodules completely as if they didn't exist.
* **recursive** (`bool`) - Retrieve all submodules recursively
(uses '--recursive' option which requires git>=1.6.5)
* **tracking** (`bool`) - Retrieve the tip of the configured
branch in .gitmodules (Uses '\-\-remote' option which requires
git>=1.8.2)
* **parent-credentials** (`bool`) - Use credentials from default
remote of parent repository (default false).
* **reference-repo** (`str`) - Path of the reference repo to use
during clone (optional)
* **timeout** (`int`) - Specify a timeout (in minutes) for
submodules operations (default 10).
* **timeout** (`str`) - Timeout for git commands in minutes (optional)
* **use-author** (`bool`): Use author rather than committer in Jenkin's
build changeset (default false)
* **wipe-workspace** (`bool`) - Wipe out workspace before build
(default true)
Job examples:
.. literalinclude:: /../../tests/githuborg/fixtures/minimal.yaml
.. literalinclude:: /../../tests/githuborg/fixtures/github-org-full.yaml
"""
github_path = "org.jenkinsci.plugins.github_branch_source"
github_path_dscore = "org.jenkinsci.plugins.github__branch__source"
mapping = [("repo-owner", "repoOwner", None)]
helpers.convert_mapping_to_xml(xml_parent, data, mapping, fail_required=True)
mapping_optional = [
("api-uri", "apiUri", None),
("credentials-id", "credentialsId", None),
]
helpers.convert_mapping_to_xml(
xml_parent, data, mapping_optional, fail_required=False
)
traits = XML.SubElement(xml_parent, "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("ssh-checkout", None):
cossh = XML.SubElement(
traits, "".join([github_path_dscore, ".SSHCheckoutTrait"])
)
if not isinstance(data.get("ssh-checkout"), bool):
cossh_credentials = [("credentials", "credentialsId", "")]
helpers.convert_mapping_to_xml(
cossh, data.get("ssh-checkout"), cossh_credentials, fail_required=True
)
if data.get("discover-tags", False):
XML.SubElement(traits, "".join([github_path_dscore, ".TagDiscoveryTrait"]))
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")
if dpro_strategy:
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()
)
dpro_mapping = [
("discover-pr-origin", "strategyId", "merge-current", dpro_strategy_map)
]
helpers.convert_mapping_to_xml(dpro, data, dpro_mapping, fail_required=True)
if data.get("head-filter-regex", None):
rshf = XML.SubElement(traits, "jenkins.scm.impl.trait.RegexSCMHeadFilterTrait")
XML.SubElement(rshf, "regex").text = data.get("head-filter-regex")
if data.get("head-pr-filter-behaviors", None):
multibranch.add_filter_branch_pr_behaviors(
traits, data.get("head-pr-filter-behaviors")
)
if data.get("property-strategies", None):
multibranch.property_strategies(xml_parent, data)
if data.get("build-strategies", None):
multibranch.build_strategies(xml_parent, data)
if data.get("notification-context", None):
rshf = XML.SubElement(
traits,
"org.jenkinsci.plugins.githubScmTraitNotificationContext."
"NotificationContextTrait",
)
XML.SubElement(rshf, "contextLabel").text = data.get("notification-context")
XML.SubElement(rshf, "typeSuffix").text = "true"
# handle the default git extensions like:
# - clean
# - shallow-clone
# - timeout
# - do-not-fetch-tags
# - submodule
# - prune
# - wipe-workspace
# - use-author
# - lfs-pull
git_extensions(traits, data)
if data.get("refspecs"):
refspec_trait = XML.SubElement(
traits,
"jenkins.plugins.git.traits.RefSpecsSCMSourceTrait",
{"plugin": "git"},
)
templates = XML.SubElement(refspec_trait, "templates")
refspecs = data.get("refspecs")
for refspec in refspecs:
e = XML.SubElement(
templates,
(
"jenkins.plugins.git.traits"
".RefSpecsSCMSourceTrait_-RefSpecTemplate"
),
)
XML.SubElement(e, "value").text = refspec
# github-only extensions
disable_github_status_path_dscore = (
"com.adobe.jenkins.disable__github__multibranch__status"
)
if data.get("disable-pr-notifications", False):
XML.SubElement(
traits,
"".join([disable_github_status_path_dscore, ".DisableStatusUpdateTrait"]),
{"plugin": "disable-github-multibranch-status"},
)

View File

@ -1726,6 +1726,7 @@ class SCM(jenkins_jobs.modules.base.Base):
# multibranch-pipeline scm implementation is incompatible with SCM
if data.get("project-type") in [
"githuborg",
"multibranch",
"multibranch-defaults",
"pipeline",

View File

@ -56,6 +56,7 @@ jenkins_jobs.projects =
flow=jenkins_jobs.modules.project_flow:Flow
folder=jenkins_jobs.modules.project_folder:Folder
freestyle=jenkins_jobs.modules.project_freestyle:Freestyle
githuborg=jenkins_jobs.modules.project_githuborg:GithubOrganization
matrix=jenkins_jobs.modules.project_matrix:Matrix
maven=jenkins_jobs.modules.project_maven:Maven
multibranch=jenkins_jobs.modules.project_multibranch:WorkflowMultiBranch

View File

@ -41,6 +41,7 @@ import jenkins_jobs.local_yaml as yaml
from jenkins_jobs.alphanum import AlphanumSort
from jenkins_jobs.modules import project_externaljob
from jenkins_jobs.modules import project_flow
from jenkins_jobs.modules import project_githuborg
from jenkins_jobs.modules import project_matrix
from jenkins_jobs.modules import project_maven
from jenkins_jobs.modules import project_multibranch
@ -224,6 +225,8 @@ class BaseScenariosTestCase(testscenarios.TestWithScenarios, BaseTestCase):
project = project_matrix.Matrix(registry)
elif yaml_content["project-type"] == "flow":
project = project_flow.Flow(registry)
elif yaml_content["project-type"] == "githuborg":
project = project_githuborg.GithubOrganization(registry)
elif yaml_content["project-type"] == "multijob":
project = project_multijob.MultiJob(registry)
elif yaml_content["project-type"] == "multibranch":

View File

View File

@ -0,0 +1,229 @@
<?xml version="1.0" encoding="utf-8"?>
<jenkins.branch.OrganizationFolder plugin="branch-api">
<properties/>
<folderViews class="jenkins.branch.OrganizationFolderViewHolder">
<owner 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">
<owner class="jenkins.branch.OrganizationFolder" 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/>
<navigators>
<org.jenkinsci.plugins.github__branch__source.GitHubSCMNavigator plugin="github-branch-source">
<repoOwner>example-owner</repoOwner>
<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.SSHCheckoutTrait>
<credentialsId>ssh_secret</credentialsId>
</org.jenkinsci.plugins.github__branch__source.SSHCheckoutTrait>
<org.jenkinsci.plugins.github__branch__source.TagDiscoveryTrait/>
<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>
<jenkins.scm.impl.trait.RegexSCMHeadFilterTrait>
<regex>(.*/master|.*/release/.*)</regex>
</jenkins.scm.impl.trait.RegexSCMHeadFilterTrait>
<net.gleske.scmfilter.impl.trait.RegexSCMHeadFilterTrait plugin="scm-filter-branch-pr">
<regex>foo/.*</regex>
<tagRegex>20\..*</tagRegex>
</net.gleske.scmfilter.impl.trait.RegexSCMHeadFilterTrait>
<net.gleske.scmfilter.impl.trait.WildcardSCMHeadFilterTrait plugin="scm-filter-branch-pr">
<includes>foo*</includes>
<excludes>bar*</excludes>
<tagIncludes>qaz*</tagIncludes>
<tagExcludes>*baz</tagExcludes>
</net.gleske.scmfilter.impl.trait.WildcardSCMHeadFilterTrait>
<net.gleske.scmfilter.impl.trait.RegexSCMOriginFilterTrait plugin="scm-filter-branch-pr">
<regex>(foo/.*|bar/.*)</regex>
<tagRegex>1\..*</tagRegex>
</net.gleske.scmfilter.impl.trait.RegexSCMOriginFilterTrait>
<net.gleske.scmfilter.impl.trait.WildcardSCMOriginFilterTrait plugin="scm-filter-branch-pr">
<includes>qaz*</includes>
<excludes>baz*</excludes>
<tagIncludes>bar*</tagIncludes>
<tagExcludes>*qaz</tagExcludes>
</net.gleske.scmfilter.impl.trait.WildcardSCMOriginFilterTrait>
<org.jenkinsci.plugins.githubScmTraitNotificationContext.NotificationContextTrait>
<contextLabel>jenkins.example.com/my_context</contextLabel>
<typeSuffix>true</typeSuffix>
</org.jenkinsci.plugins.githubScmTraitNotificationContext.NotificationContextTrait>
<jenkins.plugins.git.traits.CleanAfterCheckoutTrait>
<extension class="hudson.plugins.git.extensions.impl.CleanCheckout"/>
</jenkins.plugins.git.traits.CleanAfterCheckoutTrait>
<jenkins.plugins.git.traits.CleanBeforeCheckoutTrait>
<extension class="hudson.plugins.git.extensions.impl.CleanBeforeCheckout"/>
</jenkins.plugins.git.traits.CleanBeforeCheckoutTrait>
<jenkins.plugins.git.traits.UserIdentityTrait>
<extension class="hudson.plugins.git.extensions.impl.UserIdentity">
<email>no-reply@ci.example.com</email>
</extension>
</jenkins.plugins.git.traits.UserIdentityTrait>
<jenkins.plugins.git.traits.CloneOptionTrait>
<extension class="hudson.plugins.git.extensions.impl.CloneOption">
<shallow>true</shallow>
<depth>3</depth>
<noTags>true</noTags>
<timeout>100</timeout>
</extension>
</jenkins.plugins.git.traits.CloneOptionTrait>
<com.cloudbees.jenkins.plugins.bitbucket.notifications.SkipNotificationsTrait/>
<jenkins.plugins.git.traits.SparseCheckoutPathsTrait>
<extension class="hudson.plugins.git.extensions.impl.SparseCheckoutPaths">
<sparseCheckoutPaths>
<hudson.plugins.git.extensions.impl.SparseCheckoutPath>
<path>path1</path>
</hudson.plugins.git.extensions.impl.SparseCheckoutPath>
<hudson.plugins.git.extensions.impl.SparseCheckoutPath>
<path>path2</path>
</hudson.plugins.git.extensions.impl.SparseCheckoutPath>
<hudson.plugins.git.extensions.impl.SparseCheckoutPath>
<path>path3</path>
</hudson.plugins.git.extensions.impl.SparseCheckoutPath>
</sparseCheckoutPaths>
</extension>
</jenkins.plugins.git.traits.SparseCheckoutPathsTrait>
<jenkins.plugins.git.traits.SubmoduleOptionTrait>
<extension class="hudson.plugins.git.extensions.impl.SubmoduleOption">
<disableSubmodules>false</disableSubmodules>
<recursiveSubmodules>true</recursiveSubmodules>
<trackingSubmodules>false</trackingSubmodules>
<parentCredentials>true</parentCredentials>
<reference/>
<timeout>100</timeout>
<threads>1</threads>
</extension>
</jenkins.plugins.git.traits.SubmoduleOptionTrait>
<jenkins.plugins.git.traits.CheckoutOptionTrait>
<extension class="hudson.plugins.git.extensions.impl.CheckoutOption">
<timeout>100</timeout>
</extension>
</jenkins.plugins.git.traits.CheckoutOptionTrait>
<jenkins.plugins.git.traits.PruneStaleBranchTrait>
<extension class="hudson.plugins.git.extensions.impl.PruneStaleBranch"/>
</jenkins.plugins.git.traits.PruneStaleBranchTrait>
<jenkins.plugins.git.traits.WipeWorkspaceTrait>
<extension class="hudson.plugins.git.extensions.impl.WipeWorkspace"/>
</jenkins.plugins.git.traits.WipeWorkspaceTrait>
<jenkins.plugins.git.traits.AuthorInChangelogTrait>
<extension class="hudson.plugins.git.extensions.impl.AuthorInChangelog"/>
</jenkins.plugins.git.traits.AuthorInChangelogTrait>
<jenkins.plugins.git.traits.GitLFSPullTrait>
<extension class="hudson.plugins.git.extensions.impl.GitLFSPull"/>
</jenkins.plugins.git.traits.GitLFSPullTrait>
<jenkins.plugins.git.traits.RefSpecsSCMSourceTrait plugin="git">
<templates>
<jenkins.plugins.git.traits.RefSpecsSCMSourceTrait_-RefSpecTemplate>
<value>+refs/heads/*:refs/remotes/@{remote}/*</value>
</jenkins.plugins.git.traits.RefSpecsSCMSourceTrait_-RefSpecTemplate>
</templates>
</jenkins.plugins.git.traits.RefSpecsSCMSourceTrait>
<com.adobe.jenkins.disable__github__multibranch__status.DisableStatusUpdateTrait plugin="disable-github-multibranch-status"/>
</traits>
<strategy class="jenkins.branch.DefaultBranchPropertyStrategy">
<properties class="java.util.Arrays$ArrayList">
<a class="jenkins.branch.BranchProperty-array">
<jenkins.branch.NoTriggerBranchProperty/>
<org.jenkinsci.plugins.workflow.multibranch.DurabilityHintBranchProperty plugin="workflow-multibranch">
<hint>MAX_SURVIVABILITY</hint>
</org.jenkinsci.plugins.workflow.multibranch.DurabilityHintBranchProperty>
<com.adobe.jenkins.github__pr__comment__build.TriggerPRCommentBranchProperty plugin="github-pr-comment-build">
<commentBody>Ci build!</commentBody>
</com.adobe.jenkins.github__pr__comment__build.TriggerPRCommentBranchProperty>
<com.adobe.jenkins.github__pr__comment__build.TriggerPRReviewBranchProperty plugin="github-pr-comment-build"/>
<com.adobe.jenkins.github__pr__comment__build.TriggerPRUpdateBranchProperty plugin="github-pr-comment-build"/>
</a>
</properties>
</strategy>
<buildStrategies>
<jenkins.branch.buildstrategies.basic.AllBranchBuildStrategyImpl plugin="basic-branch-build-strategies">
<strategies>
<jenkins.branch.buildstrategies.basic.BranchBuildStrategyImpl plugin="basic-branch-build-strategies"/>
<jenkins.branch.buildstrategies.basic.SkipInitialBuildOnFirstBranchIndexing plugin="basic-branch-build-strategies"/>
</strategies>
</jenkins.branch.buildstrategies.basic.AllBranchBuildStrategyImpl>
<jenkins.branch.buildstrategies.basic.AnyBranchBuildStrategyImpl plugin="basic-branch-build-strategies">
<strategies>
<jenkins.branch.buildstrategies.basic.ChangeRequestBuildStrategyImpl plugin="basic-branch-build-strategies">
<ignoreTargetOnlyChanges>false</ignoreTargetOnlyChanges>
</jenkins.branch.buildstrategies.basic.ChangeRequestBuildStrategyImpl>
<jenkins.branch.buildstrategies.basic.TagBuildStrategyImpl plugin="basic-branch-build-strategies">
<atMostMillis>-1</atMostMillis>
<atLeastMillis>-1</atLeastMillis>
</jenkins.branch.buildstrategies.basic.TagBuildStrategyImpl>
</strategies>
</jenkins.branch.buildstrategies.basic.AnyBranchBuildStrategyImpl>
<jenkins.branch.buildstrategies.basic.TagBuildStrategyImpl plugin="basic-branch-build-strategies">
<atMostMillis>86400000</atMostMillis>
<atLeastMillis>604800000</atLeastMillis>
</jenkins.branch.buildstrategies.basic.TagBuildStrategyImpl>
<jenkins.branch.buildstrategies.basic.TagBuildStrategyImpl plugin="basic-branch-build-strategies">
<atMostMillis>-1</atMostMillis>
<atLeastMillis>-1</atLeastMillis>
</jenkins.branch.buildstrategies.basic.TagBuildStrategyImpl>
<jenkins.branch.buildstrategies.basic.ChangeRequestBuildStrategyImpl plugin="basic-branch-build-strategies">
<ignoreTargetOnlyChanges>true</ignoreTargetOnlyChanges>
</jenkins.branch.buildstrategies.basic.ChangeRequestBuildStrategyImpl>
<jenkins.branch.buildstrategies.basic.ChangeRequestBuildStrategyImpl plugin="basic-branch-build-strategies">
<ignoreTargetOnlyChanges>false</ignoreTargetOnlyChanges>
</jenkins.branch.buildstrategies.basic.ChangeRequestBuildStrategyImpl>
<jenkins.branch.buildstrategies.basic.BranchBuildStrategyImpl plugin="basic-branch-build-strategies"/>
<jenkins.branch.buildstrategies.basic.SkipInitialBuildOnFirstBranchIndexing plugin="basic-branch-build-strategies"/>
<jenkins.branch.buildstrategies.basic.NamedBranchBuildStrategyImpl plugin="basic-branch-build-strategies">
<filters>
<jenkins.branch.buildstrategies.basic.NamedBranchBuildStrategyImpl_-ExactNameFilter>
<name>test</name>
<caseSensitive>true</caseSensitive>
</jenkins.branch.buildstrategies.basic.NamedBranchBuildStrategyImpl_-ExactNameFilter>
<jenkins.branch.buildstrategies.basic.NamedBranchBuildStrategyImpl_-RegexNameFilter>
<regex>test.*$</regex>
<caseSensitive>true</caseSensitive>
</jenkins.branch.buildstrategies.basic.NamedBranchBuildStrategyImpl_-RegexNameFilter>
<jenkins.branch.buildstrategies.basic.NamedBranchBuildStrategyImpl_-WildcardsNameFilter>
<includes>testinclude</includes>
<excludes>testexclude</excludes>
</jenkins.branch.buildstrategies.basic.NamedBranchBuildStrategyImpl_-WildcardsNameFilter>
</filters>
</jenkins.branch.buildstrategies.basic.NamedBranchBuildStrategyImpl>
<jenkins.branch.buildstrategies.basic.NamedBranchBuildStrategyImpl plugin="basic-branch-build-strategies">
<filters>
<jenkins.branch.buildstrategies.basic.NamedBranchBuildStrategyImpl_-ExactNameFilter>
<name/>
<caseSensitive>false</caseSensitive>
</jenkins.branch.buildstrategies.basic.NamedBranchBuildStrategyImpl_-ExactNameFilter>
<jenkins.branch.buildstrategies.basic.NamedBranchBuildStrategyImpl_-RegexNameFilter>
<regex>^.*$</regex>
<caseSensitive>false</caseSensitive>
</jenkins.branch.buildstrategies.basic.NamedBranchBuildStrategyImpl_-RegexNameFilter>
<jenkins.branch.buildstrategies.basic.NamedBranchBuildStrategyImpl_-WildcardsNameFilter>
<includes>*</includes>
<excludes/>
</jenkins.branch.buildstrategies.basic.NamedBranchBuildStrategyImpl_-WildcardsNameFilter>
</filters>
</jenkins.branch.buildstrategies.basic.NamedBranchBuildStrategyImpl>
</buildStrategies>
</org.jenkinsci.plugins.github__branch__source.GitHubSCMNavigator>
</navigators>
<projectFactories>
<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProjectFactory plugin="workflow-multibranch">
<scriptPath>Jenkinsfile</scriptPath>
</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProjectFactory>
</projectFactories>
</jenkins.branch.OrganizationFolder>

View File

@ -0,0 +1,101 @@
name: github-org-full
project-type: githuborg
github-org:
api-uri: http://example.org/github
ssh-checkout:
credentials: 'ssh_secret'
repo-owner: example-owner
credentials-id: example-credential
branch-discovery: all
head-filter-regex: "(.*/master|.*/release/.*)"
head-pr-filter-behaviors:
head-pr-destined-regex:
branch-regexp: "foo/.*"
tag-regexp: "20\\..*"
head-pr-destined-wildcard:
branch-includes: "foo*"
tag-includes: "qaz*"
branch-excludes: "bar*"
tag-excludes: "*baz"
head-pr-originated-regex:
branch-regexp: "(foo/.*|bar/.*)"
tag-regexp: "1\\..*"
head-pr-originated-wildcard:
branch-includes: "qaz*"
tag-includes: "bar*"
branch-excludes: "baz*"
tag-excludes: "*qaz"
discover-pr-forks-strategy: both
discover-pr-forks-trust: everyone
discover-pr-origin: both
discover-tags: true
notification-context: 'jenkins.example.com/my_context'
property-strategies:
all-branches:
- suppress-scm-triggering: true
- pipeline-branch-durability-override: max-survivability
- trigger-build-on-pr-comment: "Ci build!"
- trigger-build-on-pr-review: true
- trigger-build-on-pr-update: true
build-strategies:
- all-strategies-match:
strategies:
- regular-branches: true
- skip-initial-build: true
- any-strategies-match:
strategies:
- change-request: {}
- tags: {}
- tags:
ignore-tags-newer-than: 1
ignore-tags-older-than: 7
- tags: {}
- change-request:
ignore-target-only-changes: true
- change-request: {}
- regular-branches: true
- skip-initial-build: true
- named-branches:
- exact-name:
name: 'test'
case-sensitive: true
- regex-name:
regex: 'test.*$'
case-sensitive: true
- wildcards-name:
excludes: 'testexclude'
includes: 'testinclude'
- named-branches:
- exact-name: {}
- regex-name: {}
- wildcards-name: {}
clean:
after: true
before: true
committer:
user: CI System
email: no-reply@ci.example.com
prune: true
local-branch: true
sparse-checkout:
paths:
- "path1"
- "path2"
- "path3"
shallow-clone: true
depth: 3
do-not-fetch-tags: true
disable-pr-notifications: true
refspecs:
- '+refs/heads/*:refs/remotes/@{remote}/*'
submodule:
disable: false
recursive: true
parent-credentials: true
timeout: 100
threads: 1
timeout: "100"
skip-notifications: true
use-author: true
wipe-workspace: true
lfs-pull: true

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<jenkins.branch.OrganizationFolder plugin="branch-api">
<properties/>
<folderViews class="jenkins.branch.OrganizationFolderViewHolder">
<owner 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">
<owner class="jenkins.branch.OrganizationFolder" reference="../.."/>
</icon>
<orphanedItemStrategy class="com.cloudbees.hudson.plugins.folder.computed.DefaultOrphanedItemStrategy" plugin="cloudbees-folder">
<pruneDeadBranches>false</pruneDeadBranches>
<daysToKeep>90</daysToKeep>
<numToKeep>10</numToKeep>
</orphanedItemStrategy>
<triggers>
<com.cloudbees.hudson.plugins.folder.computed.PeriodicFolderTrigger plugin="cloudbees-folder">
<spec>H * * * *</spec>
<interval>7200000</interval>
</com.cloudbees.hudson.plugins.folder.computed.PeriodicFolderTrigger>
</triggers>
<navigators>
<org.jenkinsci.plugins.github__branch__source.GitHubSCMNavigator plugin="github-branch-source">
<repoOwner>example-owner</repoOwner>
<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>
</org.jenkinsci.plugins.github__branch__source.GitHubSCMNavigator>
</navigators>
<projectFactories>
<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProjectFactory plugin="workflow-multibranch">
<scriptPath>some.Jenkinsfile</scriptPath>
</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProjectFactory>
</projectFactories>
</jenkins.branch.OrganizationFolder>

View File

@ -0,0 +1,12 @@
name: githuborg-job-full
project-type: githuborg
project: example-project
periodic-folder-trigger: 2h
prune-dead-branches: false
number-to-keep: 10
days-to-keep: 90
script-path: some.Jenkinsfile
github-org:
repo-owner: example-owner

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<jenkins.branch.OrganizationFolder plugin="branch-api">
<properties/>
<folderViews class="jenkins.branch.OrganizationFolderViewHolder">
<owner 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">
<owner class="jenkins.branch.OrganizationFolder" 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/>
<navigators>
<org.jenkinsci.plugins.github__branch__source.GitHubSCMNavigator plugin="github-branch-source">
<repoOwner>example-owner</repoOwner>
<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>
</org.jenkinsci.plugins.github__branch__source.GitHubSCMNavigator>
</navigators>
<projectFactories>
<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProjectFactory plugin="workflow-multibranch">
<scriptPath>Jenkinsfile</scriptPath>
</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProjectFactory>
</projectFactories>
</jenkins.branch.OrganizationFolder>

View File

@ -0,0 +1,5 @@
name: github-org-minimal
project-type: githuborg
project: example-project
github-org:
repo-owner: example-owner

View File

@ -0,0 +1,25 @@
#
# Copyright (c) 2021 The Linux Foundation
#
# 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 os
from jenkins_jobs.modules import project_githuborg
class TestCaseGithubOrganization(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_githuborg.GithubOrganization