Skip to content

Commit

Permalink
[git-webkit] Allow user to CC specific radar
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=245202
<rdar://problem/99942952>

Reviewed by Elliott Williams.

* Tools/Scripts/libraries/webkitbugspy/setup.py: Bump version.
* Tools/Scripts/libraries/webkitbugspy/webkitbugspy/__init__.py: Ditto.
* Tools/Scripts/libraries/webkitbugspy/webkitbugspy/bugzilla.py:
(Tracker.populate): Allow related issue to have the same number as self if trackers are different types.
(Tracker.cc_radar): Allow caller to specify radar to CC.
* Tools/Scripts/libraries/webkitbugspy/webkitbugspy/github.py:
(Issue.cc_radar):
* Tools/Scripts/libraries/webkitbugspy/webkitbugspy/issue.py:
(Issue.cc_radar):
* Tools/Scripts/libraries/webkitbugspy/webkitbugspy/mocks/bugzilla.py:
(Bugzilla._issue): Skip creating radar if 'InRadar' keyword is present.
* Tools/Scripts/libraries/webkitbugspy/webkitbugspy/radar.py:
(Tracker.cc_radar):
* Tools/Scripts/libraries/webkitbugspy/webkitbugspy/tests/bugzilla_unittest.py:
* Tools/Scripts/libraries/webkitbugspy/webkitbugspy/tracker.py:
(Tracker.cc_radar):
* Tools/Scripts/libraries/webkitscmpy/setup.py: Bump version.
* Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py: Ditto.
* Tools/Scripts/libraries/webkitscmpy/webkitscmpy/program/branch.py:
(Branch.main): Ask the user to provide an existing radar instead of always creating a new one.
* Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/branch_unittest.py:
(TestBranch.test_automatic_radar_cc):
(TestBranch.test_manual_radar_cc):

Canonical link: https://commits.webkit.org/254577@main
  • Loading branch information
JonWBedard committed Sep 17, 2022
1 parent 6e24711 commit 479d809
Show file tree
Hide file tree
Showing 13 changed files with 191 additions and 27 deletions.
2 changes: 1 addition & 1 deletion Tools/Scripts/libraries/webkitbugspy/setup.py
Expand Up @@ -30,7 +30,7 @@ def readme():

