Skip to content
This repository has been archived by the owner on May 16, 2022. It is now read-only.

closing issues using ogr #231

Merged
merged 5 commits into from
Jul 16, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions release_bot/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

class Configuration:
# note that required items need to reference strings as their length is checked
REQUIRED_ITEMS = {"conf": ['repository_name', 'repository_owner', 'github_token'],
REQUIRED_ITEMS = {"conf": ['repository_name', 'repository_owner'],
"release-conf": []}

def __init__(self):
Expand All @@ -53,7 +53,7 @@ def __init__(self):
self.github_app_cert_path = ''
self.clone_url = ''
# used for different pagure forges pagure.io by default
self.pagure_instance_url = 'pagure.io'
self.pagure_instance_url = 'https://pagure.io'
rpitonak marked this conversation as resolved.
Show resolved Hide resolved
self.webhook_handler = False
self.gitchangelog = False
self.project = None
Expand Down Expand Up @@ -143,10 +143,13 @@ def load_release_conf(self, conf):
sys.exit(1)
for index, label in enumerate(parsed_conf.get('labels', [])):
parsed_conf['labels'][index] = str(label)
if parsed_conf.get('trigger_on_issue') and not self.github_username:
msg = "Can't trigger on issue if 'github_username' is not known, disabling"
self.logger.warning(msg)
parsed_conf['trigger_on_issue'] = False

if parsed_conf.get('trigger_on_issue'):
if not self.github_username and not self.pagure_username:
msg = ("Can't trigger on issue if "
"'github_username/pagure_username' is not known, disabling")
self.logger.warning(msg)
parsed_conf['trigger_on_issue'] = False

return parsed_conf

Expand Down
72 changes: 28 additions & 44 deletions release_bot/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import jwt
import requests


logger = logging.getLogger('release-bot')


Expand All @@ -37,12 +36,12 @@ def __init__(self, iss, key, expiration=10 * 60):
def generate_token(self):
# Generate the JWT
payload = {
# issued at time
'iat': int(time.time()),
# JWT expiration time (10 minute maximum)
'exp': int(time.time()) + self.expiration,
# GitHub App's identifier
'iss': self.iss
# issued at time
'iat': int(time.time()),
# JWT expiration time (10 minute maximum)
'exp': int(time.time()) + self.expiration,
# GitHub App's identifier
'iss': self.iss
}

tok = jwt.encode(payload, self.key, algorithm='RS256')
Expand Down Expand Up @@ -101,6 +100,7 @@ def __init__(self, configuration, git):
"""
self.conf = configuration
self.logger = configuration.logger
self.project = configuration.project
self.session = requests.Session()
self.session.headers.update({'Authorization': f'token {configuration.github_token}'})
self.github_app_session = None
Expand All @@ -116,7 +116,8 @@ def update_github_app_token(self):
self.logger.debug("github app token obtained")
self.github_app_session.headers.update({'Authorization': f'token {token}'})

def do_request(self, query=None, method=None, json_payload=None, url=None, use_github_auth=False):
def do_request(self, query=None, method=None, json_payload=None, url=None,
use_github_auth=False):
"""
a single wrapper to make any type of request:

Expand All @@ -136,21 +137,25 @@ def do_request(self, query=None, method=None, json_payload=None, url=None, use_g
if query:
self.logger.debug(f'query = {query}')
if use_github_auth and self.github_app_session:
response = self.github_app_session.post(url=self.API_ENDPOINT, json={'query': query})
response = self.github_app_session.post(url=self.API_ENDPOINT,
json={'query': query})
else:
response = self.session.post(url=self.API_ENDPOINT, json={'query': query})
if response.status_code == 401 and self.github_app_session:
self.update_github_app_token()
response = self.github_app_session.post(url=self.API_ENDPOINT, json={'query': query})
response = self.github_app_session.post(url=self.API_ENDPOINT,
json={'query': query})
elif method and url:
self.logger.debug(f'{method} {url}')
if use_github_auth and self.github_app_session:
response = self.github_app_session.request(method=method, url=url, json=json_payload)
response = self.github_app_session.request(method=method, url=url,
json=json_payload)
else:
response = self.session.request(method=method, url=url, json=json_payload)
if response.status_code == 401 and self.github_app_session:
self.update_github_app_token()
response = self.github_app_session.request(method=method, url=url, json=json_payload)
response = self.github_app_session.request(method=method, url=url,
json=json_payload)
if not response.ok:
self.logger.error(f"error message: {response.content}")
else:
Expand Down Expand Up @@ -288,7 +293,8 @@ def make_new_release(self, new_release):
url = (f"{self.API3_ENDPOINT}repos/{self.conf.repository_owner}/"
f"{self.conf.repository_name}/releases")
self.logger.debug(f"About to release {new_release.version} on Github")
response = self.do_request(method="POST", url=url, json_payload=payload, use_github_auth=True)
response = self.do_request(method="POST", url=url, json_payload=payload,
use_github_auth=True)
if response.status_code != 201:
msg = f"Failed to create new release on github:\n{response.text}"
raise ReleaseException(msg)
Expand Down Expand Up @@ -320,7 +326,8 @@ def update_changelog(self, new_version):

url = (f"{self.API3_ENDPOINT}repos/{self.conf.repository_owner}/"
f"{self.conf.repository_name}/releases/{latest_release['id']}")
response = self.do_request(method="POST", url=url, json_payload={'body': changelog}, use_github_auth=True)
response = self.do_request(method="POST", url=url, json_payload={'body': changelog},
use_github_auth=True)
if response.status_code != 200:
self.logger.error((f"Something went wrong during changelog "
f"update for {new_version}:\n{response.text}"))
Expand Down Expand Up @@ -379,7 +386,8 @@ def make_pr(self, branch, version, log, changed_version_files, base='master', la
url = (f"{self.API3_ENDPOINT}repos/{self.conf.repository_owner}/"
f"{self.conf.repository_name}/pulls")
self.logger.debug(f'Attempting a PR for {branch} branch')
response = self.do_request(method="POST", url=url, json_payload=payload, use_github_auth=True)
response = self.do_request(method="POST", url=url, json_payload=payload,
use_github_auth=True)
if response.status_code == 201:
parsed = response.json()
self.logger.info(f"Created PR: {parsed['html_url']}")
Expand Down Expand Up @@ -482,23 +490,6 @@ def get_user_contact(self):
email = '[email protected]'
return name, email

def close_issue(self, number):
"""
Close an github issue
:param number: number of the issue in repository
:return: True on success, False on fail
"""
payload = {'state': 'closed'}
url = (f"{self.API3_ENDPOINT}repos/{self.conf.repository_owner}/"
f"{self.conf.repository_name}/issues/{number}")
self.logger.debug(f'Attempting to close issue #{number}')
response = self.do_request(method='PATCH', url=url, json_payload=payload, use_github_auth=True)
if response.status_code == 200:
self.logger.debug(f'Closed issue #{number}')
return True
self.logger.error(f'Failed to close issue #{number}')
return False

def put_labels_on_issue(self, number, labels):
"""
Put labels on Github issue or PR
Expand All @@ -524,21 +515,14 @@ def put_labels_on_issue(self, number, labels):
def get_file(self, name):
"""
Fetches a specific file via Github API
@:param: str, name of the file
:return: file content or None in case of error
"""
url = (f"{self.API3_ENDPOINT}repos/{self.conf.repository_owner}/"
f"{self.conf.repository_name}/contents/{name}")
self.logger.debug(f'Fetching {name}')
response = self.do_request(url=url, method='GET')
if response.status_code != 200:
self.logger.error(f'Failed to fetch {name}')
return None

parsed = response.json()
download_url = parsed['download_url']
response = requests.get(url=download_url)
if response.status_code != 200:
try:
file = self.project.get_file_content(path=name)
except FileNotFoundError:
self.logger.error(f'Failed to fetch {name}')
return None

return response.text
return file
58 changes: 32 additions & 26 deletions release_bot/releasebot.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from flask import Flask
from semantic_version import Version
from ogr import GithubService, PagureService
from ogr.abstract import IssueStatus

from release_bot.cli import CLI
from release_bot.configuration import configuration
Expand Down Expand Up @@ -104,40 +105,44 @@ def find_open_release_issues(self):
Looks for opened release issues on github
:return: True on found, False if not found
"""
cursor = ''
release_issues = {}
latest_version = Version(self.github.latest_release())
while True:
edges = self.github.walk_through_open_issues(start=cursor, direction='before')
if not edges:
self.logger.debug(f'No more open issues found')
break
else:
for edge in reversed(edges):
cursor = edge['cursor']
title = edge['node']['title'].lower().strip()
match, version = process_version_from_title(title, latest_version)
if match:
if edge['node']['authorAssociation'] in ['MEMBER', 'OWNER',
'COLLABORATOR']:
release_issues[version] = edge['node']
self.logger.info(f'Found new release issue with version: {version}')
opened_issues = self.project.get_issue_list(IssueStatus.open)
if not opened_issues:
self.logger.debug(f'No more open issues found')
else:
for issue in opened_issues:
match, version = process_version_from_title(issue.title, latest_version)
if match:
allowed_users = self.project.who_can_close_issue()
if (self.conf.github_username in allowed_users
or self.conf.pagure_username in allowed_users):
release_issues[version] = issue
self.logger.info(f'Found new release issue with version: {version}')
else:
if self.which_service() == "Github":
rpitonak marked this conversation as resolved.
Show resolved Hide resolved
self.logger.warning(f"User {self.conf.github_username } "
f"has no permission to modify issue")
else:
self.logger.warning(
f"Author association {edge['node']['authorAssociation']!r} "
f"not in ['MEMBER', 'OWNER', 'COLLABORATOR']")
self.logger.warning(f"User {self.conf.pagure_username} "
f"has no permission to modify issue")
jpopelka marked this conversation as resolved.
Show resolved Hide resolved

if len(release_issues) > 1:
msg = f'Multiple release issues are open {release_issues}, please reduce them to one'
self.logger.error(msg)
return False
if len(release_issues) == 1:
for version, node in release_issues.items():
if self.which_service() == "Github":
labels = self.new_release.labels
else:
labels = None # Pagure can't put labels on issue

for version, issue in release_issues.items():
self.new_pr.update_new_pr_details(
version=version,
issue_id=node['id'],
issue_number=node['number'],
labels=self.new_release.labels
issue_id=None,
issue_number=issue.id,
labels=labels
)
return True
else:
Expand Down Expand Up @@ -199,7 +204,8 @@ def pr_handler(success):
self.project.issue_comment(self.new_pr.issue_number, msg)
self.github.comment = comment_backup
if success:
self.github.close_issue(self.new_pr.issue_number)
self.project.issue_close(self.new_pr.issue_number)
self.logger.debug(f'Closed issue #{self.new_pr.issue_number}')

latest_gh_str = self.github.latest_release()
self.new_pr.previous_version = latest_gh_str
Expand Down Expand Up @@ -312,8 +318,8 @@ def run(self):
try:
if self.new_release.trigger_on_issue and self.find_open_release_issues():
if self.new_release.labels is not None:
self.github.put_labels_on_issue(self.new_pr.issue_number,
self.new_release.labels)
self.project.add_issue_labels(self.new_pr.issue_number,
self.new_release.labels)
self.make_release_pull_request()
except ReleaseException as exc:
self.logger.error(exc)
Expand Down
4 changes: 0 additions & 4 deletions tests/test_github.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,6 @@ def test_get_file(self):
"""Tests fetching release-conf from Github"""
assert self.github.get_file("release-conf.yaml") == RELEASE_CONF

def test_close_issue(self, open_issue):
"""Tests closing issue"""
assert self.github.close_issue(open_issue)

def test_latest_rls_not_existing(self):
"""Tests version number when there is no latest release"""
assert self.github.latest_release() == '0.0.0'
Expand Down