summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/gl_objects/commits.rst4
-rw-r--r--gitlab/exceptions.py4
-rw-r--r--gitlab/v4/objects.py16
-rwxr-xr-xtools/cli_test_v4.sh9
-rw-r--r--tools/python_test_v4.py15
5 files changed, 48 insertions, 0 deletions
diff --git a/docs/gl_objects/commits.rst b/docs/gl_objects/commits.rst
index 97cd1c4..abfedc8 100644
--- a/docs/gl_objects/commits.rst
+++ b/docs/gl_objects/commits.rst
@@ -72,6 +72,10 @@ Cherry-pick a commit into another branch::
commit.cherry_pick(branch='target_branch')
+Revert a commit on a given branch::
+
+ commit.revert(branch='target_branch')
+
Get the references the commit has been pushed to (branches and tags)::
commit.refs() # all references
diff --git a/gitlab/exceptions.py b/gitlab/exceptions.py
index aff3c87..d6791f2 100644
--- a/gitlab/exceptions.py
+++ b/gitlab/exceptions.py
@@ -245,6 +245,10 @@ class GitlabRepairError(GitlabOperationError):
pass
+class GitlabRevertError(GitlabOperationError):
+ pass
+
+
class GitlabLicenseError(GitlabOperationError):
pass
diff --git a/gitlab/v4/objects.py b/gitlab/v4/objects.py
index b31870c..d2af890 100644
--- a/gitlab/v4/objects.py
+++ b/gitlab/v4/objects.py
@@ -2136,6 +2136,22 @@ class ProjectCommit(RESTObject):
path = "%s/%s/merge_requests" % (self.manager.path, self.get_id())
return self.manager.gitlab.http_get(path, **kwargs)
+ @cli.register_custom_action("ProjectCommit", ("branch",))
+ @exc.on_http_error(exc.GitlabRevertError)
+ def revert(self, branch, **kwargs):
+ """Revert a commit on a given branch.
+
+ Args:
+ branch (str): Name of target branch
+ **kwargs: Extra options to send to the server (e.g. sudo)
+
+ Raises:
+ GitlabAuthenticationError: If authentication is not correct
+ GitlabRevertError: If the revert could not be performed
+ """
+ path = "%s/%s/revert" % (self.manager.path, self.get_id())
+ post_data = {"branch": branch}
+ self.manager.gitlab.http_post(path, post_data=post_data, **kwargs)
class ProjectCommitManager(RetrieveMixin, CreateMixin, RESTManager):
_path = "/projects/%(project_id)s/repository/commits"
diff --git a/tools/cli_test_v4.sh b/tools/cli_test_v4.sh
index dc6e0b2..b7ed708 100755
--- a/tools/cli_test_v4.sh
+++ b/tools/cli_test_v4.sh
@@ -100,6 +100,15 @@ testcase "merge request validation" '
--iid "$MR_ID" >/dev/null 2>&1
'
+# Test revert commit
+COMMITS=$(GITLAB -v project-commit list --project-id "${PROJECT_ID}")
+COMMIT_ID=$(pecho "${COMMITS}" | grep -m1 '^id:' | cut -d' ' -f2)
+
+testcase "revert commit" '
+ GITLAB project-commit revert --project-id "$PROJECT_ID" \
+ --id "$COMMIT_ID" --branch master
+'
+
# Test project labels
testcase "create project label" '
OUTPUT=$(GITLAB -v project-label create --project-id $PROJECT_ID \
diff --git a/tools/python_test_v4.py b/tools/python_test_v4.py
index bffdd2a..7c97899 100644
--- a/tools/python_test_v4.py
+++ b/tools/python_test_v4.py
@@ -462,6 +462,21 @@ d_note_from_get.delete()
discussion = commit.discussions.get(discussion.id)
# assert len(discussion.attributes["notes"]) == 1
+# Revert commit
+commit.revert(branch="master")
+revert_commit = admin_project.commits.list()[0]
+
+expected_message = "Revert \"{}\"\n\nThis reverts commit {}".format(
+ commit.message, commit.id)
+assert revert_commit.message == expected_message
+
+try:
+ commit.revert(branch="master")
+ # Only here to really ensure expected error without a full test framework
+ raise AssertionError("Two revert attempts should raise GitlabRevertError")
+except gitlab.GitlabRevertError:
+ pass
+
# housekeeping
admin_project.housekeeping()