setup(
name='webkitbugspy',
version='0.8.0',
version='0.8.1',
description='Library containing a shared API for various bug trackers.',
long_description=readme(),
classifiers=[
Expand Down
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, 8, 0)
version = Version(0, 8, 1)

from .user import User
from .issue import Issue
Expand Down
47 changes: 37 additions & 10 deletions Tools/Scripts/libraries/webkitbugspy/webkitbugspy/bugzilla.py
Expand Up @@ -240,7 +240,7 @@ def populate(self, issue, member=None):
for text in [issue.description] + [comment.content for comment in issue.comments]:
for match in self.REFERENCE_RE.findall(text):
candidate = GenericTracker.from_string(match[0]) or self.from_string(match[0])
if not candidate or candidate.link in refs or candidate.id == issue.id:
if not candidate or candidate.link in refs or (isinstance(candidate.tracker, type(issue.tracker)) and candidate.id == issue.id):
continue
issue._references.append(candidate)
refs.add(candidate.link)
Expand Down Expand Up @@ -467,7 +467,7 @@ def create(
return None
return self.issue(response.json()['id'])

def cc_radar(self, issue, block=False, timeout=None):
def cc_radar(self, issue, block=False, timeout=None, radar=None):
if not self.radar_importer:
sys.stderr.write('No radar importer specified\n')
return None
Expand All @@ -479,28 +479,55 @@ def cc_radar(self, issue, block=False, timeout=None):
sys.stderr.write('Project does not define radar tracker\n')
return None

keyword_to_add = None
comment_to_make = None
user_to_cc = self.radar_importer.name if self.radar_importer not in issue.watchers else None
if radar and isinstance(radar.tracker, RadarTracker):
if radar not in issue.references:
comment_to_make = '<rdar://problem/{}>'.format(issue.id)
if user_to_cc:
keyword_to_add = 'InRadar'
elif comment_to_make:
sys.stderr.write("{} already CCed '{}' and tracking a different bug\n".format(
self.radar_importer.name,
issue.references[0] if issue.references else '?',
))

did_modify_cc = False
if self.radar_importer not in issue.watchers:
if user_to_cc or keyword_to_add:
log.info('CCing {}'.format(self.radar_importer.name))
response = None
try:
data = dict(ids=[issue.id])
if user_to_cc:
data['cc'] = dict(add=[self.radar_importer.username])
if comment_to_make:
data['comment'] = dict(body=comment_to_make)
if keyword_to_add:
data['keywords'] = dict(add=[keyword_to_add])
response = requests.put(
'{}/rest/bug/{}{}'.format(self.url, issue.id, self._login_arguments(required=True)),
json=dict(
ids=[issue.id],
cc=dict(add=[self.radar_importer.username]),
),
json=data,
)
except RuntimeError as e:
sys.stderr.write('{}\n'.format(e))
if response and response.status_code // 100 == 4 and self._logins_left:
self._logins_left -= 1
if response and response.status_code // 100 == 2:
if not response or response.status_code // 100 != 2:
sys.stderr.write("Failed to cc {} on '{}'\n".format(self.radar_importer.name, issue))
elif radar and isinstance(radar.tracker, RadarTracker):
if comment_to_make:
issue._references = None
issue._comments.append(Issue.Comment(
user=self.me(),
timestamp=int(time.time()),
content=comment_to_make,
))
return radar
else:
did_modify_cc = True
issue._comments = None
issue._references = None
else:
sys.stderr.write("Failed to cc {} on '{}'\n".format(self.radar_importer.name, issue))

start = time.time()
while start + (timeout or 60) > time.time():
Expand Down
Expand Up @@ -602,6 +602,6 @@ def parse_error(self, json):

return 'Error Message: {}\n{}'.format(message, ''.join(error_messages))

def cc_radar(self, issue, block=False, timeout=None):
def cc_radar(self, issue, block=False, timeout=None, radar=None):
sys.stderr.write('No radar CC implemented for GitHub Issues\n')
return None
4 changes: 2 additions & 2 deletions Tools/Scripts/libraries/webkitbugspy/webkitbugspy/issue.py
Expand Up @@ -194,8 +194,8 @@ def redacted(self):
def set_component(self, project=None, component=None, version=None):
return self.tracker.set(self, project=project, component=component, version=version)

def cc_radar(self, block=False, timeout=None):
return self.tracker.cc_radar(self, block=block, timeout=timeout)
def cc_radar(self, block=False, timeout=None, radar=None):
return self.tracker.cc_radar(self, block=block, timeout=timeout, radar=radar)

def __hash__(self):
return hash(self.link)
Expand Down
Expand Up @@ -155,11 +155,10 @@ def _issue(self, url, id, credentials=None, data=None):
if not candidate:
continue
issue['watchers'].append(candidate)
if 'Radar' not in candidate.name or 'Bug Importer' not in candidate.name:
if 'Radar' not in candidate.name or 'Bug Importer' not in candidate.name or 'InRadar' in data.get('keywords', {}).get('add', []):
continue
radar_id = issue['id']
if RadarMock.top:
print('Ugh, this is the problem')
radar_id = RadarMock.top.add(dict(
title='{} ({})'.format(issue['description'], issue['id']),
timestamp=time.time(),
Expand Down
2 changes: 1 addition & 1 deletion Tools/Scripts/libraries/webkitbugspy/webkitbugspy/radar.py
Expand Up @@ -456,6 +456,6 @@ def create(
result.assign(self.me())
return result

def cc_radar(self, issue, block=False, timeout=None):
def cc_radar(self, issue, block=False, timeout=None, radar=None):
# cc-ing radar is a no-op for radar
return issue
Expand Up @@ -480,3 +480,22 @@ def test_cc_with_radarclient(self):
self.assertEqual(len(issue.references), 1)
self.assertEqual(issue.references[0].link, '<rdar://4>')
self.assertEqual(issue.references[0].title, 'An example issue for testing (1)')

def test_cc_existing_radar(self):
with OutputCapture(level=logging.INFO), mocks.Bugzilla(self.URL.split('://')[1], environment=wkmocks.Environment(
BUGS_EXAMPLE_COM_USERNAME='tcontributor@example.com',
BUGS_EXAMPLE_COM_PASSWORD='password',
), users=mocks.USERS, issues=mocks.ISSUES, projects=mocks.PROJECTS), mocks.Radar(
users=mocks.USERS, issues=mocks.ISSUES, projects=mocks.PROJECTS,
), wkmocks.Time:
radar_tracker = radar.Tracker()
bugzilla_tracker = bugzilla.Tracker(self.URL, radar_importer=mocks.USERS['Radar WebKit Bug Importer'])

with patch('webkitbugspy.Tracker._trackers', [radar_tracker, bugzilla_tracker]):
issue = bugzilla_tracker.issue(1)
self.assertEqual(issue.references, [])
self.assertIsNotNone(issue.cc_radar(block=True, radar=Tracker.from_string('<rdar://1>')))
self.assertEqual(issue.comments[-1].content, '<rdar://problem/1>')
self.assertEqual(len(issue.references), 1)
self.assertEqual(issue.references[0].link, '<rdar://1>')
self.assertEqual(issue.references[0].title, 'Example issue 1')
Expand Up @@ -142,5 +142,5 @@ def projects(self):
def create(self, title, description, **kwargs):
raise NotImplementedError()

def cc_radar(self, issue, block=False, timeout=None):
def cc_radar(self, issue, block=False, timeout=None, radar=None):
raise NotImplementedError()
2 changes: 1 addition & 1 deletion Tools/Scripts/libraries/webkitscmpy/setup.py
Expand Up @@ -29,7 +29,7 @@ def readme():

setup(
name='webkitscmpy',
version='5.6.4',
version='5.6.5',
description='Library designed to interact with git and svn repositories.',
long_description=readme(),
classifiers=[
Expand Down
Expand Up @@ -46,7 +46,7 @@ def _maybe_add_webkitcorepy_path():
"Please install webkitcorepy with `pip install webkitcorepy --extra-index-url <package index URL>`"
)

version = Version(5, 6, 4)
version = Version(5, 6, 5)

AutoInstall.register(Package('fasteners', Version(0, 15, 0)))
AutoInstall.register(Package('jinja2', Version(2, 11, 3)))
Expand Down
27 changes: 22 additions & 5 deletions Tools/Scripts/libraries/webkitscmpy/webkitscmpy/program/branch.py
Expand Up @@ -138,11 +138,28 @@ def main(cls, args, repository, why=None, redact=False, **kwargs):
else:
log.warning("'{}' has no spaces, assuming user intends it to be a branch name".format(args.issue))

if issue:
for tracker in Tracker._trackers:
if isinstance(tracker, radar.Tracker) and tracker.radarclient():
issue.cc_radar(block=True)
break
needs_radar = issue and not isinstance(issue.tracker, radar.Tracker)
needs_radar = needs_radar and any([
isinstance(tracker, radar.Tracker) and tracker.radarclient()
for tracker in Tracker._trackers
])
needs_radar = needs_radar and not any([
isinstance(reference.tracker, radar.Tracker)
for reference in issue.references
])

if needs_radar:
rdar = None
if not getattr(args, 'defaults', None):
sys.stdout.write('Existing radar to CC (leave empty to create new radar)')
sys.stdout.flush()
input = Terminal.input(': ')
if re.match(r'\d+', input):
input = '<rdar://problem/{}>'.format(input)
rdar = Tracker.from_string(input)
issue.cc_radar(block=True, radar=rdar)

if issue and not isinstance(issue.tracker, radar.Tracker):
args._title = issue.title
args._bug_urls = Commit.bug_urls(issue)

Expand Down
Expand Up @@ -24,7 +24,7 @@
import os

from mock import patch
from webkitbugspy import bugzilla, mocks as bmocks, radar
from webkitbugspy import bugzilla, mocks as bmocks, radar, Tracker
from webkitcorepy import OutputCapture, testing, mocks as wkmocks
from webkitcorepy.mocks import Time as MockTime, Terminal as MockTerminal, Environment
from webkitscmpy import local, program, mocks, log
Expand Down Expand Up @@ -98,6 +98,108 @@ def test_prompt_url(self):
self.assertEqual(captured.root.log.getvalue(), "Creating the local development branch 'eng/Example-feature-1'...\n")
self.assertEqual(captured.stdout.getvalue(), "Enter issue URL or title of new issue: \nCreated the local development branch 'eng/Example-feature-1'\n")

def test_automatic_radar_cc(self):
with MockTerminal.input('{}/show_bug.cgi?id=2'.format(self.BUGZILLA), ''), OutputCapture(level=logging.INFO) as captured, mocks.local.Git(self.path), bmocks.Bugzilla(
self.BUGZILLA.split('://')[-1],
issues=bmocks.ISSUES,
projects=bmocks.PROJECTS,
users=bmocks.USERS,
environment=Environment(
BUGS_EXAMPLE_COM_USERNAME='tcontributor@example.com',
BUGS_EXAMPLE_COM_PASSWORD='password',
),
), bmocks.Radar(issues=bmocks.ISSUES), patch('webkitbugspy.Tracker._trackers', [
bugzilla.Tracker(self.BUGZILLA, radar_importer=bmocks.USERS['Radar WebKit Bug Importer']),
radar.Tracker(),
]), mocks.local.Svn(), MockTime:
self.assertEqual(0, program.main(args=('branch', '-v'), path=self.path))
self.assertEqual(local.Git(self.path).branch, 'eng/Example-feature-1')

issue = Tracker.from_string('{}/show_bug.cgi?id=2'.format(self.BUGZILLA))
self.assertEqual(len(issue.references), 2)
self.assertEqual(issue.references[0].link, '<rdar://4>')
self.assertEqual(issue.comments[-1].content, '<rdar://problem/4>')

self.assertEqual(
captured.root.log.getvalue(),
"CCing Radar WebKit Bug Importer\n"
"Creating the local development branch 'eng/Example-feature-1'...\n",
)
self.assertEqual(
captured.stdout.getvalue(),
"Enter issue URL or title of new issue: \n"
"Existing radar to CC (leave empty to create new radar): \n"
"Created the local development branch 'eng/Example-feature-1'\n",
)

def test_manual_radar_cc(self):
with MockTerminal.input('{}/show_bug.cgi?id=2'.format(self.BUGZILLA), '<rdar://4>'), OutputCapture(level=logging.INFO) as captured, mocks.local.Git(self.path), bmocks.Bugzilla(
self.BUGZILLA.split('://')[-1],
issues=bmocks.ISSUES,
projects=bmocks.PROJECTS,
users=bmocks.USERS,
environment=Environment(
BUGS_EXAMPLE_COM_USERNAME='tcontributor@example.com',
BUGS_EXAMPLE_COM_PASSWORD='password',
),
), bmocks.Radar(issues=bmocks.ISSUES), patch('webkitbugspy.Tracker._trackers', [
bugzilla.Tracker(self.BUGZILLA, radar_importer=bmocks.USERS['Radar WebKit Bug Importer']),
radar.Tracker(),
]), mocks.local.Svn(), MockTime:
self.assertEqual(0, program.main(args=('branch', '-v'), path=self.path))
self.assertEqual(local.Git(self.path).branch, 'eng/Example-feature-1')

issue = Tracker.from_string('{}/show_bug.cgi?id=2'.format(self.BUGZILLA))
self.assertEqual(len(issue.references), 2)
self.assertEqual(issue.references[0].link, '<rdar://2>')
self.assertEqual(issue.comments[-1].content, '<rdar://problem/2>')

self.assertEqual(
captured.root.log.getvalue(),
"CCing Radar WebKit Bug Importer\n"
"Creating the local development branch 'eng/Example-feature-1'...\n",
)
self.assertEqual(
captured.stdout.getvalue(),
"Enter issue URL or title of new issue: \n"
"Existing radar to CC (leave empty to create new radar): \n"
"Created the local development branch 'eng/Example-feature-1'\n",
)

def test_manual_radar_cc_integer(self):
with MockTerminal.input('{}/show_bug.cgi?id=2'.format(self.BUGZILLA), '4'), OutputCapture(level=logging.INFO) as captured, mocks.local.Git(self.path), bmocks.Bugzilla(
self.BUGZILLA.split('://')[-1],
issues=bmocks.ISSUES,
projects=bmocks.PROJECTS,
users=bmocks.USERS,
environment=Environment(
BUGS_EXAMPLE_COM_USERNAME='tcontributor@example.com',
BUGS_EXAMPLE_COM_PASSWORD='password',
),
), bmocks.Radar(issues=bmocks.ISSUES), patch('webkitbugspy.Tracker._trackers', [
bugzilla.Tracker(self.BUGZILLA, radar_importer=bmocks.USERS['Radar WebKit Bug Importer']),
radar.Tracker(),
]), mocks.local.Svn(), MockTime:
self.assertEqual(0, program.main(args=('branch', '-v'), path=self.path))
self.assertEqual(local.Git(self.path).branch, 'eng/Example-feature-1')

issue = Tracker.from_string('{}/show_bug.cgi?id=2'.format(self.BUGZILLA))
self.assertEqual(len(issue.references), 2)
self.assertEqual(issue.references[0].link, '<rdar://2>')
self.assertEqual(issue.comments[-1].content, '<rdar://problem/2>')

self.assertEqual(
captured.root.log.getvalue(),
"CCing Radar WebKit Bug Importer\n"
"Creating the local development branch 'eng/Example-feature-1'...\n",
)
self.assertEqual(
captured.stdout.getvalue(),
"Enter issue URL or title of new issue: \n"
"Existing radar to CC (leave empty to create new radar): \n"
"Created the local development branch 'eng/Example-feature-1'\n",
)

def test_redacted(self):
class MockOptions(object):
def __init__(self):
Expand Down

0 comments on commit 479d809

Please sign in to comment.