Show More
@@ -138,28 +138,32 b' def getrepophid(repo):' | |||||
138 |
|
138 | |||
139 | _differentialrevisiontagre = re.compile('\AD([1-9][0-9]*)\Z') |
|
139 | _differentialrevisiontagre = re.compile('\AD([1-9][0-9]*)\Z') | |
140 | _differentialrevisiondescre = re.compile( |
|
140 | _differentialrevisiondescre = re.compile( | |
141 | '^Differential Revision:\s*(.*)D([1-9][0-9]*)$', re.M) |
|
141 | '^Differential Revision:\s*(?:.*)D([1-9][0-9]*)$', re.M) | |
142 |
|
142 | |||
143 | def getoldnodedrevmap(repo, nodelist): |
|
143 | def getoldnodedrevmap(repo, nodelist): | |
144 | """find previous nodes that has been sent to Phabricator |
|
144 | """find previous nodes that has been sent to Phabricator | |
145 |
|
145 | |||
146 |
return {node: (oldnode |
|
146 | return {node: (oldnode, Differential diff, Differential Revision ID)} | |
147 | for node in nodelist with known previous sent versions, or associated |
|
147 | for node in nodelist with known previous sent versions, or associated | |
148 | Differential Revision IDs. |
|
148 | Differential Revision IDs. ``oldnode`` and ``Differential diff`` could | |
|
149 | be ``None``. | |||
149 |
|
150 | |||
150 | Examines all precursors and their tags. Tags with format like "D1234" are |
|
151 | Examines commit messages like "Differential Revision:" to get the | |
151 | considered a match and the node with that tag, and the number after "D" |
|
152 | association information. | |
152 | (ex. 1234) will be returned. |
|
|||
153 |
|
153 | |||
154 | If tags are not found, examine commit message. The "Differential Revision:" |
|
154 | If such commit message line is not found, examines all precursors and their | |
155 | line could associate this changeset to a Differential Revision. |
|
155 | tags. Tags with format like "D1234" are considered a match and the node | |
|
156 | with that tag, and the number after "D" (ex. 1234) will be returned. | |||
|
157 | ||||
|
158 | The ``old node``, if not None, is guaranteed to be the last diff of | |||
|
159 | corresponding Differential Revision, and exist in the repo. | |||
156 | """ |
|
160 | """ | |
157 | url, token = readurltoken(repo) |
|
161 | url, token = readurltoken(repo) | |
158 | unfi = repo.unfiltered() |
|
162 | unfi = repo.unfiltered() | |
159 | nodemap = unfi.changelog.nodemap |
|
163 | nodemap = unfi.changelog.nodemap | |
160 |
|
164 | |||
161 |
result = {} # {node: (oldnode |
|
165 | result = {} # {node: (oldnode?, lastdiff?, drev)} | |
162 |
toconfirm = {} # {node: ( |
|
166 | toconfirm = {} # {node: (force, {precnode}, drev)} | |
163 | for node in nodelist: |
|
167 | for node in nodelist: | |
164 | ctx = unfi[node] |
|
168 | ctx = unfi[node] | |
165 | # For tags like "D123", put them into "toconfirm" to verify later |
|
169 | # For tags like "D123", put them into "toconfirm" to verify later | |
@@ -169,39 +173,49 b' def getoldnodedrevmap(repo, nodelist):' | |||||
169 | for tag in unfi.nodetags(n): |
|
173 | for tag in unfi.nodetags(n): | |
170 | m = _differentialrevisiontagre.match(tag) |
|
174 | m = _differentialrevisiontagre.match(tag) | |
171 | if m: |
|
175 | if m: | |
172 |
toconfirm[node] = ( |
|
176 | toconfirm[node] = (0, set(precnodes), int(m.group(1))) | |
173 | continue |
|
177 | continue | |
174 |
|
178 | |||
175 |
# Check commit message |
|
179 | # Check commit message | |
176 | m = _differentialrevisiondescre.search(ctx.description()) |
|
180 | m = _differentialrevisiondescre.search(ctx.description()) | |
177 | if m: |
|
181 | if m: | |
178 | if m.group(1).rstrip('/') == url.rstrip('/'): |
|
182 | toconfirm[node] = (1, set(precnodes), int(m.group(1))) | |
179 | result[node] = (None, int(m.group(2))) |
|
|||
180 | else: |
|
|||
181 | unfi.ui.warn(_('%s: Differential Revision URL ignored - host ' |
|
|||
182 | 'does not match config\n') % ctx) |
|
|||
183 |
|
183 | |||
184 | # Double check if tags are genuine by collecting all old nodes from |
|
184 | # Double check if tags are genuine by collecting all old nodes from | |
185 | # Phabricator, and expect precursors overlap with it. |
|
185 | # Phabricator, and expect precursors overlap with it. | |
186 | if toconfirm: |
|
186 | if toconfirm: | |
187 | confirmed = {} # {drev: {oldnode}} |
|
187 | drevs = [drev for force, precs, drev in toconfirm.values()] | |
188 | drevs = [drev for n, precs, drev in toconfirm.values()] |
|
188 | alldiffs = callconduit(unfi, 'differential.querydiffs', | |
189 | diffs = callconduit(unfi, 'differential.querydiffs', |
|
189 | {'revisionIDs': drevs}) | |
190 | {'revisionIDs': drevs}) |
|
190 | getnode = lambda d: bin(encoding.unitolocal( | |
191 | for diff in diffs.values(): |
|
191 | getdiffmeta(d).get(r'node', ''))) or None | |
192 | drev = int(diff[r'revisionID']) |
|
192 | for newnode, (force, precset, drev) in toconfirm.items(): | |
193 | oldnode = bin(encoding.unitolocal(getdiffmeta(diff).get(r'node'))) |
|
193 | diffs = [d for d in alldiffs.values() | |
194 | if node: |
|
194 | if int(d[r'revisionID']) == drev] | |
195 | confirmed.setdefault(drev, set()).add(oldnode) |
|
195 | ||
196 | for newnode, (oldnode, precset, drev) in toconfirm.items(): |
|
196 | # "precursors" as known by Phabricator | |
197 | if bool(precset & confirmed.get(drev, set())): |
|
197 | phprecset = set(getnode(d) for d in diffs) | |
198 | result[newnode] = (oldnode, drev) |
|
198 | ||
199 | else: |
|
199 | # Ignore if precursors (Phabricator and local repo) do not overlap, | |
|
200 | # and force is not set (when commit message says nothing) | |||
|
201 | if not force and not bool(phprecset & precset): | |||
200 | tagname = 'D%d' % drev |
|
202 | tagname = 'D%d' % drev | |
201 | tags.tag(repo, tagname, nullid, message=None, user=None, |
|
203 | tags.tag(repo, tagname, nullid, message=None, user=None, | |
202 | date=None, local=True) |
|
204 | date=None, local=True) | |
203 | unfi.ui.warn(_('D%s: local tag removed - does not match ' |
|
205 | unfi.ui.warn(_('D%s: local tag removed - does not match ' | |
204 | 'Differential history\n') % drev) |
|
206 | 'Differential history\n') % drev) | |
|
207 | continue | |||
|
208 | ||||
|
209 | # Find the last node using Phabricator metadata, and make sure it | |||
|
210 | # exists in the repo | |||
|
211 | oldnode = lastdiff = None | |||
|
212 | if diffs: | |||
|
213 | lastdiff = max(diffs, key=lambda d: int(d[r'id'])) | |||
|
214 | oldnode = getnode(lastdiff) | |||
|
215 | if oldnode and oldnode not in nodemap: | |||
|
216 | oldnode = None | |||
|
217 | ||||
|
218 | result[newnode] = (oldnode, lastdiff, drev) | |||
205 |
|
219 | |||
206 | return result |
|
220 | return result | |
207 |
|
221 | |||
@@ -354,7 +368,8 b' def phabsend(ui, repo, *revs, **opts):' | |||||
354 | phids = userphids(repo, reviewers) |
|
368 | phids = userphids(repo, reviewers) | |
355 | actions.append({'type': 'reviewers.add', 'value': phids}) |
|
369 | actions.append({'type': 'reviewers.add', 'value': phids}) | |
356 |
|
370 | |||
357 | oldnodedrev = getoldnodedrevmap(repo, [repo[r].node() for r in revs]) |
|
371 | # {newnode: (oldnode, olddiff, olddrev} | |
|
372 | oldmap = getoldnodedrevmap(repo, [repo[r].node() for r in revs]) | |||
358 |
|
373 | |||
359 | # Send patches one by one so we know their Differential Revision IDs and |
|
374 | # Send patches one by one so we know their Differential Revision IDs and | |
360 | # can provide dependency relationship |
|
375 | # can provide dependency relationship | |
@@ -364,7 +379,7 b' def phabsend(ui, repo, *revs, **opts):' | |||||
364 | ctx = repo[rev] |
|
379 | ctx = repo[rev] | |
365 |
|
380 | |||
366 | # Get Differential Revision ID |
|
381 | # Get Differential Revision ID | |
367 |
oldnode, revid = old |
|
382 | oldnode, olddiff, revid = oldmap.get(ctx.node(), (None, None, None)) | |
368 | if oldnode != ctx.node(): |
|
383 | if oldnode != ctx.node(): | |
369 | # Create or update Differential Revision |
|
384 | # Create or update Differential Revision | |
370 | revision = createdifferentialrevision(ctx, revid, lastrevid, |
|
385 | revision = createdifferentialrevision(ctx, revid, lastrevid, |
General Comments 0
You need to be logged in to leave comments.
Login now