diff options
| -rw-r--r-- | AUTHORS.rst | 14 | ||||
| -rw-r--r-- | README.rst | 63 | ||||
| -rw-r--r-- | pygerrit/events.py | 21 | ||||
| -rw-r--r-- | pygerrit/models.py | 2 | ||||
| -rw-r--r-- | pygerrit/rest/__init__.py | 8 | ||||
| -rwxr-xr-x | rest_example.py | 17 |
6 files changed, 105 insertions, 20 deletions
diff --git a/AUTHORS.rst b/AUTHORS.rst new file mode 100644 index 0000000..58941af --- /dev/null +++ b/AUTHORS.rst @@ -0,0 +1,14 @@ +pygerrit is written and maintained by David Pursehouse and +various contributors: + +Development Lead +```````````````` + +- David Pursehouse <david.pursehouse@sonymobile.com> + + +Patches and Suggestions +``````````````````````` + +- Ernst Sjöstrand <ernst.sjostrand@sonymobile.com> +- Jens Andersen <jens.andersen@gmail.com> @@ -2,7 +2,7 @@ Pygerrit - Client library for interacting with Gerrit Code Review ================================================================= Pygerrit is a Python library to interact with the -`Gerrit Code Review`_ system over ssh. +`Gerrit Code Review`_ system over ssh or via the REST API. Installation ------------ @@ -20,9 +20,9 @@ Prerequisites Pygerrit runs on Ubuntu 10.4 and Mac OSX 10.8.4 with Python 2.6.x and 2.7.x. Support for other platforms and Python versions is not guaranteed. -To connect to the review server, pygerrit requires the ssh connection -parameters (hostname, port, username) to be present in the ``.ssh/config`` -file for the current user: +For easier connection to the review server over ssh, the ssh connection +parameters (hostname, port, username) can be given in the user's ``.ssh/config`` +file: .. code-block:: bash @@ -31,6 +31,24 @@ file for the current user: Port 29418 User username +SSH Interface +------------- + +The SSH interface can be used to run commands on the Gerrit server. + +.. code-block:: pycon + + >>> from pygerrit.ssh import GerritSSHClient + >>> client = GerritSSHClient("review") + >>> result = client.run_gerrit_command("version") + >>> result + <GerritSSHCommandResult [version]> + >>> result.stdout + <paramiko.ChannelFile from <paramiko.Channel 2 (closed) -> <paramiko.Transport at 0xd2387d90L (cipher aes128-cbc, 128 bits) (active; 0 open channel(s))>>> + >>> result.stdout.read() + 'gerrit version 2.6.1\n' + >>> + Event Stream ------------ @@ -44,9 +62,41 @@ client to fetch them from a queue. It also allows users to easily add handling of custom event types, for example if they are running a customised Gerrit installation with non-standard events. -Refer to the `example`_ script for a brief example of how the interface -works. +.. code-block:: pycon + + >>> from pygerrit.client import GerritClient + >>> client = GerritClient("review") + >>> client.gerrit_version() + '2.6.1' + >>> client.start_event_stream() + >>> client.get_event() + <CommentAddedEvent>: <Change 12345, platform/packages/apps/Example, master> <Patchset 1, 5c4b2f76297f04fbab77eb8c3462e087bc4b6f90> <Account Bob Example (bob.example@example.com)> + >>> client.get_event() + <CommentAddedEvent>: <Change 67890, platform/frameworks/example, master> <Patchset 2, c7d4f9956c80b1df66a66d66dea3960e71de4910> <Account John Example (john.example@example.com)> + >>> client.stop_event_stream() + >>> + + +Refer to the `example`_ script for a more detailed example of how the SSH +event stream interface works. + +REST API +-------- + +Gerrit offers a feature-rich REST API. This library provides a simple +interface for clients to interact with Gerrit via the REST API. + +.. code-block:: pycon + + >>> from requests.auth import HTTPDigestAuth + >>> from pygerrit.rest import GerritRestAPI + >>> auth = HTTPDigestAuth('username', 'password') + >>> rest = GerritRestAPI(url='http://review.example.net', auth=auth) + >>> changes = rest.get("/changes/?q=owner:self%20status:open") + +Refer to the `rest_example`_ script for a more detailed example of how the +REST API interface works. Copyright and License --------------------- @@ -60,4 +110,5 @@ license details. .. _`Gerrit Code Review`: https://code.google.com/p/gerrit/ .. _example: https://github.com/sonyxperiadev/pygerrit/blob/master/example.py +.. _rest_example: https://github.com/sonyxperiadev/pygerrit/blob/master/rest_example.py .. _LICENSE: https://github.com/sonyxperiadev/pygerrit/blob/master/LICENSE diff --git a/pygerrit/events.py b/pygerrit/events.py index ebbb327..c6563cd 100644 --- a/pygerrit/events.py +++ b/pygerrit/events.py @@ -220,7 +220,8 @@ class MergeFailedEvent(GerritEvent): self.change = Change(json_data["change"]) self.patchset = Patchset(json_data["patchSet"]) self.submitter = Account(json_data["submitter"]) - self.reason = json_data["reason"] + if 'reason' in json_data: + self.reason = json_data["reason"] except KeyError as e: raise GerritError("MergeFailedEvent: %s" % e) @@ -239,16 +240,15 @@ class ChangeAbandonedEvent(GerritEvent): super(ChangeAbandonedEvent, self).__init__(json_data) try: self.change = Change(json_data["change"]) - self.patchset = Patchset.from_json(json_data) self.abandoner = Account(json_data["abandoner"]) - self.reason = json_data["reason"] + if 'reason' in json_data: + self.reason = json_data["reason"] except KeyError as e: raise GerritError("ChangeAbandonedEvent: %s" % e) def __repr__(self): - return u"<ChangeAbandonedEvent>: %s %s %s" % (self.change, - self.patchset, - self.abandoner) + return u"<ChangeAbandonedEvent>: %s %s" % (self.change, + self.abandoner) @GerritEventFactory.register("change-restored") @@ -260,16 +260,15 @@ class ChangeRestoredEvent(GerritEvent): super(ChangeRestoredEvent, self).__init__(json_data) try: self.change = Change(json_data["change"]) - self.patchset = Patchset.from_json(json_data) self.restorer = Account(json_data["restorer"]) - self.reason = json_data["reason"] + if 'reason' in json_data: + self.reason = json_data["reason"] except KeyError as e: raise GerritError("ChangeRestoredEvent: %s" % e) def __repr__(self): - return u"<ChangeRestoredEvent>: %s %s %s" % (self.change, - self.patchset, - self.restorer) + return u"<ChangeRestoredEvent>: %s %s" % (self.change, + self.restorer) @GerritEventFactory.register("ref-updated") diff --git a/pygerrit/models.py b/pygerrit/models.py index ac9575a..22716ec 100644 --- a/pygerrit/models.py +++ b/pygerrit/models.py @@ -64,6 +64,8 @@ class Change(object): self.subject = from_json(json_data, "subject") self.url = from_json(json_data, "url") self.owner = Account.from_json(json_data, "owner") + if 'sortKey' in json_data: + self.sortkey = from_json(json_data, "sortKey") def __repr__(self): return u"<Change %s, %s, %s>" % (self.number, self.project, self.branch) diff --git a/pygerrit/rest/__init__.py b/pygerrit/rest/__init__.py index 99364e1..b5cfd3a 100644 --- a/pygerrit/rest/__init__.py +++ b/pygerrit/rest/__init__.py @@ -74,7 +74,7 @@ class GerritRestAPI(object): """ Interface to the Gerrit REST API. """ - def __init__(self, url, auth=None): + def __init__(self, url, auth=None, verify=True): """ Constructor. `url` is assumed to be the full URL to the server, including the @@ -84,8 +84,12 @@ class GerritRestAPI(object): class from the `requests` module. The `url` will be adjusted if necessary to make sure it includes Gerrit's authentication suffix. + If `verify` is False, the underlying requests library will be + configured to not attempt to verify SSL certificates. + """ - self.kwargs = {'auth': auth} + self.kwargs = {'auth': auth, + 'verify': verify} self.url = url.rstrip('/') self.session = requests.session() diff --git a/rest_example.py b/rest_example.py index 132765f..1c278c8 100755 --- a/rest_example.py +++ b/rest_example.py @@ -30,6 +30,11 @@ import optparse import sys from requests.auth import HTTPBasicAuth, HTTPDigestAuth +try: + from requests_kerberos import HTTPKerberosAuth, OPTIONAL + _kerberos_support = True +except ImportError: + _kerberos_support = False from pygerrit.rest import GerritRestAPI from pygerrit.rest.auth import HTTPDigestAuthFromNetrc, HTTPBasicAuthFromNetrc @@ -44,6 +49,10 @@ def _main(): parser.add_option('-b', '--basic-auth', dest='basic_auth', action='store_true', help='use basic auth instead of digest') + if HTTPKerberosAuth: + parser.add_option('-k', '--kerberos-auth', dest='kerberos_auth', + action='store_true', + help='use kerberos auth') parser.add_option('-u', '--username', dest='username', help='username') parser.add_option('-p', '--password', dest='password', @@ -64,7 +73,13 @@ def _main(): if not options.gerrit_url: parser.error("Must specify Gerrit URL with --gerrit-url") - if options.username and options.password: + if _kerberos_support and options.kerberos_auth: + if options.username or options.password \ + or options.basic_auth or options.netrc: + parser.error("--kerberos-auth may not be used together with " + "--username, --password, --basic-auth or --netrc") + auth = HTTPKerberosAuth(mutual_authentication=OPTIONAL) + elif options.username and options.password: if options.netrc: logging.warning("--netrc option ignored") if options.basic_auth: |
