diff options
author | Richard Maw <richard.maw@codethink.co.uk> | 2015-04-29 11:16:54 +0000 |
---|---|---|
committer | Richard Maw <richard.maw@codethink.co.uk> | 2015-04-29 11:32:51 +0000 |
commit | eaa06853a161d87b1623cf56f75d3ec404ba06f6 (patch) | |
tree | a1bfb591c937053de9ea808384f4afd7f8a981eb | |
parent | 290483010cfc7945cd4483fadd1d98c3b83efb3c (diff) | |
download | morph-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.py | 28 |
1 files changed, 27 insertions, 1 deletions
diff --git a/morphlib/branchmanager.py b/morphlib/branchmanager.py index 92a1f4be..ebec7fe6 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)) |