OLD | NEW |
---|---|
1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import collections | 5 import collections |
6 import urlparse | |
7 | |
8 from dashboard.services import gerrit_service | |
6 | 9 |
7 | 10 |
8 class Patch(collections.namedtuple('Patch', ('server', 'issue', 'patchset'))): | 11 def FromDict(data): |
9 """A patch in Rietveld.""" | 12 # If we have more Patch types in the future, we can loop |
10 # TODO: Support Gerrit. | 13 # through them all and try each one's FromDict() in turn. |
11 # https://github.com/catapult-project/catapult/issues/3599 | 14 return GerritPatch.FromDict(data) |
15 | |
16 | |
17 class GerritPatch(collections.namedtuple( | |
18 'GerritPatch', ('server', 'change', 'revision'))): | |
19 """A patch in Gerrit. | |
20 | |
21 change is a change ID of the format '<project>~<branch>~<Change-Id>' and | |
22 revision is a commit ID. Both are described in the Gerrit API documentation. | |
23 https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#ids | |
24 | |
25 They must be in a canonical format so we can look up builds precisely. | |
26 """ | |
12 | 27 |
13 def __str__(self): | 28 def __str__(self): |
14 return self.id_string | 29 return self.id_string |
15 | 30 |
16 @property | 31 @property |
17 def id_string(self): | 32 def id_string(self): |
18 return '%s/%d/%d' % (self.server, self.issue, self.patchset) | 33 return '%s/%s/%s' % (self.server, self.change, self.revision) |
34 | |
35 def BuildParameters(self): | |
36 patch_info = gerrit_service.GetChange( | |
37 self.server, self.change, fields=('ALL_REVISIONS',)) | |
38 revision_info = patch_info['revisions'][self.revision] | |
39 return { | |
40 'patch_gerrit_url': self.server, | |
41 'patch_issue': patch_info['_number'], | |
42 'patch_project': patch_info['project'], | |
43 'patch_ref': revision_info['fetch']['http']['ref'], | |
44 'patch_repository_url': revision_info['fetch']['http']['url'], | |
45 'patch_set': revision_info['_number'], | |
46 'patch_storage': 'gerrit', | |
47 } | |
19 | 48 |
20 def AsDict(self): | 49 def AsDict(self): |
21 return self._asdict() | 50 return self._asdict() |
22 | 51 |
23 @classmethod | 52 @classmethod |
24 def FromDict(cls, data): | 53 def FromDict(cls, data): |
25 # TODO: Validate to ensure the patch exists on the server. | 54 """Creates a new GerritPatch from the given data. |
26 return cls(data['server'], data['issue'], data['patchset']) | 55 |
56 Args: | |
57 data: A patch URL string, for example: | |
58 https://chromium-review.googlesource.com/c/chromium/tools/build/+/679595 | |
59 Or a dict containing {server, change, revision [optional]}. | |
60 change is a {change-id} as described in the Gerrit API documentation. | |
61 revision is a commit ID hash or numeric patch number. | |
62 If revision is omitted, it is the change's current revision. | |
63 | |
64 Returns: | |
65 A GerritPatch. | |
66 | |
67 Raises: | |
68 KeyError: The patch doesn't have the given revision. | |
69 """ | |
70 if isinstance(data, basestring): | |
71 url_parts = urlparse.urlparse(data) | |
72 server = urlparse.urlunsplit( | |
73 (url_parts.scheme, url_parts.netloc, '', '', '')) | |
74 change = url_parts.path.rsplit('/', 1)[-1] | |
75 revision = None | |
perezju
2017/09/26 09:15:47
how do we know to which repository should the patc
dtu
2017/09/26 20:00:23
As far as I can tell from the Gerrit doc, the nume
perezju
2017/09/27 08:21:47
Wow, had no idea. Ok, thanks for the explanation!
| |
76 else: | |
77 server = data['server'] | |
78 change = data['change'] | |
79 revision = data.get('revision') | |
80 | |
81 # Look up the patch and convert everything to a canonical format. | |
82 patch_info = gerrit_service.GetChange( | |
83 server, change, fields=('ALL_REVISIONS',)) | |
84 change = patch_info['id'] | |
85 | |
86 # Revision can be a revision ID or numeric patch number. | |
87 if not revision: | |
88 revision = patch_info['current_revision'] | |
89 for revision_id, revision_info in patch_info['revisions'].iteritems(): | |
90 if revision == revision_id or revision == revision_info['_number']: | |
91 revision = revision_id | |
92 break | |
93 else: | |
94 raise KeyError('Patch revision not found: %s/%s revision %s' % | |
95 (server, change, revision)) | |
96 | |
97 return cls(server, change, revision) | |
OLD | NEW |