Migrate create_new_branch to toddler in scm_request_processor

The method is migrated from fedscm_admin to scm_request_processor.
Now we need to continue with writing test for scm_request_processor.
This commit is contained in:
Michal Konečný 2022-03-14 17:13:03 +01:00
parent e94e1e7162
commit 0ec16b0195
2 changed files with 91 additions and 125 deletions

View file

@ -101,6 +101,10 @@ dist_git_token = "private random string to change"
# This is the same format as used by the distgit_bugzilla_sync cron/app
email_overrides_file = "/path/to/email_overrides.toml"
# Path to temporary directory
# Will be used for creating temporary files and directories
temp_dir = "path/to/temporary/folder"
[consumer_config.default.pdc_config]
# Configuration to talk to PDC, as understood by pdc-client.
server = "https://pdc.fedoraproject.org/rest_api/v1/"

View file

@ -6,14 +6,16 @@ https://pagure.io/releng/fedora-scm-requests/issues.
Authors: Michal Konecny <mkonecny@redhat.com>
"""
import fnmatch
import logging
import re
from tempfile import TemporaryDirectory
import arrow
from pagure_messages.issue_schema import IssueNewV1
from toddlers.base import ToddlerBase
from toddlers.utils import bugzilla_system, fedora_account, pagure, pdc
from toddlers.utils import bugzilla_system, fedora_account, pagure, pdc, git
from toddlers.exceptions import ValidationError
# Regex for branch name validation
@ -67,6 +69,9 @@ class SCMRequestProcessor(ToddlerBase):
# Pagure object connected to dist-git
dist_git = None
# Path to temporary dir
temp_dir = None
def accepts_topic(self, topic: str) -> bool:
"""Returns a boolean whether this toddler is interested in messages
from this specific topic.
@ -113,6 +118,7 @@ class SCMRequestProcessor(ToddlerBase):
self.monitoring_choices = config.get("monitoring_choices")
self.pagure_namespace_to_component = config.get("pagure_namespace_to_component")
self.pagure_namespace_to_product = config.get("pagure_namespace_to_product")
self.temp_dir = config.get("temp_dir")
_log.info("Setting up PDC client")
pdc.set_pdc(config)
@ -518,18 +524,19 @@ class SCMRequestProcessor(ToddlerBase):
)
return
if create_git_branch:
assert_git_repo_initialized_remotely(namespace, repo)
branch_name = issue_body_json['branch'].strip()
if is_epel(branch_name) and not valid_epel_package(repo, branch_name):
if not force:
prompt_to_close_bad_ticket(issue_json, INVALID_EPEL_ERROR)
return
if re.match(EPEL_REGEX, branch_name) and not self.valid_epel_package(repo, branch_name):
self.pagure_io.close_issue(
issue["id"],
namespace=PROJECT_NAMESPACE,
message=INVALID_EPEL_ERROR,
reason="Invalid"
)
return
# Pagure uses plural names for namespaces, but PDC does not use the
# plural version for branch types
branch_type = pdc.component_type_to_singular(namespace)
click.echo('- Checking if {0} already exists in PDC.'.format(branch_name))
branch_type = namespace.strip().rstrip('s')
_log.info('- Checking if {0} already exists in PDC.'.format(branch_name))
pdc_branch = pdc.get_branch(repo, branch_name, branch_type)
if pdc_branch:
ticket_text = \
@ -540,107 +547,84 @@ class SCMRequestProcessor(ToddlerBase):
"``git checkout -b <branch_name> && git push -u origin <branch_name>``.\n" \
"``<branch_name>`` is the name of the branch you requested. \n" \
"You only need to do this once and you can then use fedpkg as you normally do."
prompt_to_close_bad_ticket(
issue_json, ticket_text)
self.pagure_io.close_issue(
issue["id"],
namespace=PROJECT_NAMESPACE,
message=ticket_text,
reason="Invalid"
)
return
issue_id = issue_json['id']
issue_title = issue_json['title'].strip()
issue_owner = issue_json['user']['name']
issue_ui_url = pagure.get_pagure_issue_url(issue_id)
issue_id = issue['id']
issue_title = issue['title'].strip()
issue_owner = issue['user']['name']
issue_ui_url = issue["full_url"]
# Check if the branch requestor is one of the maintainers or part of the groups
click.echo('- Checking if {0} is one of the maintainers of the package'.format(issue_owner))
if force:
msg = ' WARNING: Checking of maintainers is skipped'
click.secho(msg, fg='yellow')
else:
# Get the list of maintainers of the package
maintainers = set(contributors['users']['admin']) | \
set(contributors['users']['commit']) | \
set(u['user']
for u in contributors['users']['collaborators']
if fnmatch.fnmatch(branch_name, u['branches']))
_log.info('- Checking if {0} is one of the maintainers of the package'.format(issue_owner))
# Get the list of FAS groups who can maintain the package
access_groups = set(contributors['groups']['admin']) | \
set(contributors['groups']['commit']) | \
set(g['user']
for g in contributors['groups']['collaborators']
if fnmatch.fnmatch(branch_name, g['branches']))
group_member = False
for access_group in access_groups:
# Check if the requestor is part of any of the FAS groups who can maintain the package
if FAS_CLIENT.user_member_of(FAS_CLIENT.get_fas_user(issue_owner), access_group):
group_member = True
break
if issue_owner not in maintainers and not group_member:
prompt_to_close_bad_ticket(
issue_json, '{0} is not a maintainer of the {1} package'.format(issue_owner, repo)
)
return
# Get the list of maintainers of the package
maintainers = set(contributors['users']['admin']) | \
set(contributors['users']['commit']) | \
set(u['user']
for u in contributors['users']['collaborators']
if fnmatch.fnmatch(branch_name, u['branches']))
if auto_approve and \
not ticket_requires_approval('new_branch', issue_body_json):
click.echo('- Auto-approving the new branch request for "{0}" on '
'{1}/{2}'.format(branch_name, namespace, repo))
action = 'approve'
else:
click.echo('\nTicket #{0}'.format(issue_id))
click.echo(' Ticket Title: {0}'.format(issue_title))
click.echo(' Ticket Opened By: {0}'.format(issue_owner))
click.echo(' Ticket URL: {0}'.format(issue_ui_url))
click.echo(' Action: New Branch')
click.echo(' Namespace: {0}'.format(namespace))
click.echo(' Name: {0}'.format(repo))
click.echo(' Branch: {0}'.format(branch_name))
click.echo(' SLs: {0}'.format(', '.join(sla_list)))
click.echo(' Git Branch: {0}'.format(bool_to_word(
create_git_branch)))
if not auto_approve:
action = prompt_for_ticket_action()
else:
action = 'approve'
if action == 'approve':
pagure_url = get_config_item(CONFIG, 'pagure_dist_git_url')
dist_git_url = '{0}/{1}/{2}'.format(
pagure_url.rstrip('/'), namespace, repo)
# If the global component already exists, this will not try to create
# it
pdc.new_global_component(repo, dist_git_url)
# Pagure uses plural names for namespaces, but PDC does not use the
# plural version for branch types
branch_type = pdc.component_type_to_singular(namespace)
pdc.new_branch(repo, branch_name, branch_type)
for sla, eol in issue_body_json['sls'].items():
pdc.new_sla_to_branch(
sla, eol, repo, branch_name, branch_type)
if create_git_branch:
new_git_branch(namespace, repo, branch_name)
new_branch_comment = ('The branch was created in PDC and git. It '
'may take up to 10 minutes before you have '
'write access on the branch.')
else:
new_branch_comment = (
'The branch in PDC was created. Pagure is still processing '
'the request, but in about 10 minutes, you may create the '
'branch in Pagure using git.')
comment_and_close_ticket(issue_id, bug_id, new_branch_comment,
prompt_for_comment=False)
elif action == 'deny':
comment_body = click.prompt(
'Please enter a comment explaining the denial')
pagure.close_issue(issue_id, comment_body, 'Denied')
if bug_id:
BUGZILLA_CLIENT.comment(bug_id, comment_body)
else:
# This means the admin is skipping this ticket for now
# Get the list of FAS groups who can maintain the package
access_groups = set(contributors['groups']['admin']) | \
set(contributors['groups']['commit']) | \
set(g['user']
for g in contributors['groups']['collaborators']
if fnmatch.fnmatch(branch_name, g['branches']))
group_member = False
for access_group in access_groups:
# Check if the requestor is part of any of the FAS groups who can maintain the package
if fedora_account.user_member_of(fedora_account.get_user_by_username(issue_owner), access_group):
group_member = True
break
if issue_owner not in maintainers and not group_member:
self.pagure_io.close_issue(
issue["id"],
namespace=PROJECT_NAMESPACE,
message='{0} is not a maintainer of the {1} package'.format(issue_owner, repo),
reason="Invalid"
)
return
_log.info("Ticket passed all validations. Creating repository.")
# Create the PDC entry
dist_git_url = '{0}/{1}/{2}'.format(
self.dist_git._pagure_url.rstrip('/'), namespace, repo)
# If the global component already exists, this will not try to create
# it
pdc.new_global_component(repo, dist_git_url)
pdc.new_branch(repo, branch_name, branch_type)
for sla, eol in issue_body_json['sls'].items():
pdc.new_sla_to_branch(
sla, eol, repo, branch_name, branch_type)
if create_git_branch:
with TemporaryDirectory(dir=self.temp_dir) as tmp_dir:
repo = git.clone_repo(dist_git_url, tmp_dir)
default_branch = self.dist_git.get_default_branch(namespace, repo)
commit = repo.first_commit(default_branch)
self.dist_git.new_branch(namespace, repo, branch_name, from_commit=commit)
new_branch_comment = ('The branch was created in PDC and git. It '
'may take up to 10 minutes before you have '
'write access on the branch.')
else:
new_branch_comment = (
'The branch in PDC was created. Pagure is still processing '
'the request, but in about 10 minutes, you may create the '
'branch in Pagure using git.')
self.pagure_io.close_issue(
issue["id"],
namespace=PROJECT_NAMESPACE,
message=new_branch_comment,
reason="Processed"
)
def validate_review_bug(self, bug_id: str, pkg: str, branch: str,
require_auth: bool = False, check_fas: bool = False,
namespace: str = 'rpms', pagure_user: Optional[str] = None
@ -923,25 +907,3 @@ class SCMRequestProcessor(ToddlerBase):
'git branch can\'t be created.')
pagure.new_branch(
namespace, repo, branch, from_commit=git_obj.first_commit(namespace, repo))
def ticket_requires_approval(issue_type, issue):
"""
Determines if the issue requires approval from an administrator.
:param issue_type: a string determining the issue type
:param issue: a dictionary of the issue
:return: a boolean
"""
# Only some new_branch requests can be auto-approved
if issue_type != 'new_branch':
return True
namespace = issue['namespace'].strip()
# Only some RPM requests can be auto-approved for now
if namespace != 'rpms':
return True
branch_name = issue['branch'].strip()
standard_branch = is_valid_standard_branch(branch_name)
return not (standard_branch and not re.match(r'^(el|epel)[0-9]+$',
branch_name))