Merge lp:~jelmer/brz/tag-selector into lp:brz/3.1

Proposed by Jelmer Vernooij
Status: Merged
Approved by: Jelmer Vernooij
Approved revision: no longer in the source branch.
Merge reported by: The Breezy Bot
Merged at revision: not available
Proposed branch: lp:~jelmer/brz/tag-selector
Merge into: lp:brz/3.1
Diff against target: 1290 lines (+266/-129)
23 files modified
breezy/branch.py (+42/-26)
breezy/bzr/branch.py (+1/-1)
breezy/bzr/bzrdir.py (+4/-2)
breezy/bzr/remote.py (+2/-2)
breezy/controldir.py (+15/-8)
breezy/git/branch.py (+55/-33)
breezy/git/dir.py (+5/-4)
breezy/git/interrepo.py (+12/-6)
breezy/git/workingtree.py (+2/-2)
breezy/plugins/propose/github.py (+4/-3)
breezy/plugins/propose/gitlabs.py (+3/-3)
breezy/plugins/propose/launchpad.py (+15/-11)
breezy/plugins/weave_fmt/bzrdir.py (+2/-2)
breezy/propose.py (+1/-1)
breezy/tag.py (+21/-20)
breezy/tests/per_branch/test_pull.py (+1/-1)
breezy/tests/per_branch/test_tags.py (+15/-0)
breezy/tests/per_controldir/test_push.py (+11/-0)
breezy/tests/per_interbranch/test_pull.py (+21/-1)
breezy/tests/per_interbranch/test_push.py (+20/-0)
breezy/tests/test_foreign.py (+1/-1)
breezy/tests/test_tag.py (+11/-0)
breezy/workingtree.py (+2/-2)
To merge this branch: bzr merge lp:~jelmer/brz/tag-selector
Reviewer Review Type Date Requested Status
Jelmer Vernooij Approve
Review via email: mp+379435@code.launchpad.net

Commit message

Add a tag_selector argument to push/pull/sprout functions.

Description of the change

Add a tag_selector argument to push/pull/sprout functions.

