Skip to content

Commit

Permalink
Cherry-pick 270193@main (9c049ce). rdar://113880142
Browse files Browse the repository at this point in the history
    [webkitbugspy] Set keywords on issues
    https://bugs.webkit.org/show_bug.cgi?id=260184
    rdar://113880142

    Reviewed by Dewei Zhu.

    Tools and services should be able to add and remove keywords from
    radars and bugzillas.

    * Tools/Scripts/libraries/webkitbugspy/setup.py: Bump version.
    * Tools/Scripts/libraries/webkitbugspy/webkitbugspy/__init__.py: Ditto.
    * Tools/Scripts/libraries/webkitbugspy/webkitbugspy/bugzilla.py:
    (Tracker.set): Add ability to set keywords.
    * Tools/Scripts/libraries/webkitbugspy/webkitbugspy/issue.py:
    (Issue.set_keywords): Set keywords in tracker implementation.
    * Tools/Scripts/libraries/webkitbugspy/webkitbugspy/mocks/bugzilla.py:
    (Bugzilla._issue): Mock adding and setting keywords.
    * Tools/Scripts/libraries/webkitbugspy/webkitbugspy/mocks/radar.py:
    (RadarModel.keywords): Pull from pre-constructed Keyword objects.
    (RadarModel.remove_keyword): Remove a keyword from the issue.
    (RadarModel.add_keyword): Add a keyword to the issue.
    (RadarClient.keywords_for_name): List all keywords starting with a given string.
    (Radar.__init__): Construct set of available keywords.
    * Tools/Scripts/libraries/webkitbugspy/webkitbugspy/radar.py:
    (Tracker.__init__): Keep track of previously queries keywords.
    (Tracker.set): Add and remove keywords from a radar.
    * Tools/Scripts/libraries/webkitbugspy/webkitbugspy/tests/bugzilla_unittest.py:
    * Tools/Scripts/libraries/webkitbugspy/webkitbugspy/tests/radar_unittest.py:

    Canonical link: https://commits.webkit.org/270193@main

Canonical link: https://commits.webkit.org/267815.562@safari-7617-branch
  • Loading branch information
JonWBedard committed Nov 11, 2023
1 parent 03fee13 commit 2c7b4d7
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 6 deletions.
2 changes: 1 addition & 1 deletion Tools/Scripts/libraries/webkitbugspy/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def readme():

setup(
name='webkitbugspy',
version='0.13.3',
version='0.14.0',
description='Library containing a shared API for various bug trackers.',
long_description=readme(),
classifiers=[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def _maybe_add_library_path(path):
"Please install webkitcorepy with `pip install webkitcorepy --extra-index-url <package index URL>`"
)

version = Version(0, 13, 3)
version = Version(0, 14, 0)

from .user import User
from .issue import Issue
Expand Down
10 changes: 8 additions & 2 deletions Tools/Scripts/libraries/webkitbugspy/webkitbugspy/bugzilla.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ def populate(self, issue, member=None):

return issue

def set(self, issue, assignee=None, opened=None, why=None, project=None, component=None, version=None, original=None, **properties):
def set(self, issue, assignee=None, opened=None, why=None, project=None, component=None, version=None, original=None, keywords=None, **properties):
update_dict = dict()

if properties:
Expand Down Expand Up @@ -400,6 +400,9 @@ def set(self, issue, assignee=None, opened=None, why=None, project=None, compone
update_dict['component'] = component
update_dict['version'] = version

if keywords is not None:
update_dict['keywords'] = dict(set=keywords)

if update_dict:
update_dict['ids'] = [issue.id]
response = None
Expand All @@ -420,10 +423,13 @@ def set(self, issue, assignee=None, opened=None, why=None, project=None, compone
issue._opened = None
sys.stderr.write("Failed to modify '{}'\n".format(issue))
return None
elif project and component and version:

if project and component and version:
issue._project = project
issue._component = component
issue._version = version
if keywords is not None:
issue._keywords = keywords

return issue

Expand Down
3 changes: 3 additions & 0 deletions Tools/Scripts/libraries/webkitbugspy/webkitbugspy/issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ def keywords(self):
self.tracker.populate(self, 'keywords')
return self._keywords

def set_keywords(self, keywords):
return self.tracker.set(self, keywords=keywords)

@property
def classification(self):
if self._classification is None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,14 @@ def _issue(self, url, id, credentials=None, data=None):
if data.get('version'):
issue['version'] = data['version']

keywords = data.get('keywords', {})
if keywords:
assert len(keywords) == 1
if keywords.get('set'):
issue['keywords'] = keywords.get('set')
elif keywords.get('add'):
issue['keywords'] = issue.get('keywords', []) + keywords.get('add')

if not issue.get('watchers', None):
issue['watchers'] = []
for candidate in data.get('cc', {}).get('add', []):
Expand Down
22 changes: 21 additions & 1 deletion Tools/Scripts/libraries/webkitbugspy/webkitbugspy/mocks/radar.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ def related_radars(self):
yield ref

def keywords(self):
return [self.Keyword(keyword) for keyword in self._issue.get('keywords', [])]
return [self.client.parent.keywords[keyword] for keyword in self._issue.get('keywords', [])]

def commit_changes(self):
self.client.parent.issues[self.id]['comments'] = [
Expand Down Expand Up @@ -281,6 +281,15 @@ def relationships(self, relationships=None):
))
return result

def remove_keyword(self, keyword):
if keyword.name in self._issue.get('keywords') or []:
self._issue['keywords'].remove(keyword.name)

def add_keyword(self, keyword):
self._issue['keywords'] = self._issue.get('keywords') or []
if keyword.name not in self._issue['keywords']:
self._issue['keywords'].append(keyword.name)


class RadarClient(object):
def __init__(self, parent, authentication_strategy):
Expand Down Expand Up @@ -387,6 +396,12 @@ def clone_radar(self, problem_id, reason_text, component=None):
reproducible='Always',
))

