summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Maw <richard.maw@codethink.co.uk>2015-04-29 11:16:54 (GMT)
committerRichard Maw <richard.maw@codethink.co.uk>2015-04-29 11:32:51 (GMT)
commiteaa06853a161d87b1623cf56f75d3ec404ba06f6 (patch)
treea1bfb591c937053de9ea808384f4afd7f8a981eb
parent290483010cfc7945cd4483fadd1d98c3b83efb3c (diff)
downloadmorph-eaa06853a161d87b1623cf56f75d3ec404ba06f6.tar.gz
RemoteRefManager: Fail all ref updates when one fails
There's no API to do it in one push yet, but we can send a delete for all the branches that *did* commit. Change-Id: I671e9384b84657a3e9034d62818caa0ac0d8de1e
-rw-r--r--morphlib/branchmanager.py28
1 files changed, 27 insertions, 1 deletions
diff --git a/morphlib/branchmanager.py b/morphlib/branchmanager.py
index 92a1f4b..ebec7fe 100644
--- a/morphlib/branchmanager.py
+++ b/morphlib/branchmanager.py
@@ -17,6 +17,7 @@ import cliapp
import collections
import morphlib
+from morphlib.gitdir import PushFailureError as _PushFailureError
class RefCleanupError(cliapp.AppException):
@@ -212,11 +213,36 @@ class RemoteRefManager(object):
after the end of the block the with statement the RemoteRefManager
is used in.
+ If any of the refspecs failed to push, then they are all rolled back.
+ The result includes ones that had succeeded, but if you want to re-try
+ some refspecs, you need to re-try the ones that succeeded as well as
+ the ones that failed.
+
'''
# Calculate the refspecs required to undo the pushed changes.
delete_specs = tuple(rs.revert() for rs in refspecs)
- result = remote.push(*refspecs)
+ try:
+ result = remote.push(*refspecs)
+ except _PushFailureError as e: # pragma: no cover
+ results = set(e.results)
+ e.results = results
+ # Skip deletes if we didn't fail because a ref update failed
+ if not results:
+ raise
+
+ undorefspecs = set()
+ for flag, sha1, target, summary, reason in results:
+ for rs in refspecs:
+ if rs.target == target and rs.source == sha1:
+ break
+ if flag != '!':
+ undorefspecs.add(rs.revert())
+ # We may have nothing to undo because all our pushes failed
+ if undorefspecs:
+ remote.push(*undorefspecs)
+ raise
+
# Register cleanup after pushing, so that if this push fails,
# we don't try to undo it.
self._cleanup.append((remote, delete_specs))