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 # This is the same format as used by the distgit_bugzilla_sync cron/app
email_overrides_file = "/path/to/email_overrides.toml" 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] [consumer_config.default.pdc_config]
# Configuration to talk to PDC, as understood by pdc-client. # Configuration to talk to PDC, as understood by pdc-client.
server = "https://pdc.fedoraproject.org/rest_api/v1/" 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> Authors: Michal Konecny <mkonecny@redhat.com>
""" """
import fnmatch
import logging import logging
import re import re
from tempfile import TemporaryDirectory
import arrow import arrow
from pagure_messages.issue_schema import IssueNewV1 from pagure_messages.issue_schema import IssueNewV1
from toddlers.base import ToddlerBase 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 from toddlers.exceptions import ValidationError
# Regex for branch name validation # Regex for branch name validation
@ -67,6 +69,9 @@ class SCMRequestProcessor(ToddlerBase):
# Pagure object connected to dist-git # Pagure object connected to dist-git
dist_git = None dist_git = None
# Path to temporary dir
temp_dir = None
def accepts_topic(self, topic: str) -> bool: def accepts_topic(self, topic: str) -> bool:
"""Returns a boolean whether this toddler is interested in messages """Returns a boolean whether this toddler is interested in messages
from this specific topic. from this specific topic.
@ -113,6 +118,7 @@ class SCMRequestProcessor(ToddlerBase):
self.monitoring_choices = config.get("monitoring_choices") self.monitoring_choices = config.get("monitoring_choices")
self.pagure_namespace_to_component = config.get("pagure_namespace_to_component") self.pagure_namespace_to_component = config.get("pagure_namespace_to_component")
self.pagure_namespace_to_product = config.get("pagure_namespace_to_product") self.pagure_namespace_to_product = config.get("pagure_namespace_to_product")
self.temp_dir = config.get("temp_dir")
_log.info("Setting up PDC client") _log.info("Setting up PDC client")
pdc.set_pdc(config) pdc.set_pdc(config)
@ -518,18 +524,19 @@ class SCMRequestProcessor(ToddlerBase):
) )
return return
if create_git_branch:
assert_git_repo_initialized_remotely(namespace, repo)
branch_name = issue_body_json['branch'].strip() branch_name = issue_body_json['branch'].strip()
if is_epel(branch_name) and not valid_epel_package(repo, branch_name): if re.match(EPEL_REGEX, branch_name) and not self.valid_epel_package(repo, branch_name):
if not force: self.pagure_io.close_issue(
prompt_to_close_bad_ticket(issue_json, INVALID_EPEL_ERROR) issue["id"],
return namespace=PROJECT_NAMESPACE,
message=INVALID_EPEL_ERROR,
reason="Invalid"
)
return
# Pagure uses plural names for namespaces, but PDC does not use the # Pagure uses plural names for namespaces, but PDC does not use the
# plural version for branch types # plural version for branch types
branch_type = pdc.component_type_to_singular(namespace) branch_type = namespace.strip().rstrip('s')
click.echo('- Checking if {0} already exists in PDC.'.format(branch_name)) _log.info('- Checking if {0} already exists in PDC.'.format(branch_name))
pdc_branch = pdc.get_branch(repo, branch_name, branch_type) pdc_branch = pdc.get_branch(repo, branch_name, branch_type)
if pdc_branch: if pdc_branch:
ticket_text = \ ticket_text = \
@ -540,107 +547,84 @@ class SCMRequestProcessor(ToddlerBase):
"``git checkout -b <branch_name> && git push -u origin <branch_name>``.\n" \ "``git checkout -b <branch_name> && git push -u origin <branch_name>``.\n" \
"``<branch_name>`` is the name of the branch you requested. \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." "You only need to do this once and you can then use fedpkg as you normally do."
prompt_to_close_bad_ticket( self.pagure_io.close_issue(
issue_json, ticket_text) issue["id"],
namespace=PROJECT_NAMESPACE,
message=ticket_text,
reason="Invalid"
)
return return
issue_id = issue_json['id'] issue_id = issue['id']
issue_title = issue_json['title'].strip() issue_title = issue['title'].strip()
issue_owner = issue_json['user']['name'] issue_owner = issue['user']['name']
issue_ui_url = pagure.get_pagure_issue_url(issue_id) issue_ui_url = issue["full_url"]
# Check if the branch requestor is one of the maintainers or part of the groups # 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)) _log.info('- 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']))
# Get the list of FAS groups who can maintain the package # Get the list of maintainers of the package
access_groups = set(contributors['groups']['admin']) | \ maintainers = set(contributors['users']['admin']) | \
set(contributors['groups']['commit']) | \ set(contributors['users']['commit']) | \
set(g['user'] set(u['user']
for g in contributors['groups']['collaborators'] for u in contributors['users']['collaborators']
if fnmatch.fnmatch(branch_name, g['branches'])) if fnmatch.fnmatch(branch_name, u['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
if auto_approve and \ # Get the list of FAS groups who can maintain the package
not ticket_requires_approval('new_branch', issue_body_json): access_groups = set(contributors['groups']['admin']) | \
click.echo('- Auto-approving the new branch request for "{0}" on ' set(contributors['groups']['commit']) | \
'{1}/{2}'.format(branch_name, namespace, repo)) set(g['user']
action = 'approve' for g in contributors['groups']['collaborators']
else: if fnmatch.fnmatch(branch_name, g['branches']))
click.echo('\nTicket #{0}'.format(issue_id)) group_member = False
click.echo(' Ticket Title: {0}'.format(issue_title)) for access_group in access_groups:
click.echo(' Ticket Opened By: {0}'.format(issue_owner)) # Check if the requestor is part of any of the FAS groups who can maintain the package
click.echo(' Ticket URL: {0}'.format(issue_ui_url)) if fedora_account.user_member_of(fedora_account.get_user_by_username(issue_owner), access_group):
click.echo(' Action: New Branch') group_member = True
click.echo(' Namespace: {0}'.format(namespace)) break
click.echo(' Name: {0}'.format(repo)) if issue_owner not in maintainers and not group_member:
click.echo(' Branch: {0}'.format(branch_name)) self.pagure_io.close_issue(
click.echo(' SLs: {0}'.format(', '.join(sla_list))) issue["id"],
click.echo(' Git Branch: {0}'.format(bool_to_word( namespace=PROJECT_NAMESPACE,
create_git_branch))) message='{0} is not a maintainer of the {1} package'.format(issue_owner, repo),
reason="Invalid"
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
return 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, def validate_review_bug(self, bug_id: str, pkg: str, branch: str,
require_auth: bool = False, check_fas: bool = False, require_auth: bool = False, check_fas: bool = False,
namespace: str = 'rpms', pagure_user: Optional[str] = None namespace: str = 'rpms', pagure_user: Optional[str] = None
@ -923,25 +907,3 @@ class SCMRequestProcessor(ToddlerBase):
'git branch can\'t be created.') 'git branch can\'t be created.')
pagure.new_branch( pagure.new_branch(
namespace, repo, branch, from_commit=git_obj.first_commit(namespace, repo)) 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))