Merge "Don't match branch protection rule patterns locally"

This commit is contained in:
Zuul 2020-09-15 07:38:19 +00:00 committed by Gerrit Code Review
commit fd519765e6
6 changed files with 51 additions and 12 deletions

View File

@ -32,7 +32,6 @@ paho-mqtt
cherrypy cherrypy
ws4py ws4py
routes routes
pathspec
jsonpath-rw jsonpath-rw
urllib3!=1.25.4,!=1.25.5 # https://github.com/urllib3/urllib3/pull/1684 urllib3!=1.25.4,!=1.25.5 # https://github.com/urllib3/urllib3/pull/1684
cheroot!=8.1.*,!=8.2.*,!=8.3.0 # https://github.com/cherrypy/cheroot/issues/263 cheroot!=8.1.*,!=8.2.*,!=8.3.0 # https://github.com/cherrypy/cheroot/issues/263

View File

@ -26,11 +26,28 @@ class FakePageInfo(ObjectType):
return False return False
class FakeMatchingRef(ObjectType):
name = String()
def resolve_name(parent, info):
return parent
class FakeMatchingRefs(ObjectType):
nodes = List(FakeMatchingRef)
def resolve_nodes(parent, info):
# To simplify tests just return the pattern and a bogus ref that should
# not disturb zuul.
return [parent.pattern, 'bogus-ref']
class FakeBranchProtectionRule(ObjectType): class FakeBranchProtectionRule(ObjectType):
pattern = String() pattern = String()
requiredStatusCheckContexts = List(String) requiredStatusCheckContexts = List(String)
requiresApprovingReviews = Boolean() requiresApprovingReviews = Boolean()
requiresCodeOwnerReviews = Boolean() requiresCodeOwnerReviews = Boolean()
matchingRefs = Field(FakeMatchingRefs, first=Int())
def resolve_pattern(parent, info): def resolve_pattern(parent, info):
return parent.pattern return parent.pattern
@ -44,6 +61,9 @@ class FakeBranchProtectionRule(ObjectType):
def resolve_requiresCodeOwnerReviews(parent, info): def resolve_requiresCodeOwnerReviews(parent, info):
return parent.require_codeowners_review return parent.require_codeowners_review
def resolve_matchingRefs(parent, info, first=None):
return parent
class FakeBranchProtectionRules(ObjectType): class FakeBranchProtectionRules(ObjectType):
nodes = List(FakeBranchProtectionRule) nodes = List(FakeBranchProtectionRule)

View File

@ -1633,7 +1633,8 @@ class GithubConnection(BaseConnection):
# For performance reasons fetch all needed data for canMerge upfront # For performance reasons fetch all needed data for canMerge upfront
# using a single graphql call. # using a single graphql call.
canmerge_data = self.graphql_client.fetch_canmerge(github, change) canmerge_data = self.graphql_client.fetch_canmerge(
github, change, zuul_event_id=event)
# If the PR is a draft it cannot be merged. # If the PR is a draft it cannot be merged.
if canmerge_data.get('isDraft', False): if canmerge_data.get('isDraft', False):

View File

@ -13,9 +13,10 @@
# under the License. # under the License.
import logging import logging
import pathspec
from pkg_resources import resource_string from pkg_resources import resource_string
from zuul.lib.logutil import get_annotated_logger
def nested_get(d, *keys, default=None): def nested_get(d, *keys, default=None):
temp = d temp = d
@ -70,7 +71,8 @@ class GraphQLClient:
response = github.session.post(self.url, json=query) response = github.session.post(self.url, json=query)
return response.json() return response.json()
def fetch_canmerge(self, github, change): def fetch_canmerge(self, github, change, zuul_event_id=None):
log = get_annotated_logger(self.log, zuul_event_id)
owner, repo = change.project.name.split('/') owner, repo = change.project.name.split('/')
data = self._fetch_canmerge(github, owner, repo, change.number, data = self._fetch_canmerge(github, owner, repo, change.number,
@ -81,14 +83,21 @@ class GraphQLClient:
# Find corresponding rule to our branch # Find corresponding rule to our branch
rules = nested_get(repository, 'branchProtectionRules', 'nodes', rules = nested_get(repository, 'branchProtectionRules', 'nodes',
default=[]) default=[])
matching_rule = None
for rule in rules: # Filter branch protection rules for the one matching the change.
pattern = pathspec.patterns.GitWildMatchPattern( matching_rules = [
rule.get('pattern')) rule for rule in rules
match = pathspec.match_files([pattern], [change.branch]) for ref in nested_get(rule, 'matchingRefs', 'nodes', default=[])
if match: if ref.get('name') == change.branch
matching_rule = rule ]
break if len(matching_rules) > 1:
log.warn('More than one branch protection rules match change %s',
change)
return result
elif len(matching_rules) == 1:
matching_rule = matching_rules[0]
else:
matching_rule = None
# If there is a matching rule, get required status checks # If there is a matching rule, get required status checks
if matching_rule: if matching_rule:

View File

@ -11,6 +11,11 @@ query canMergeData(
requiredStatusCheckContexts requiredStatusCheckContexts
requiresApprovingReviews requiresApprovingReviews
requiresCodeOwnerReviews requiresCodeOwnerReviews
matchingRefs(first: 100) {
nodes {
name
}
}
} }
} }
pullRequest(number: $pull) { pullRequest(number: $pull) {

View File

@ -11,6 +11,11 @@ query canMergeData(
requiredStatusCheckContexts requiredStatusCheckContexts
requiresApprovingReviews requiresApprovingReviews
requiresCodeOwnerReviews requiresCodeOwnerReviews
matchingRefs(first: 100) {
nodes {
name
}
}
} }
} }
pullRequest(number: $pull) { pullRequest(number: $pull) {