def keywords_for_name(self, keyword_name):
return [
keyword for name, keyword in self.parent.keywords.items()
if name.startswith(keyword_name)
]


class Radar(Base, ContextStack):
top = None
Expand Down Expand Up @@ -458,6 +473,11 @@ def __init__(self, users=None, issues=None, projects=None, milestones=None):
for name in sorted([user.name for user in users or []]):
self.users.add(self.transform_user(users[name]))

self.keywords = {}
for issue in issues or []:
for keyword in issue.get('keywords') or []:
self.keywords[keyword] = RadarModel.Keyword(keyword)

self.issues = {}
for issue in issues or []:
self.add(issue)
Expand Down
25 changes: 24 additions & 1 deletion Tools/Scripts/libraries/webkitbugspy/webkitbugspy/radar.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ def __init__(self, users=None, authentication=None, project=None, projects=None,
super(Tracker, self).__init__(users=users, redact=redact, redact_exemption=redact_exemption, hide_title=hide_title)
self._projects = [project] if project else (projects or [])

self._keywords = dict()
self._invalid_keywords = set()

self.library = self.radarclient()
authentication = authentication or (self.authentication() if self.library else None)
if authentication:
Expand Down Expand Up @@ -278,7 +281,7 @@ def populate(self, issue, member=None):

return issue

def set(self, issue, assignee=None, opened=None, why=None, project=None, component=None, version=None, original=None, **properties):
def set(self, issue, assignee=None, opened=None, why=None, project=None, component=None, version=None, original=None, keywords=None, **properties):
if not self.client or not self.library:
sys.stderr.write('radarclient inaccessible on this machine\n')
return None
Expand Down Expand Up @@ -358,6 +361,26 @@ def set(self, issue, assignee=None, opened=None, why=None, project=None, compone
issue._component = component
issue._version = version

if keywords is not None:
for keyword in keywords + issue.keywords:
if keyword not in self._invalid_keywords and keyword not in self._keywords:
candidates = self.client.keywords_for_name(keyword)
for candidate in candidates:
self._keywords[candidate.name] = candidate
if keyword in self._keywords:
continue
self._invalid_keywords.add(keyword)
raise ValueError("'{}' is not a valid keyword".format(keyword))

for word in issue.keywords:
if word not in keywords:
radar.remove_keyword(self._keywords[word])
for word in keywords:
if word not in issue.keywords:
radar.add_keyword(self._keywords[word])
did_change = True
issue._keywords = keywords

if did_change:
radar.commit_changes()
return self.add_comment(issue, why) if why else issue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -572,3 +572,21 @@ def test_classification(self):
with mocks.Bugzilla(self.URL.split('://')[1], issues=mocks.ISSUES):
tracker = bugzilla.Tracker(self.URL)
self.assertEqual(tracker.issue(1).classification, '')

def test_set_keywords(self):
with OutputCapture(level=logging.INFO), mocks.Bugzilla(
self.URL.split('://')[1],
projects=mocks.PROJECTS,
environment=wkmocks.Environment(
BUGS_EXAMPLE_COM_USERNAME='tcontributor@example.com',
BUGS_EXAMPLE_COM_PASSWORD='password',
), users=mocks.USERS, issues=mocks.ISSUES,
):

tracker = bugzilla.Tracker(self.URL)
issue = tracker.issue(1)

self.assertEqual(issue.keywords, ['Keyword A'])
issue.set_keywords(['REGRESSION'])
self.assertEqual(issue.keywords, ['REGRESSION'])
self.assertEqual(tracker.issue(1).keywords, ['REGRESSION'])
Original file line number Diff line number Diff line change
Expand Up @@ -448,3 +448,13 @@ def test_clone(self):
'<original text - begin>\n\n'
'An example issue for testing',
)

def test_set_keywords(self):
with wkmocks.Environment(RADAR_USERNAME='tcontributor'), mocks.Radar(issues=mocks.ISSUES, projects=mocks.PROJECTS):
tracker = radar.Tracker()
issue = tracker.issue(1)

self.assertEqual(issue.keywords, ['Keyword A'])
issue.set_keywords(['Keyword B'])
self.assertEqual(issue.keywords, ['Keyword B'])
self.assertEqual(tracker.issue(1).keywords, ['Keyword B'])

0 comments on commit 2c7b4d7

Please sign in to comment.