To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) :
review: Approve
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'breezy/branch.py'
2--- breezy/branch.py 2020-01-20 00:03:54 +0000
3+++ breezy/branch.py 2020-02-19 23:22:37 +0000
4@@ -1194,7 +1194,8 @@
5 if revno < 1 or revno > self.revno():
6 raise errors.InvalidRevisionNumber(revno)
7
8- def clone(self, to_controldir, revision_id=None, repository_policy=None):
9+ def clone(self, to_controldir, revision_id=None, repository_policy=None,
10+ tag_selector=None):
11 """Clone this branch into to_controldir preserving all semantic values.
12
13 Most API users will want 'create_clone_on_transport', which creates a
14@@ -1207,11 +1208,12 @@
15 with self.lock_read(), result.lock_write():
16 if repository_policy is not None:
17 repository_policy.configure_branch(result)
18- self.copy_content_into(result, revision_id=revision_id)
19+ self.copy_content_into(
20+ result, revision_id=revision_id, tag_selector=tag_selector)
21 return result
22
23 def sprout(self, to_controldir, revision_id=None, repository_policy=None,
24- repository=None, lossy=False):
25+ repository=None, lossy=False, tag_selector=None):
26 """Create a new line of development from the branch, into to_controldir.
27
28 to_controldir controls the branch format.
29@@ -1228,7 +1230,8 @@
30 with self.lock_read(), result.lock_write():
31 if repository_policy is not None:
32 repository_policy.configure_branch(result)
33- self.copy_content_into(result, revision_id=revision_id)
34+ self.copy_content_into(
35+ result, revision_id=revision_id, tag_selector=tag_selector)
36 master_url = self.get_bound_location()
37 if master_url is None:
38 result.set_parent(self.user_url)
39@@ -1261,14 +1264,16 @@
40 revno = 1
41 destination.set_last_revision_info(revno, revision_id)
42
43- def copy_content_into(self, destination, revision_id=None):
44+ def copy_content_into(self, destination, revision_id=None, tag_selector=None):
45 """Copy the content of self into destination.
46
47 revision_id: if not None, the revision history in the new branch will
48 be truncated to end with revision_id.
49+ tag_selector: Optional callback that receives a tag name
50+ and should return a boolean to indicate whether a tag should be copied
51 """
52 return InterBranch.get(self, destination).copy_content_into(
53- revision_id=revision_id)
54+ revision_id=revision_id, tag_selector=tag_selector)
55
56 def update_references(self, target):
57 if not self._format.supports_reference_locations:
58@@ -1313,7 +1318,8 @@
59
60 def create_clone_on_transport(self, to_transport, revision_id=None,
61 stacked_on=None, create_prefix=False,
62- use_existing_dir=False, no_tree=None):
63+ use_existing_dir=False, no_tree=None,
64+ tag_selector=None):
65 """Create a clone of this branch and its bzrdir.
66
67 :param to_transport: The transport to clone onto.
68@@ -1333,7 +1339,7 @@
69 dir_to = self.controldir.clone_on_transport(
70 to_transport, revision_id=revision_id, stacked_on=stacked_on,
71 create_prefix=create_prefix, use_existing_dir=use_existing_dir,
72- no_tree=no_tree)
73+ no_tree=no_tree, tag_selector=tag_selector)
74 return dir_to.open_branch()
75
76 def create_checkout(self, to_location, revision_id=None,
77@@ -2060,7 +2066,7 @@
78 raise NotImplementedError(klass._get_branch_formats_to_test)
79
80 def pull(self, overwrite=False, stop_revision=None,
81- possible_transports=None, local=False):
82+ possible_transports=None, local=False, tag_selector=None):
83 """Mirror source into target branch.
84
85 The target branch is considered to be 'local', having low latency.
86@@ -2070,18 +2076,21 @@
87 raise NotImplementedError(self.pull)
88
89 def push(self, overwrite=False, stop_revision=None, lossy=False,
90- _override_hook_source_branch=None):
91+ _override_hook_source_branch=None, tag_selector=None):
92 """Mirror the source branch into the target branch.
93
94 The source branch is considered to be 'local', having low latency.
95 """
96 raise NotImplementedError(self.push)
97
98- def copy_content_into(self, revision_id=None):
99+ def copy_content_into(self, revision_id=None, tag_selector=None):
100 """Copy the content of source into target
101
102- revision_id: if not None, the revision history in the new branch will
103- be truncated to end with revision_id.
104+ :param revision_id:
105+ if not None, the revision history in the new branch will
106+ be truncated to end with revision_id.
107+ :param tag_selector: Optional callback that can decide
108+ to copy or not copy tags.
109 """
110 raise NotImplementedError(self.copy_content_into)
111
112@@ -2128,7 +2137,7 @@
113 return format._custom_format
114 return format
115
116- def copy_content_into(self, revision_id=None):
117+ def copy_content_into(self, revision_id=None, tag_selector=None):
118 """Copy the content of source into target
119
120 revision_id: if not None, the revision history in the new branch will
121@@ -2145,7 +2154,7 @@
122 if parent:
123 self.target.set_parent(parent)
124 if self.source._push_should_merge_tags():
125- self.source.tags.merge_to(self.target.tags)
126+ self.source.tags.merge_to(self.target.tags, selector=tag_selector)
127
128 def fetch(self, stop_revision=None, limit=None, lossy=False):
129 if self.target.base == self.source.base:
130@@ -2206,7 +2215,8 @@
131
132 def pull(self, overwrite=False, stop_revision=None,
133 possible_transports=None, run_hooks=True,
134- _override_hook_target=None, local=False):
135+ _override_hook_target=None, local=False,
136+ tag_selector=None):
137 """Pull from source into self, updating my master if any.
138
139 :param run_hooks: Private parameter - if false, this branch
140@@ -2237,15 +2247,17 @@
141 if master_branch:
142 # pull from source into master.
143 master_branch.pull(
144- self.source, overwrite, stop_revision, run_hooks=False)
145+ self.source, overwrite, stop_revision, run_hooks=False,
146+ tag_selector=tag_selector)
147 return self._pull(
148 overwrite, stop_revision, _hook_master=master_branch,
149 run_hooks=run_hooks,
150 _override_hook_target=_override_hook_target,
151- merge_tags_to_master=not source_is_master)
152+ merge_tags_to_master=not source_is_master,
153+ tag_selector=tag_selector)
154
155 def push(self, overwrite=False, stop_revision=None, lossy=False,
156- _override_hook_source_branch=None):
157+ _override_hook_source_branch=None, tag_selector=None):
158 """See InterBranch.push.
159
160 This is the basic concrete implementation of push()
161@@ -2277,18 +2289,21 @@
162 with master_branch.lock_write():
163 # push into the master from the source branch.
164 master_inter = InterBranch.get(self.source, master_branch)
165- master_inter._basic_push(overwrite, stop_revision)
166+ master_inter._basic_push(
167+ overwrite, stop_revision, tag_selector=tag_selector)
168 # and push into the target branch from the source. Note
169 # that we push from the source branch again, because it's
170 # considered the highest bandwidth repository.
171- result = self._basic_push(overwrite, stop_revision)
172+ result = self._basic_push(
173+ overwrite, stop_revision, tag_selector=tag_selector)
174 result.master_branch = master_branch
175 result.local_branch = self.target
176 _run_hooks()
177 else:
178 master_branch = None
179 # no master branch
180- result = self._basic_push(overwrite, stop_revision)
181+ result = self._basic_push(
182+ overwrite, stop_revision, tag_selector=tag_selector)
183 # TODO: Why set master_branch and local_branch if there's no
184 # binding? Maybe cleaner to just leave them unset? -- mbp
185 # 20070504
186@@ -2297,7 +2312,7 @@
187 _run_hooks()
188 return result
189
190- def _basic_push(self, overwrite, stop_revision):
191+ def _basic_push(self, overwrite, stop_revision, tag_selector=None):
192 """Basic implementation of push without bound branches or hooks.
193
194 Must be called with source read locked and target write locked.
195@@ -2316,7 +2331,7 @@
196 if self.source._push_should_merge_tags():
197 result.tag_updates, result.tag_conflicts = (
198 self.source.tags.merge_to(
199- self.target.tags, "tags" in overwrite))
200+ self.target.tags, "tags" in overwrite, selector=tag_selector))
201 self.update_references()
202 result.new_revno, result.new_revid = self.target.last_revision_info()
203 return result
204@@ -2324,7 +2339,7 @@
205 def _pull(self, overwrite=False, stop_revision=None,
206 possible_transports=None, _hook_master=None, run_hooks=True,
207 _override_hook_target=None, local=False,
208- merge_tags_to_master=True):
209+ merge_tags_to_master=True, tag_selector=None):
210 """See Branch.pull.
211
212 This function is the core worker, used by GenericInterBranch.pull to
213@@ -2368,7 +2383,8 @@
214 result.tag_updates, result.tag_conflicts = (
215 self.source.tags.merge_to(
216 self.target.tags, "tags" in overwrite,
217- ignore_master=not merge_tags_to_master))
218+ ignore_master=not merge_tags_to_master,
219+ selector=tag_selector))
220 self.update_references()
221 result.new_revno, result.new_revid = (
222 self.target.last_revision_info())
223
224=== modified file 'breezy/bzr/branch.py'
225--- breezy/bzr/branch.py 2020-02-18 01:32:25 +0000
226+++ breezy/bzr/branch.py 2020-02-19 23:22:37 +0000
227@@ -1033,7 +1033,7 @@
228 def _make_reference_clone_function(format, a_branch):
229 """Create a clone() routine for a branch dynamically."""
230 def clone(to_bzrdir, revision_id=None,
231- repository_policy=None):
232+ repository_policy=None, tag_selector=None):
233 """See Branch.clone()."""
234 return format.initialize(to_bzrdir, target_branch=a_branch)
235 # cannot obey revision_id limits when cloning a reference ...
236
237=== modified file 'breezy/bzr/bzrdir.py'
238--- breezy/bzr/bzrdir.py 2020-01-19 01:29:22 +0000
239+++ breezy/bzr/bzrdir.py 2020-02-19 23:22:37 +0000
240@@ -143,7 +143,8 @@
241
242 def clone_on_transport(self, transport, revision_id=None,
243 force_new_repo=False, preserve_stacking=False, stacked_on=None,
244- create_prefix=False, use_existing_dir=True, no_tree=False):
245+ create_prefix=False, use_existing_dir=True, no_tree=False,
246+ tag_selector=None):
247 """Clone this bzrdir and its contents to transport verbatim.
248
249 :param transport: The transport for the location to produce the clone
250@@ -235,7 +236,8 @@
251 if local_branch is not None:
252 local_branch.clone(
253 result, revision_id=revision_id,
254- repository_policy=repository_policy)
255+ repository_policy=repository_policy,
256+ tag_selector=tag_selector)
257 try:
258 # Cheaper to check if the target is not local, than to try making
259 # the tree and fail.
260
261=== modified file 'breezy/bzr/remote.py'
262--- breezy/bzr/remote.py 2020-02-09 01:16:06 +0000
263+++ breezy/bzr/remote.py 2020-02-19 23:22:37 +0000
264@@ -4033,12 +4033,12 @@
265 source, overwrite=overwrite, stop_revision=stop_revision,
266 _override_hook_target=self, **kwargs)
267
268- def push(self, target, overwrite=False, stop_revision=None, lossy=False):
269+ def push(self, target, overwrite=False, stop_revision=None, lossy=False, tag_selector=None):
270 with self.lock_read():
271 self._ensure_real()
272 return self._real_branch.push(
273 target, overwrite=overwrite, stop_revision=stop_revision, lossy=lossy,
274- _override_hook_source_branch=self)
275+ _override_hook_source_branch=self, tag_selector=tag_selector)
276
277 def peek_lock_mode(self):
278 return self._lock_mode
279
280=== modified file 'breezy/controldir.py'
281--- breezy/controldir.py 2019-11-06 01:31:41 +0000
282+++ breezy/controldir.py 2020-02-19 23:22:37 +0000
283@@ -400,7 +400,8 @@
284 raise NotImplementedError(self.sprout)
285
286 def push_branch(self, source, revision_id=None, overwrite=False,
287- remember=False, create_prefix=False, lossy=False):
288+ remember=False, create_prefix=False, lossy=False,
289+ tag_selector=None):
290 """Push the source branch into this ControlDir."""
291 br_to = None
292 # If we can open a branch, use its direct repository, otherwise see
293@@ -424,7 +425,9 @@
294 # revision
295 revision_id = source.last_revision()
296 repository_to.fetch(source.repository, revision_id=revision_id)
297- br_to = source.sprout(self, revision_id=revision_id, lossy=lossy)
298+ br_to = source.sprout(
299+ self, revision_id=revision_id, lossy=lossy,
300+ tag_selector=tag_selector)
301 if source.get_push_location() is None or remember:
302 # FIXME: Should be done only if we succeed ? -- vila 2012-01-18
303 source.set_push_location(br_to.base)
304@@ -444,17 +447,19 @@
305 tree_to = self.open_workingtree()
306 except errors.NotLocalUrl:
307 push_result.branch_push_result = source.push(
308- br_to, overwrite, stop_revision=revision_id, lossy=lossy)
309+ br_to, overwrite, stop_revision=revision_id, lossy=lossy,
310+ tag_selector=tag_selector)
311 push_result.workingtree_updated = False
312 except errors.NoWorkingTree:
313 push_result.branch_push_result = source.push(
314- br_to, overwrite, stop_revision=revision_id, lossy=lossy)
315+ br_to, overwrite, stop_revision=revision_id, lossy=lossy,
316+ tag_selector=tag_selector)
317 push_result.workingtree_updated = None # Not applicable
318 else:
319 with tree_to.lock_write():
320 push_result.branch_push_result = source.push(
321 tree_to.branch, overwrite, stop_revision=revision_id,
322- lossy=lossy)
323+ lossy=lossy, tag_selector=tag_selector)
324 tree_to.update()
325 push_result.workingtree_updated = True
326 push_result.old_revno = push_result.branch_push_result.old_revno
327@@ -493,7 +498,7 @@
328 raise NotImplementedError(self.check_conversion_target)
329
330 def clone(self, url, revision_id=None, force_new_repo=False,
331- preserve_stacking=False):
332+ preserve_stacking=False, tag_selector=None):
333 """Clone this controldir and its contents to url verbatim.
334
335 :param url: The url create the clone at. If url's last component does
336@@ -509,11 +514,13 @@
337 return self.clone_on_transport(_mod_transport.get_transport(url),
338 revision_id=revision_id,
339 force_new_repo=force_new_repo,
340- preserve_stacking=preserve_stacking)
341+ preserve_stacking=preserve_stacking,
342+ tag_selector=tag_selector)
343
344 def clone_on_transport(self, transport, revision_id=None,
345 force_new_repo=False, preserve_stacking=False, stacked_on=None,
346- create_prefix=False, use_existing_dir=True, no_tree=False):
347+ create_prefix=False, use_existing_dir=True, no_tree=False,
348+ tag_selector=None):
349 """Clone this controldir and its contents to transport verbatim.
350
351 :param transport: The transport for the location to produce the clone
352
353=== modified file 'breezy/git/branch.py'
354--- breezy/git/branch.py 2020-02-18 01:27:12 +0000
355+++ breezy/git/branch.py 2020-02-19 23:22:37 +0000
356@@ -131,7 +131,7 @@
357 return False
358 return True
359
360- def merge(self, overwrite=False, ignore_master=False):
361+ def merge(self, overwrite=False, ignore_master=False, selector=None):
362 if self.source.branch.repository.has_same_location(self.target.branch.repository):
363 return {}, []
364 updates = {}
365@@ -142,6 +142,8 @@
366 ret = dict(old_refs)
367 for ref_name, tag_name, peeled, unpeeled in (
368 source_tag_refs.iteritems()):
369+ if selector and not selector(tag_name):
370+ continue
371 if old_refs.get(ref_name) == unpeeled:
372 pass
373 elif overwrite or ref_name not in old_refs:
374@@ -158,7 +160,7 @@
375 return ret
376 self.target.branch.repository.controldir.send_pack(
377 get_changed_refs, lambda have, want: [])
378- return updates, conflicts
379+ return updates, set(conflicts)
380
381
382 class InterTagsFromGitToLocalGit(InterTags):
383@@ -173,7 +175,7 @@
384 return False
385 return True
386
387- def merge(self, overwrite=False, ignore_master=False):
388+ def merge(self, overwrite=False, ignore_master=False, selector=None):
389 if self.source.branch.repository.has_same_location(self.target.branch.repository):
390 return {}, []
391
392@@ -184,6 +186,8 @@
393 target_repo = self.target.branch.repository
394
395 for ref_name, tag_name, peeled, unpeeled in source_tag_refs:
396+ if selector and not selector(tag_name):
397+ continue
398 if target_repo._git.refs.get(ref_name) == unpeeled:
399 pass
400 elif overwrite or ref_name not in target_repo._git.refs:
401@@ -215,7 +219,7 @@
402 tag_name)
403 continue
404 conflicts.append((tag_name, source_revid, target_revid))
405- return updates, conflicts
406+ return updates, set(conflicts)
407
408
409 class InterTagsFromGitToNonGit(InterTags):
410@@ -228,7 +232,7 @@
411 return False
412 return True
413
414- def merge(self, overwrite=False, ignore_master=False):
415+ def merge(self, overwrite=False, ignore_master=False, selector=None):
416 """See Tags.merge_to."""
417 source_tag_refs = self.source.branch.get_tag_refs()
418 if ignore_master:
419@@ -239,22 +243,26 @@
420 if master is not None:
421 es.enter_context(master.lock_write())
422 updates, conflicts = self._merge_to(
423- self.target, source_tag_refs, overwrite=overwrite)
424+ self.target, source_tag_refs, overwrite=overwrite,
425+ selector=selector)
426 if master is not None:
427 extra_updates, extra_conflicts = self._merge_to(
428 master.tags, overwrite=overwrite,
429 source_tag_refs=source_tag_refs,
430- ignore_master=ignore_master)
431+ ignore_master=ignore_master, selector=selector)
432 updates.update(extra_updates)
433- conflicts += extra_conflicts
434+ conflicts.update(extra_conflicts)
435 return updates, conflicts
436
437- def _merge_to(self, to_tags, source_tag_refs, overwrite=False):
438+ def _merge_to(self, to_tags, source_tag_refs, overwrite=False,
439+ selector=None):
440 unpeeled_map = defaultdict(set)
441 conflicts = []
442 updates = {}
443 result = dict(to_tags.get_tag_dict())
444 for ref_name, tag_name, peeled, unpeeled in source_tag_refs:
445+ if selector and not selector(tag_name):
446+ continue
447 if unpeeled is not None:
448 unpeeled_map[peeled].add(unpeeled)
449 try:
450@@ -273,7 +281,7 @@
451 map_file = UnpeelMap.from_repository(to_tags.branch.repository)
452 map_file.update(unpeeled_map)
453 map_file.save_in_repository(to_tags.branch.repository)
454- return updates, conflicts
455+ return updates, set(conflicts)
456
457
458 InterTags.register_optimiser(InterTagsFromGitToRemoteGit)
459@@ -659,9 +667,10 @@
460 return revision.NULL_REVISION
461 return self.lookup_foreign_revision_id(self.head)
462
463- def _basic_push(self, target, overwrite=False, stop_revision=None):
464+ def _basic_push(self, target, overwrite=False, stop_revision=None,
465+ tag_selector=None):
466 return branch.InterBranch.get(self, target)._basic_push(
467- overwrite, stop_revision)
468+ overwrite, stop_revision, tag_selector=tag_selector)
469
470 def lookup_foreign_revision_id(self, foreign_revid):
471 try:
472@@ -981,7 +990,7 @@
473 stop_revision, fetch_tags=fetch_tags, limit=limit, lossy=lossy)
474 return _mod_repository.FetchResult()
475
476- def fetch_objects(self, stop_revision, fetch_tags, limit=None, lossy=False):
477+ def fetch_objects(self, stop_revision, fetch_tags, limit=None, lossy=False, tag_selector=None):
478 interrepo = self._get_interrepo(self.source, self.target)
479 if fetch_tags is None:
480 c = self.source.get_config_stack()
481@@ -999,7 +1008,7 @@
482 else:
483 self._last_revid = stop_revision
484 real = interrepo.get_determine_wants_revids(
485- [self._last_revid], include_tags=fetch_tags)
486+ [self._last_revid], include_tags=fetch_tags, tag_selector=tag_selector)
487 return real(heads)
488 pack_hint, head, refs = interrepo.fetch_objects(
489 determine_wants, self.source.mapping, limit=limit,
490@@ -1009,8 +1018,8 @@
491 self.target.repository.pack(hint=pack_hint)
492 return head, refs
493
494- def _update_revisions(self, stop_revision=None, overwrite=False):
495- head, refs = self.fetch_objects(stop_revision, fetch_tags=None)
496+ def _update_revisions(self, stop_revision=None, overwrite=False, tag_selector=None):
497+ head, refs = self.fetch_objects(stop_revision, fetch_tags=None, tag_selector=tag_selector)
498 if overwrite:
499 prev_last_revid = None
500 else:
501@@ -1035,7 +1044,7 @@
502 pass
503
504 def _basic_pull(self, stop_revision, overwrite, run_hooks,
505- _override_hook_target, _hook_master):
506+ _override_hook_target, _hook_master, tag_selector=None):
507 if overwrite is True:
508 overwrite = set(["history", "tags"])
509 elif not overwrite:
510@@ -1052,7 +1061,8 @@
511 (result.old_revno, result.old_revid) = \
512 self.target.last_revision_info()
513 result.new_git_head, remote_refs = self._update_revisions(
514- stop_revision, overwrite=("history" in overwrite))
515+ stop_revision, overwrite=("history" in overwrite),
516+ tag_selector=tag_selector)
517 tags_ret = self.source.tags.merge_to(
518 self.target.tags, ("tags" in overwrite), ignore_master=True)
519 if isinstance(tags_ret, tuple):
520@@ -1075,7 +1085,7 @@
521
522 def pull(self, overwrite=False, stop_revision=None,
523 possible_transports=None, _hook_master=None, run_hooks=True,
524- _override_hook_target=None, local=False):
525+ _override_hook_target=None, local=False, tag_selector=None):
526 """See Branch.pull.
527
528 :param _hook_master: Private parameter - set the branch to
529@@ -1113,9 +1123,10 @@
530 master_branch = None
531 return self._basic_pull(stop_revision, overwrite, run_hooks,
532 _override_hook_target,
533- _hook_master=master_branch)
534+ _hook_master=master_branch,
535+ tag_selector=tag_selector)
536
537- def _basic_push(self, overwrite, stop_revision):
538+ def _basic_push(self, overwrite, stop_revision, tag_selector=None):
539 if overwrite is True:
540 overwrite = set(["history", "tags"])
541 elif not overwrite:
542@@ -1125,9 +1136,11 @@
543 result.target_branch = self.target
544 result.old_revno, result.old_revid = self.target.last_revision_info()
545 result.new_git_head, remote_refs = self._update_revisions(
546- stop_revision, overwrite=("history" in overwrite))
547+ stop_revision, overwrite=("history" in overwrite),
548+ tag_selector=tag_selector)
549 tags_ret = self.source.tags.merge_to(
550- self.target.tags, "tags" in overwrite, ignore_master=True)
551+ self.target.tags, "tags" in overwrite, ignore_master=True,
552+ selector=tag_selector)
553 (result.tag_updates, result.tag_conflicts) = tags_ret
554 result.new_revno, result.new_revid = self.target.last_revision_info()
555 self.update_references(revid=result.new_revid)
556@@ -1156,7 +1169,7 @@
557 return (isinstance(source, LocalGitBranch) and
558 isinstance(target, RemoteGitBranch))
559
560- def _basic_push(self, overwrite, stop_revision):
561+ def _basic_push(self, overwrite, stop_revision, tag_selector=None):
562 result = GitBranchPushResult()
563 result.source_branch = self.source
564 result.target_branch = self.target
565@@ -1181,6 +1194,8 @@
566 result.new_revid = stop_revision
567 for name, sha in viewitems(
568 self.source.repository._git.refs.as_dict(b"refs/tags")):
569+ if tag_selector and not tag_selector(name):
570+ continue
571 if sha not in self.source.repository._git:
572 trace.mutter('Ignoring missing SHA: %s', sha)
573 continue
574@@ -1220,7 +1235,7 @@
575 interrepo.fetch_objects(determine_wants, limit=limit, lossy=lossy)
576 return _mod_repository.FetchResult()
577
578- def _basic_push(self, overwrite=False, stop_revision=None):
579+ def _basic_push(self, overwrite=False, stop_revision=None, tag_selector=None):
580 if overwrite is True:
581 overwrite = set(["history", "tags"])
582 elif not overwrite:
583@@ -1236,7 +1251,8 @@
584 other_branch=self.source)
585 tags_ret = self.source.tags.merge_to(
586 self.target.tags,
587- overwrite=("tags" in overwrite))
588+ overwrite=("tags" in overwrite),
589+ selector=tag_selector)
590 if isinstance(tags_ret, tuple):
591 (result.tag_updates, result.tag_conflicts) = tags_ret
592 else:
593@@ -1264,7 +1280,8 @@
594 return result.refs, stop_revision
595
596 def pull(self, stop_revision=None, overwrite=False,
597- possible_transports=None, run_hooks=True, local=False):
598+ possible_transports=None, run_hooks=True, local=False,
599+ tag_selector=None):
600 # This type of branch can't be bound.
601 if local:
602 raise errors.LocalRequiresBoundBranch()
603@@ -1284,7 +1301,8 @@
604 (result.old_revid if ("history" not in overwrite) else None),
605 other_branch=self.source)
606 tags_ret = self.source.tags.merge_to(
607- self.target.tags, overwrite=("tags" in overwrite))
608+ self.target.tags, overwrite=("tags" in overwrite),
609+ selector=tag_selector)
610 if isinstance(tags_ret, tuple):
611 (result.tag_updates, result.tag_conflicts) = tags_ret
612 else:
613@@ -1352,7 +1370,7 @@
614 refs[ref] = (None, revid)
615 return refs, main_ref, (stop_revno, stop_revision)
616
617- def _update_refs(self, result, old_refs, new_refs, overwrite):
618+ def _update_refs(self, result, old_refs, new_refs, overwrite, tag_selector):
619 mutter("updating refs. old refs: %r, new refs: %r",
620 old_refs, new_refs)
621 result.tag_updates = {}
622@@ -1391,6 +1409,8 @@
623 except ValueError:
624 pass
625 else:
626+ if tag_selector and not tag_selector(tag_name):
627+ continue
628 result.tag_updates[tag_name] = revid
629 ret[ref] = (git_sha, revid)
630 else:
631@@ -1426,7 +1446,8 @@
632 for (old_revid, (new_sha, new_revid)) in revidmap.items()})
633
634 def pull(self, overwrite=False, stop_revision=None, local=False,
635- possible_transports=None, run_hooks=True, _stop_revno=None):
636+ possible_transports=None, run_hooks=True, _stop_revno=None,
637+ tag_selector=None):
638 result = GitBranchPullResult()
639 result.source_branch = self.source
640 result.target_branch = self.target
641@@ -1435,7 +1456,7 @@
642 stop_revision, stop_revno=_stop_revno)
643
644 def update_refs(old_refs):
645- return self._update_refs(result, old_refs, new_refs, overwrite)
646+ return self._update_refs(result, old_refs, new_refs, overwrite, tag_selector)
647 try:
648 result.revidmap, old_refs, new_refs = (
649 self.interrepo.fetch_refs(update_refs, lossy=False))
650@@ -1455,7 +1476,8 @@
651 return result
652
653 def push(self, overwrite=False, stop_revision=None, lossy=False,
654- _override_hook_source_branch=None, _stop_revno=None):
655+ _override_hook_source_branch=None, _stop_revno=None,
656+ tag_selector=None):
657 result = GitBranchPushResult()
658 result.source_branch = self.source
659 result.target_branch = self.target
660@@ -1466,7 +1488,7 @@
661 stop_revision, stop_revno=_stop_revno)
662
663 def update_refs(old_refs):
664- return self._update_refs(result, old_refs, new_refs, overwrite)
665+ return self._update_refs(result, old_refs, new_refs, overwrite, tag_selector)
666 try:
667 result.revidmap, old_refs, new_refs = (
668 self.interrepo.fetch_refs(
669
670=== modified file 'breezy/git/dir.py'
671--- breezy/git/dir.py 2020-01-18 16:14:28 +0000
672+++ breezy/git/dir.py 2020-02-19 23:22:37 +0000
673@@ -223,7 +223,8 @@
674 def clone_on_transport(self, transport, revision_id=None,
675 force_new_repo=False, preserve_stacking=False,
676 stacked_on=None, create_prefix=False,
677- use_existing_dir=True, no_tree=False):
678+ use_existing_dir=True, no_tree=False,
679+ tag_selector=None):
680 """See ControlDir.clone_on_transport."""
681 from ..repository import InterRepository
682 from .mapping import default_mapping
683@@ -245,7 +246,7 @@
684 interrepo = InterRepository.get(source_repo, target_repo)
685 if revision_id is not None:
686 determine_wants = interrepo.get_determine_wants_revids(
687- [revision_id], include_tags=True)
688+ [revision_id], include_tags=True, tag_selector=tag_selector)
689 else:
690 determine_wants = interrepo.determine_wants_all
691 (pack_hint, _, refs) = interrepo.fetch_objects(determine_wants,
692@@ -317,7 +318,7 @@
693
694 def push_branch(self, source, revision_id=None, overwrite=False,
695 remember=False, create_prefix=False, lossy=False,
696- name=None):
697+ name=None, tag_selector=None):
698 """Push the source branch into this ControlDir."""
699 push_result = GitPushResult()
700 push_result.workingtree_updated = None
701@@ -330,7 +331,7 @@
702 target = self.open_branch(name, nascent_ok=True)
703 push_result.branch_push_result = source.push(
704 target, overwrite=overwrite, stop_revision=revision_id,
705- lossy=lossy)
706+ lossy=lossy, tag_selector=tag_selector)
707 push_result.new_revid = push_result.branch_push_result.new_revid
708 push_result.old_revid = push_result.branch_push_result.old_revid
709 try:
710
711=== modified file 'breezy/git/interrepo.py'
712--- breezy/git/interrepo.py 2020-01-20 00:26:26 +0000
713+++ breezy/git/interrepo.py 2020-02-19 23:22:37 +0000
714@@ -81,6 +81,7 @@
715 )
716 from .refs import (
717 is_tag,
718+ ref_to_tag_name,
719 )
720 from .repository import (
721 GitRepository,
722@@ -409,7 +410,7 @@
723 def _target_has_shas(self, shas):
724 raise NotImplementedError(self._target_has_shas)
725
726- def get_determine_wants_heads(self, wants, include_tags=False):
727+ def get_determine_wants_heads(self, wants, include_tags=False, tag_selector=None):
728 wants = set(wants)
729
730 def determine_wants(refs):
731@@ -422,7 +423,11 @@
732 for k, sha in viewitems(refs):
733 if k.endswith(ANNOTATED_TAG_SUFFIX):
734 continue
735- if not is_tag(k):
736+ try:
737+ tag_name = ref_to_tag_name(k)
738+ except ValueError:
739+ continue
740+ if tag_selector and not tag_selector(tag_name):
741 continue
742 if sha == ZERO_SHA:
743 continue
744@@ -508,14 +513,15 @@
745 """
746 raise NotImplementedError(self.fetch_objects)
747
748- def get_determine_wants_revids(self, revids, include_tags=False):
749+ def get_determine_wants_revids(self, revids, include_tags=False, tag_selector=None):
750 wants = set()
751 for revid in set(revids):
752 if self.target.has_revision(revid):
753 continue
754 git_sha, mapping = self.source.lookup_bzr_revision_id(revid)
755 wants.add(git_sha)
756- return self.get_determine_wants_heads(wants, include_tags=include_tags)
757+ return self.get_determine_wants_heads(
758+ wants, include_tags=include_tags, tag_selector=tag_selector)
759
760 def fetch(self, revision_id=None, find_ghosts=False,
761 mapping=None, fetch_spec=None, include_tags=False, lossy=False):
762@@ -688,14 +694,14 @@
763 result.refs = wants_recorder.remote_refs
764 return result
765
766- def get_determine_wants_revids(self, revids, include_tags=False):
767+ def get_determine_wants_revids(self, revids, include_tags=False, tag_selector=None):
768 wants = set()
769 for revid in set(revids):
770 if revid == NULL_REVISION:
771 continue
772 git_sha, mapping = self.source.lookup_bzr_revision_id(revid)
773 wants.add(git_sha)
774- return self.get_determine_wants_heads(wants, include_tags=include_tags)
775+ return self.get_determine_wants_heads(wants, include_tags=include_tags, tag_selector=tag_selector)
776
777 def get_determine_wants_branches(self, branches, include_tags=False):
778 def determine_wants(refs):
779
780=== modified file 'breezy/git/workingtree.py'
781--- breezy/git/workingtree.py 2020-01-19 01:29:22 +0000
782+++ breezy/git/workingtree.py 2020-02-19 23:22:37 +0000
783@@ -1213,12 +1213,12 @@
784
785 def pull(self, source, overwrite=False, stop_revision=None,
786 change_reporter=None, possible_transports=None, local=False,
787- show_base=False):
788+ show_base=False, tag_selector=None):
789 with self.lock_write(), source.lock_read():
790 old_revision = self.branch.last_revision()
791 count = self.branch.pull(source, overwrite, stop_revision,
792 possible_transports=possible_transports,
793- local=local)
794+ local=local, tag_selector=tag_selector)
795 self._update_git_tree(
796 old_revision=old_revision,
797 new_revision=self.branch.last_revision(),
798
799=== modified file 'breezy/plugins/propose/github.py'
800--- breezy/plugins/propose/github.py 2020-02-15 14:33:33 +0000
801+++ breezy/plugins/propose/github.py 2020-02-19 23:22:37 +0000
802@@ -379,7 +379,7 @@
803
804 def publish_derived(self, local_branch, base_branch, name, project=None,
805 owner=None, revision_id=None, overwrite=False,
806- allow_lossy=True):
807+ allow_lossy=True, tag_selector=None):
808 base_owner, base_project, base_branch_name = parse_github_branch_url(base_branch)
809 base_repo = self._get_repo(base_owner, base_project)
810 if owner is None:
811@@ -399,13 +399,14 @@
812 try:
813 push_result = remote_dir.push_branch(
814 local_branch, revision_id=revision_id, overwrite=overwrite,
815- name=name)
816+ name=name, tag_selector=tag_selector)
817 except errors.NoRoundtrippingSupport:
818 if not allow_lossy:
819 raise
820 push_result = remote_dir.push_branch(
821 local_branch, revision_id=revision_id,
822- overwrite=overwrite, name=name, lossy=True)
823+ overwrite=overwrite, name=name, lossy=True,
824+ tag_selector=tag_selector)
825 return push_result.target_branch, github_url_to_bzr_url(
826 remote_repo['html_url'], name)
827
828
829=== modified file 'breezy/plugins/propose/gitlabs.py'
830--- breezy/plugins/propose/gitlabs.py 2020-01-28 23:33:16 +0000
831+++ breezy/plugins/propose/gitlabs.py 2020-02-19 23:22:37 +0000
832@@ -418,7 +418,7 @@
833
834 def publish_derived(self, local_branch, base_branch, name, project=None,
835 owner=None, revision_id=None, overwrite=False,
836- allow_lossy=True):
837+ allow_lossy=True, tag_selector=None):
838 (host, base_project, base_branch_name) = parse_gitlab_branch_url(base_branch)
839 if owner is None:
840 owner = self._get_logged_in_username()
841@@ -433,13 +433,13 @@
842 try:
843 push_result = remote_dir.push_branch(
844 local_branch, revision_id=revision_id, overwrite=overwrite,
845- name=name)
846+ name=name, tag_selector=tag_selector)
847 except errors.NoRoundtrippingSupport:
848 if not allow_lossy:
849 raise
850 push_result = remote_dir.push_branch(
851 local_branch, revision_id=revision_id, overwrite=overwrite,
852- name=name, lossy=True)
853+ name=name, lossy=True, tag_selector=tag_selector)
854 public_url = gitlab_url_to_bzr_url(
855 target_project['http_url_to_repo'], name)
856 return push_result.target_branch, public_url
857
858=== modified file 'breezy/plugins/propose/launchpad.py'
859--- breezy/plugins/propose/launchpad.py 2020-01-28 23:33:16 +0000
860+++ breezy/plugins/propose/launchpad.py 2020-02-19 23:22:37 +0000
861@@ -260,7 +260,8 @@
862 return "~%s/%s" % (owner, project)
863
864 def _publish_git(self, local_branch, base_path, name, owner, project=None,
865- revision_id=None, overwrite=False, allow_lossy=True):
866+ revision_id=None, overwrite=False, allow_lossy=True,
867+ tag_selector=None):
868 to_path = self._get_derived_git_path(base_path, owner, project)
869 to_transport = get_transport("git+ssh://git.launchpad.net/" + to_path)
870 try:
871@@ -272,21 +273,23 @@
872 if dir_to is None:
873 try:
874 br_to = local_branch.create_clone_on_transport(
875- to_transport, revision_id=revision_id, name=name)
876+ to_transport, revision_id=revision_id, name=name,
877+ tag_selector=tag_selector)
878 except errors.NoRoundtrippingSupport:
879 br_to = local_branch.create_clone_on_transport(
880 to_transport, revision_id=revision_id, name=name,
881- lossy=True)
882+ lossy=True, tag_selector=tag_selector)
883 else:
884 try:
885 dir_to = dir_to.push_branch(
886- local_branch, revision_id, overwrite=overwrite, name=name)
887+ local_branch, revision_id, overwrite=overwrite, name=name,
888+ tag_selector=tag_selector)
889 except errors.NoRoundtrippingSupport:
890 if not allow_lossy:
891 raise
892 dir_to = dir_to.push_branch(
893 local_branch, revision_id, overwrite=overwrite, name=name,
894- lossy=True)
895+ lossy=True, tag_selector=tag_selector)
896 br_to = dir_to.target_branch
897 return br_to, (
898 "https://git.launchpad.net/%s/+ref/%s" % (to_path, name))
899@@ -312,7 +315,7 @@
900
901 def _publish_bzr(self, local_branch, base_branch, name, owner,
902 project=None, revision_id=None, overwrite=False,
903- allow_lossy=True):
904+ allow_lossy=True, tag_selector=None):
905 to_path = self._get_derived_bzr_path(base_branch, name, owner, project)
906 to_transport = get_transport("lp:" + to_path)
907 try:
908@@ -323,10 +326,11 @@
909
910 if dir_to is None:
911 br_to = local_branch.create_clone_on_transport(
912- to_transport, revision_id=revision_id)
913+ to_transport, revision_id=revision_id, tag_selector=tag_selector)
914 else:
915 br_to = dir_to.push_branch(
916- local_branch, revision_id, overwrite=overwrite).target_branch
917+ local_branch, revision_id, overwrite=overwrite,
918+ tag_selector=tag_selector).target_branch
919 return br_to, ("https://code.launchpad.net/" + to_path)
920
921 def _split_url(self, url):
922@@ -343,7 +347,7 @@
923
924 def publish_derived(self, local_branch, base_branch, name, project=None,
925 owner=None, revision_id=None, overwrite=False,
926- allow_lossy=True):
927+ allow_lossy=True, tag_selector=None):
928 """Publish a branch to the site, derived from base_branch.
929
930 :param base_branch: branch to derive the new branch from
931@@ -362,12 +366,12 @@
932 return self._publish_bzr(
933 local_branch, base_branch, name, project=project, owner=owner,
934 revision_id=revision_id, overwrite=overwrite,
935- allow_lossy=allow_lossy)
936+ allow_lossy=allow_lossy, tag_selector=tag_selector)
937 elif base_vcs == 'git':
938 return self._publish_git(
939 local_branch, base_path, name, project=project, owner=owner,
940 revision_id=revision_id, overwrite=overwrite,
941- allow_lossy=allow_lossy)
942+ allow_lossy=allow_lossy, tag_selector=tag_selector)
943 else:
944 raise AssertionError('not a valid Launchpad URL')
945
946
947=== modified file 'breezy/plugins/weave_fmt/bzrdir.py'
948--- breezy/plugins/weave_fmt/bzrdir.py 2020-01-31 10:39:02 +0000
949+++ breezy/plugins/weave_fmt/bzrdir.py 2020-02-19 23:22:37 +0000
950@@ -747,7 +747,7 @@
951 return self._format.__class__()
952
953 def clone(self, url, revision_id=None, force_new_repo=False,
954- preserve_stacking=False):
955+ preserve_stacking=False, tag_selector=None):
956 """See ControlDir.clone().
957
958 force_new_repo has no effect, since this family of formats always
959@@ -759,7 +759,7 @@
960 result = self._format._initialize_for_clone(url)
961 self.open_repository().clone(result, revision_id=revision_id)
962 from_branch = self.open_branch()
963- from_branch.clone(result, revision_id=revision_id)
964+ from_branch.clone(result, revision_id=revision_id, tag_selector=tag_selector)
965 try:
966 tree = self.open_workingtree()
967 except errors.NotLocalUrl:
968
969=== modified file 'breezy/propose.py'
970--- breezy/propose.py 2020-01-28 23:33:16 +0000
971+++ breezy/propose.py 2020-02-19 23:22:37 +0000
972@@ -239,7 +239,7 @@
973
974 def publish_derived(self, new_branch, base_branch, name, project=None,
975 owner=None, revision_id=None, overwrite=False,
976- allow_lossy=True):
977+ allow_lossy=True, tag_selector=None):
978 """Publish a branch to the site, derived from base_branch.
979
980 :param base_branch: branch to derive the new branch from
981
982=== modified file 'breezy/tag.py'
983--- breezy/tag.py 2020-02-19 03:30:42 +0000
984+++ breezy/tag.py 2020-02-19 23:22:37 +0000
985@@ -35,20 +35,13 @@
986 from .inter import InterObject
987 from .registry import Registry
988 from .sixish import text_type
989-from .lazy_import import lazy_import
990-lazy_import(globals(), """
991-
992-from breezy import (
993+from . import (
994 cleanup,
995- )
996-""")
997-
998-from . import (
999 errors,
1000 )
1001
1002
1003-def _reconcile_tags(source_dict, dest_dict, overwrite):
1004+def _reconcile_tags(source_dict, dest_dict, overwrite, selector):
1005 """Do a two-way merge of two tag dictionaries.
1006
1007 * only in source => source value
1008@@ -64,6 +57,8 @@
1009 updates = {}
1010 result = dict(dest_dict) # copy
1011 for name, target in source_dict.items():
1012+ if selector and not selector(name):
1013+ continue
1014 if result.get(name) == target:
1015 pass
1016 elif name not in result or overwrite:
1017@@ -93,7 +88,7 @@
1018 rev[d[key]].add(key)
1019 return rev
1020
1021- def merge_to(self, to_tags, overwrite=False, ignore_master=False):
1022+ def merge_to(self, to_tags, overwrite=False, ignore_master=False, selector=None):
1023 """Copy tags between repositories if necessary and possible.
1024
1025 This method has common command-line behaviour about handling
1026@@ -115,7 +110,9 @@
1027 done.
1028 """
1029 intertags = InterTags.get(self, to_tags)
1030- return intertags.merge(overwrite=overwrite, ignore_master=ignore_master)
1031+ return intertags.merge(
1032+ overwrite=overwrite, ignore_master=ignore_master,
1033+ selector=selector)
1034
1035 def set_tag(self, tag_name, revision):
1036 """Set a tag.
1037@@ -174,7 +171,7 @@
1038 lookup_tag = _not_supported
1039 delete_tag = _not_supported
1040
1041- def merge_to(self, to_tags, overwrite=False, ignore_master=False):
1042+ def merge_to(self, to_tags, overwrite=False, ignore_master=False, selector=None):
1043 # we never have anything to copy
1044 return {}, []
1045
1046@@ -199,7 +196,7 @@
1047 # This is the default implementation
1048 return True
1049
1050- def merge(self, overwrite=False, ignore_master=False):
1051+ def merge(self, overwrite=False, ignore_master=False, selector=None):
1052 """Copy tags between repositories if necessary and possible.
1053
1054 This method has common command-line behaviour about handling
1055@@ -212,6 +209,9 @@
1056 :param overwrite: Overwrite conflicting tags in the target branch
1057 :param ignore_master: Do not modify the tags in the target's master
1058 branch (if any). Default is false (so the master will be updated).
1059+ :param selector: Callback that determines whether a tag should be
1060+ copied. It should take a tag name and as argument and return a
1061+ boolean.
1062
1063 :returns: Tuple with tag_updates and tag_conflicts.
1064 tag_updates is a dictionary with new tags, None is used for
1065@@ -250,10 +250,11 @@
1066 master = self.target.branch.get_master_branch()
1067 if master is not None:
1068 stack.enter_context(master.lock_write())
1069- updates, conflicts = self._merge_to(self.target, source_dict, overwrite)
1070+ updates, conflicts = self._merge_to(
1071+ self.target, source_dict, overwrite, selector=selector)
1072 if master is not None:
1073- extra_updates, extra_conflicts = self._merge_to(master.tags,
1074- source_dict, overwrite)
1075+ extra_updates, extra_conflicts = self._merge_to(
1076+ master.tags, source_dict, overwrite, selector=selector)
1077 updates.update(extra_updates)
1078 conflicts += extra_conflicts
1079 # We use set() to remove any duplicate conflicts from the master
1080@@ -261,10 +262,10 @@
1081 return updates, set(conflicts)
1082
1083 @classmethod
1084- def _merge_to(cls, to_tags, source_dict, overwrite):
1085+ def _merge_to(cls, to_tags, source_dict, overwrite, selector):
1086 dest_dict = to_tags.get_tag_dict()
1087 result, updates, conflicts = _reconcile_tags(
1088- source_dict, dest_dict, overwrite)
1089+ source_dict, dest_dict, overwrite, selector)
1090 if result != dest_dict:
1091 to_tags._set_tag_dict(result)
1092 return updates, conflicts
1093@@ -303,11 +304,11 @@
1094 def _set_tag_dict(self, result):
1095 self._tag_dict = dict(result.items())
1096
1097- def merge_to(self, to_tags, overwrite=False, ignore_master=False):
1098+ def merge_to(self, to_tags, overwrite=False, ignore_master=False, selector=None):
1099 source_dict = self.get_tag_dict()
1100 dest_dict = to_tags.get_tag_dict()
1101 result, updates, conflicts = _reconcile_tags(
1102- source_dict, dest_dict, overwrite)
1103+ source_dict, dest_dict, overwrite, selector)
1104 if result != dest_dict:
1105 to_tags._set_tag_dict(result)
1106 return updates, conflicts
1107
1108=== modified file 'breezy/tests/per_branch/test_pull.py'
1109--- breezy/tests/per_branch/test_pull.py 2018-11-17 20:50:40 +0000
1110+++ breezy/tests/per_branch/test_pull.py 2020-02-19 23:22:37 +0000
1111@@ -118,7 +118,7 @@
1112 self.assertEqual(p1, result.old_revid)
1113 self.assertEqual(2, result.new_revno)
1114 self.assertEqual(m1, result.new_revid)
1115- self.assertEqual([], result.tag_conflicts)
1116+ self.assertEqual([], list(result.tag_conflicts))
1117
1118 def test_pull_overwrite(self):
1119 tree_a = self.make_branch_and_tree('tree_a')
1120
1121=== modified file 'breezy/tests/per_branch/test_tags.py'
1122--- breezy/tests/per_branch/test_tags.py 2019-02-02 21:58:23 +0000
1123+++ breezy/tests/per_branch/test_tags.py 2020-02-19 23:22:37 +0000
1124@@ -142,6 +142,21 @@
1125 self.assertEqual(updates, {})
1126 self.assertEqual(b2.tags.lookup_tag('conflicts'), revid2)
1127
1128+ def test_merge_tags_selector(self):
1129+ b1, [revid, revid1] = self.make_branch_with_revision_tuple('b1', 2)
1130+ w2 = b1.controldir.sprout('b2', revision_id=revid).open_workingtree()
1131+ revid2 = w2.commit('revision 2')
1132+ b2 = w2.branch
1133+ # if there are tags in the source and not the destination, then they
1134+ # just go across
1135+ b1.tags.set_tag('tag1', revid)
1136+ b1.tags.set_tag('tag2', revid2)
1137+ updates, conflicts = b1.tags.merge_to(b2.tags, selector=lambda x: x == 'tag1')
1138+ self.assertEqual({'tag1': revid}, updates)
1139+ self.assertEqual(set(), set(conflicts))
1140+ self.assertEqual(b2.tags.lookup_tag('tag1'), revid)
1141+ self.assertRaises(errors.NoSuchTag, b2.tags.lookup_tag, 'tag2')
1142+
1143 def test_unicode_tag(self):
1144 tag_name = u'\u3070'
1145 b1, [revid] = self.make_branch_with_revision_tuple('b', 1)
1146
1147=== modified file 'breezy/tests/per_controldir/test_push.py'
1148--- breezy/tests/per_controldir/test_push.py 2019-02-15 03:42:06 +0000
1149+++ breezy/tests/per_controldir/test_push.py 2020-02-19 23:22:37 +0000
1150@@ -99,3 +99,14 @@
1151 self.assertEqual(2, result.branch_push_result.new_revno)
1152 self.assertEqual(tree.branch.base, result.source_branch.base)
1153 self.assertEqual(dir.open_branch().base, result.target_branch.base)
1154+
1155+ def test_push_tag_selector(self):
1156+ tree, rev1 = self.create_simple_tree()
1157+ try:
1158+ tree.branch.tags.set_tag('tag1', rev1)
1159+ except TagsNotSupported:
1160+ raise TestNotApplicable('tags not supported')
1161+ tree.branch.tags.set_tag('tag2', rev1)
1162+ dir = self.make_repository('dir').controldir
1163+ dir.push_branch(tree.branch, tag_selector=lambda x: x == 'tag1')
1164+ self.assertEqual({'tag1': rev1}, dir.open_branch().tags.get_tag_dict())
1165
1166=== modified file 'breezy/tests/per_interbranch/test_pull.py'
1167--- breezy/tests/per_interbranch/test_pull.py 2018-11-11 04:08:32 +0000
1168+++ breezy/tests/per_interbranch/test_pull.py 2020-02-19 23:22:37 +0000
1169@@ -144,7 +144,7 @@
1170 self.assertEqual(p1, result.old_revid)
1171 self.assertEqual(2, result.new_revno)
1172 self.assertEqual(m1, result.new_revid)
1173- self.assertEqual([], result.tag_conflicts)
1174+ self.assertEqual([], list(result.tag_conflicts))
1175
1176 def test_pull_overwrite(self):
1177 tree_a = self.make_from_branch_and_tree('tree_a')
1178@@ -180,6 +180,26 @@
1179 self.assertEqual(tree_b.branch.last_revision(),
1180 tree_a.branch.last_revision())
1181
1182+ def test_pull_tag_selector(self):
1183+ if not self.branch_format_from.supports_tags():
1184+ raise TestNotApplicable('from format does not support tags')
1185+ if not self.branch_format_to.supports_tags():
1186+ raise TestNotApplicable('to format does not support tags')
1187+ tree_a = self.make_from_branch_and_tree('tree_a')
1188+ revid1 = tree_a.commit('message 1')
1189+ try:
1190+ tree_b = self.sprout_to(
1191+ tree_a.controldir, 'tree_b').open_workingtree()
1192+ except errors.NoRoundtrippingSupport:
1193+ raise TestNotApplicable(
1194+ 'lossless push between %r and %r not supported' %
1195+ (self.branch_format_from, self.branch_format_to))
1196+ tree_b.branch.tags.set_tag('tag1', revid1)
1197+ tree_b.branch.tags.set_tag('tag2', revid1)
1198+ tree_b.branch.get_config_stack().set('branch.fetch_tags', True)
1199+ tree_a.pull(tree_b.branch, tag_selector=lambda x: x == 'tag1')
1200+ self.assertEqual({'tag1': revid1}, tree_a.branch.tags.get_tag_dict())
1201+
1202
1203 class TestPullHook(TestCaseWithInterBranch):
1204
1205
1206=== modified file 'breezy/tests/per_interbranch/test_push.py'
1207--- breezy/tests/per_interbranch/test_push.py 2018-11-16 11:37:47 +0000
1208+++ breezy/tests/per_interbranch/test_push.py 2020-02-19 23:22:37 +0000
1209@@ -375,6 +375,26 @@
1210 self.overrideAttr(SmartServerRepositoryGetParentMap,
1211 'no_extra_results', True)
1212
1213+ def test_push_tag_selector(self):
1214+ if not self.branch_format_from.supports_tags():
1215+ raise tests.TestNotApplicable('from format does not support tags')
1216+ if not self.branch_format_to.supports_tags():
1217+ raise tests.TestNotApplicable('to format does not support tags')
1218+ tree_a = self.make_from_branch_and_tree('tree_a')
1219+ revid1 = tree_a.commit('message 1')
1220+ try:
1221+ tree_b = self.sprout_to(
1222+ tree_a.controldir, 'tree_b').open_workingtree()
1223+ except errors.NoRoundtrippingSupport:
1224+ raise tests.TestNotApplicable(
1225+ 'lossless push between %r and %r not supported' %
1226+ (self.branch_format_from, self.branch_format_to))
1227+ tree_b.branch.tags.set_tag('tag1', revid1)
1228+ tree_b.branch.tags.set_tag('tag2', revid1)
1229+ tree_b.branch.get_config_stack().set('branch.fetch_tags', True)
1230+ tree_b.branch.push(tree_a.branch, tag_selector=lambda x: x == 'tag1')
1231+ self.assertEqual({'tag1': revid1}, tree_a.branch.tags.get_tag_dict())
1232+
1233
1234 class TestPushHook(TestCaseWithInterBranch):
1235
1236
1237=== modified file 'breezy/tests/test_foreign.py'
1238--- breezy/tests/test_foreign.py 2018-11-25 20:44:56 +0000
1239+++ breezy/tests/test_foreign.py 2020-02-19 23:22:37 +0000
1240@@ -171,7 +171,7 @@
1241 def is_compatible(source, target):
1242 return isinstance(target, DummyForeignVcsBranch)
1243
1244- def push(self, overwrite=False, stop_revision=None, lossy=False):
1245+ def push(self, overwrite=False, stop_revision=None, lossy=False, tag_selector=None):
1246 if not lossy:
1247 raise errors.NoRoundtrippingSupport(self.source, self.target)
1248 result = branch.BranchPushResult()
1249
1250=== modified file 'breezy/tests/test_tag.py'
1251--- breezy/tests/test_tag.py 2020-02-18 01:32:25 +0000
1252+++ breezy/tests/test_tag.py 2020-02-19 23:22:37 +0000
1253@@ -122,6 +122,17 @@
1254 self.assertEqual({u'tag-2': b'z'}, updates)
1255 self.assertEqual(b'z', b.tags.lookup_tag('tag-2'))
1256
1257+ def test_merge_to_with_selector(self):
1258+ a = self.make_branch_supporting_tags('a')
1259+ b = self.make_branch_supporting_tags('b')
1260+ # simple merge
1261+ a.tags.set_tag('tag-1', b'x')
1262+ a.tags.set_tag('tag-2', b'y')
1263+ updates, conflicts = a.tags.merge_to(b.tags, selector=lambda x: x == 'tag-1')
1264+ self.assertEqual(list(conflicts), [])
1265+ self.assertEqual({u'tag-1': b'x'}, updates)
1266+ self.assertRaises(errors.NoSuchTag, b.tags.lookup_tag, 'tag-2')
1267+
1268
1269 class TestTagsInCheckouts(TestCaseWithTransport):
1270 """Tests for how tags are synchronised between the master and child branch
1271
1272=== modified file 'breezy/workingtree.py'
1273--- breezy/workingtree.py 2020-01-30 17:54:42 +0000
1274+++ breezy/workingtree.py 2020-02-19 23:22:37 +0000
1275@@ -821,13 +821,13 @@
1276
1277 def pull(self, source, overwrite=False, stop_revision=None,
1278 change_reporter=None, possible_transports=None, local=False,
1279- show_base=False):
1280+ show_base=False, tag_selector=None):
1281 with self.lock_write(), source.lock_read():
1282 old_revision_info = self.branch.last_revision_info()
1283 basis_tree = self.basis_tree()
1284 count = self.branch.pull(source, overwrite, stop_revision,
1285 possible_transports=possible_transports,
1286- local=local)
1287+ local=local, tag_selector=tag_selector)
1288 new_revision_info = self.branch.last_revision_info()
1289 if new_revision_info != old_revision_info:
1290 repository = self.branch.repository

Subscribers

People subscribed via source and target branches