Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PTFE-1482 introduce bot status report #167

Merged
merged 9 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 7 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
# Change Log
All notable changes to this project will be documented in this file.

## [4.0.0] - 2024-03-06
# Removed
- Support of tasks as it unused to due its incompatibility with GitHub.

# Added
- Bert-E's status notifications through a build status check.

## [3.12.0] - 2024-02-26
# Added
- Add toggable list of options and commands to init message.
Expand Down
4 changes: 0 additions & 4 deletions bert_e/bert_e.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,6 @@ def __init__(self, settings):
)
if settings.repository_host == 'bitbucket':
self.settings.robot.account_id = self.client.get_user_id()
if settings.repository_host == 'github':
if settings['tasks']:
LOG.warning("Disabling tasks on GitHub repo")
settings['tasks'] = []
self.project_repo = self.client.get_repository(
owner=settings.repository_owner,
slug=settings.repository_slug
Expand Down
34 changes: 34 additions & 0 deletions bert_e/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import Literal
from bert_e.lib.template_loader import render

# When dont_repeat_if_in_history is None, Bert-E will look for the message
Expand All @@ -27,6 +28,7 @@ class BertE_Exception(Exception):
class TemplateException(BertE_Exception):
code = -2
template = None
status: Literal[None, "in_progress", "success", "failure"] = None
# whether to re-publish if the message is already in the history
dont_repeat_if_in_history = -1

Expand All @@ -40,6 +42,11 @@ def __init__(self, **kwargs):
self.msg = render(self.template, code=self.code, **kwargs)
super(TemplateException, self).__init__(self.msg)

@property
def title(self) -> str:
# Return the exception class name as the title
return self.__class__.__name__


class InternalException(BertE_Exception):
code = 1
Expand Down Expand Up @@ -69,6 +76,7 @@ class HelpMessage(TemplateException):
class SuccessMessage(TemplateException):
code = 102
template = 'successful_merge.md'
status = "success"


class CommandNotImplemented(TemplateException):
Expand All @@ -86,61 +94,73 @@ class StatusReport(TemplateException):
class IncompatibleSourceBranchPrefix(TemplateException):
code = 106
template = 'incompatible_source_branch_prefix.md'
status = "failure"


class MissingJiraId(TemplateException):
code = 107
template = 'missing_jira_id.md'
status = "failure"


class JiraIssueNotFound(TemplateException):
code = 108
template = 'jira_issue_not_found.md'
status = "failure"


class IssueTypeNotSupported(TemplateException):
code = 109
template = 'issue_type_not_supported.md'
status = "failure"


class IncorrectJiraProject(TemplateException):
code = 110
template = 'incorrect_jira_project.md'
status = "failure"


class MismatchPrefixIssueType(TemplateException):
code = 111
template = 'mismatch_prefix_issue_type.md'
status = "failure"


class IncorrectFixVersion(TemplateException):
code = 112
template = 'incorrect_fix_version.md'
status = "failure"


class BranchHistoryMismatch(TemplateException):
code = 113
template = 'history_mismatch.md'
status = "failure"


class Conflict(TemplateException):
code = 114
template = 'conflict.md'
status = "failure"


class ApprovalRequired(TemplateException):
code = 115
template = 'need_approval.md'
status = "in_progress"


class BuildFailed(TemplateException):
code = 118
template = 'build_failed.md'
status = "failure"


class AfterPullRequest(TemplateException):
code = 120
template = 'after_pull_request.md'
status = "in_progress"


class IntegrationDataCreated(InformationException):
Expand All @@ -151,21 +171,25 @@ class IntegrationDataCreated(InformationException):
class UnknownCommand(TemplateException):
code = 122
template = 'unknown_command.md'
status = "failure"


class NotEnoughCredentials(TemplateException):
code = 123
template = "not_enough_credentials.md"
status = "failure"


class QueueConflict(TemplateException):
code = 124
template = "queue_conflict.md"
status = "failure"


class Queued(TemplateException):
code = 125
template = 'queued.md'
status = "in_progress"

def __init__(self, branches, ignored, issue, author, active_options):
"""Save args for later use by tests."""
Expand All @@ -187,11 +211,13 @@ class PartialMerge(TemplateException):
code = 126
template = 'partial_merge.md'
dont_repeat_if_in_history = 0 # allow repeating as many times as it occurs
status = "success"


class QueueOutOfOrder(TemplateException):
code = 127
template = "queue_out_of_order.md"
status = "failure"


class ResetComplete(TemplateException):
Expand All @@ -202,36 +228,44 @@ class ResetComplete(TemplateException):
class LossyResetWarning(TemplateException):
code = 129
template = "lossy_reset.md"
status = "failure"


class IncorrectCommandSyntax(TemplateException):
code = 130
template = "incorrect_command_syntax.md"
status = "failure"


class IncorrectPullRequestNumber(TemplateException):
code = 131
template = "incorrect_pull_request_number.md"
status = "failure"


class SourceBranchTooOld(TemplateException):
code = 132
template = "source_branch_too_old.md"
status = "failure"


class FlakyGitHost(TemplateException):
code = 133
template = "flaky_git_host.md"
status = "failure"


class NotAuthor(TemplateException):
code = 134
template = "not_author.md"
status = "failure"


class RequestIntegrationBranches(TemplateException):
code = 135
template = "request_integration_branches.md"
# TODO: review if it should be failure.
status = "in_progress"


# internal exceptions
Expand Down
34 changes: 11 additions & 23 deletions bert_e/git_host/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,23 +250,8 @@ def key(self) -> str:
"""The build status key."""


class AbstractTask(metaclass=ABCMeta):
"""Abstract class defining a task's interface."""
# Empty, but used as a return value below


class AbstractComment(metaclass=ABCMeta):
"""Abstract class defining the interface of a pull requests's comment."""
@abstractmethod
def add_task(self, msg: str) -> AbstractTask:
"""Attach a new task attached to this comment.

Args:
- msg: the message of the task to attach.

Returns: the newly created task.

"""

@abstractmethod
def delete(self) -> None:
Expand Down Expand Up @@ -326,14 +311,6 @@ def get_approvals(self) -> Iterable[str]:
def get_participants(self) -> Iterable[str]:
"""Get the usernames of the participants to this pull request."""

@abstractmethod
def get_tasks(self) -> Iterable[AbstractTask]:
"""Get this pull request's tasks.

Returns: an iterable over the Task objects.

"""

@abstractmethod
def comment_review(self):
"""Request changes on this pull request."""
Expand All @@ -350,6 +327,17 @@ def approve(self):
def decline(self):
"""Decline this pull request."""

@abstractmethod
def set_bot_status(self, status: str | None, title: str,
summary: str) -> None:
"""Set a status check reporting its advancement regarding Bert-E's checks

Args:
- status: the status of the check.
- title: the title of the check.
- summary: the summary of the check.
"""

@property
@abstractmethod
def id(self) -> str:
Expand Down
54 changes: 4 additions & 50 deletions bert_e/git_host/bitbucket/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@

from . import schema
from .. import base, cache, factory
from bert_e.exceptions import TaskAPIError

MAX_PR_TITLE_LEN = 255

Expand Down Expand Up @@ -356,6 +355,10 @@ def add_comment(self, msg):
pull_request_id=self['id']
)

def set_bot_status(self, status: str | None, title: str, summary: str):
raise NotImplementedError('"set_bot_status" feature '
'is not available in bitbucket')

def get_comments(self, deleted=False):
return sorted(
(comment
Expand All @@ -367,10 +370,6 @@ def get_comments(self, deleted=False):
key=lambda c: c.created_on
)

def get_tasks(self):
return Task.get_list(self.client, full_name=self.full_name(),
pull_request_id=self['id'])

def get_change_requests(self):
# Not supported by bitbucket, default to an empty tuple of usernames
return tuple()
Expand Down Expand Up @@ -485,11 +484,6 @@ def full_name(self):
p = Path(urlparse(self.data['links']['self']['href']).path).resolve()
return '%s/%s' % p.parts[3:5]

def add_task(self, msg):
return Task(self.client, content=msg, full_name=self.full_name(),
pull_request_id=self.data['pullrequest']['id'],
comment_id=self.id).create()

def delete(self):
return super().delete(self.client, full_name=self.full_name(),
pull_request_id=self.data['pullrequest']['id'],
Expand Down Expand Up @@ -520,46 +514,6 @@ def deleted(self):
return self.data['deleted']


class Task(BitBucketObject, base.AbstractTask):
get_url = 'https://bitbucket.org/!api/internal/repositories/$full_name/' \
'pullrequests/$pull_request_id/tasks/$task_id'
add_url = 'https://bitbucket.org/!api/internal/repositories/$full_name/' \
'pullrequests/$pull_request_id/tasks'
list_url = add_url + '?page=$page'

def __init__(self, client, **kwargs):
super().__init__(client, **kwargs)
if 'comment_id' in self._json_data:
self._json_data['comment'] = {'id': self._json_data['comment_id']}
if 'content' in self._json_data:
self._json_data['content'] = {'raw': self._json_data['content']}

def create(self, *args, **kwargs):
try:
return super().create(*args, **kwargs)
except Exception as err:
raise TaskAPIError('create', err)

def delete(self, *args, **kwargs):
try:
return super().delete(*args, **kwargs)
except Exception as err:
raise TaskAPIError('delete', err)

def get(self, *args, **kwargs):
try:
return super().get(*args, **kwargs)
except Exception as err:
raise TaskAPIError('get', err)

@classmethod
def get_list(self, *args, **kwargs):
try:
return list(super().get_list(*args, **kwargs))
except Exception as err:
raise TaskAPIError('get_list', err)


class BuildStatus(BitBucketObject, base.AbstractBuildStatus):
get_url = 'https://api.bitbucket.org/2.0/repositories/$owner/$repo_slug/' \
'commit/$revision/statuses/build/$key'
Expand Down
Loading
Loading