Esempio n. 1
0
    def get_file(self, repository, path, revision, *args, **kwargs):
        """Return the contents of a file at the specified revision.

        Args:
            repository (reviewboard.scmtools.models.Repository):
                The repository configured to use Gerrit.

            path (unicode):
                The file path (ignored).

            revision (unicode):
                The file's Git object ID.

            *args (tuple):
                Ignored positional arguments.

            **kwargs (dict):
                Ignored keyword arguments.

        Returns:
            bytes:
            The contents of the file.

        Raises:
            reviewboard.hostingsvcs.errors.FileNotFoundError:
                The file does not exist in the remote repository.

            reviewboard.hostingsvcs.errors.HostingServiceAPIError:
                An error occurred communicating with the Gerrit API.
        """
        url = self._build_project_api_url(repository, 'blobs', revision,
                                          'content')

        try:
            rsp = self.client.http_get(url).data
        except HostingServiceAPIError as e:
            if e.http_code == 404:
                raise FileNotFoundError(path, revision=revision)

            raise HostingServiceAPIError(
                ugettext('Could not get file "%(file)s" at revision '
                         '"%(rev)s": %(error)s') % {
                             'file': path,
                             'rev': revision,
                             'error': e.read(),
                         },
                http_code=e.http_code)

        try:
            return base64.b64decode(rsp)
        except Exception as e:
            raise HostingServiceAPIError(
                ugettext('An error occurred while retrieving "%(file)s" at '
                         'revision "%(rev)s" from Gerrit: the response could '
                         'not be decoded: %(error)s') % {
                             'file': path,
                             'rev': revision,
                             'error': e,
                         })
Esempio n. 2
0
    def api_get(self, url, raw_content=False):
        """Perform an HTTP GET request to the API.

        Args:
            url (unicode):
                The full URL to the API resource.

            raw_content (bool, optional):
                If set to ``True``, the raw content of the result will be
                returned, instead of a parsed XML result.

        Returns:
            object:
            The parsed content of the result, as a dictionary, or the raw
            bytes content if ``raw_content`` is ``True``.
        """
        hosting_service = self.hosting_service

        try:
            account_data = hosting_service.account.data
            api_username = '******' % (account_data['domain'],
                                      hosting_service.account.username)
            api_key = decrypt_password(account_data['api_key'])

            response = self.http_get(
                url,
                username=api_username,
                password=api_key,
                headers={
                    'Accept': self.API_MIMETYPE,
                })
            data = response.data

            if raw_content:
                return data
            else:
                return self.parse_xml(data)
        except HTTPError as e:
            data = e.read()
            msg = str(e)

            rsp = self.parse_xml(data)

            if rsp and 'errors' in rsp:
                errors = rsp['errors']

                if 'error' in errors:
                    msg = errors['error']

            if e.code == 401:
                raise AuthorizationError(msg)
            else:
                raise HostingServiceAPIError(msg, http_code=e.code, rsp=rsp)
        except URLError as e:
            raise HostingServiceAPIError(e.reason)
Esempio n. 3
0
    def process_http_error(self, request, e):
        """Process an HTTP error, converting to a HostingServiceError.

        Args:
            request (reviewboard.hostingsvcs.service.
                     HostingServiceHTTPRequest):
                The request that resulted in an error.

            e (urllib2.URLError):
                The error to process.

        Raises:
            reviewboard.hostingsvcs.errors.HostingServiceAPIError:
                An error occurred communicating with the Gerrit API. A payload
                is available.

            reviewboard.hostingsvcs.errors.HostingServiceError:
                An error occurred communicating with the Gerrit API. A payload
                is not available.

            reviewboard.scmtools.errors.UnverifiedCertificateError:
                The SSL certificate was not able to be verified.
        """
        super(GerritClient, self).process_http_error(request, e)

        if isinstance(e, HTTPError):
            code = e.getcode()

            try:
                raise HostingServiceAPIError(e.reason, code, e.read())
            except AttributeError:
                raise HostingServiceError(e.reason, code)
        elif isinstance(e, URLError):
            raise HostingServiceError(e.reason)
Esempio n. 4
0
    def _check_api_error(self, e):
        data = e.read()

        try:
            rsp = json.loads(data)
        except:
            rsp = None

        message = data

        if rsp and 'error' in rsp:
            error = rsp['error']

            if 'message' in error:
                message = error['message']

        if message:
            message = six.text_type(message)

        if e.code == 401:
            self._raise_auth_error(message)
        elif e.code == 404:
            if message.startswith('Repository'):
                raise HostingServiceError(message, http_code=e.code)

            # We don't have a path here, but it will be filled in inside
            # _api_get_src.
            raise FileNotFoundError('')
        else:
            raise HostingServiceAPIError(
                message
                or (ugettext('Unexpected HTTP %s error when talking to '
                             'Bitbucket') % e.code),
                http_code=e.code,
                rsp=e)
Esempio n. 5
0
    def http_request(self,
                     url,
                     body=None,
                     headers=None,
                     method='GET',
                     username=None,
                     password=None):
        """Make an HTTP request to the given URL and return the result.

        This method requires both the username and password arguments to be
        passed since all Gerrit API endpoints require authentication.

        Args:
            url (unicode):
                The URL to make the request against.

            body (unicode, optional):
                The request body.

            headers (dict, optional):
                Additional headers to include in the request.

            method (unicode, optional):
                The HTTP method to use for the request. This defaults to GET.

            username (unicode):
                The username to use for authentication.

            password (unicode):
                The password to use for authentication.

        Returns:
            tuple:
            A 2-tuple of:

            * The response body (:py:class:`bytes`).
            * The response headers (:py:class:`dict`).
        """
        assert username is not None
        assert password is not None

        opener = self.get_opener(url, username, password)
        request = URLRequest(url, body, headers, method=method)

        # Gerrit 2.14+ require Basic Auth, so add that header. Old versions
        # use Digest Auth, which get_opener() already prepared.
        if username is not None and password is not None:
            request.add_basic_auth(username, password)

        try:
            response = opener.open(request)
        except HTTPError as e:
            try:
                raise HostingServiceAPIError(e.reason, e.getcode(), e.read())
            except AttributeError:
                raise HostingServiceError(e.reason, e.getcode())
        except URLError as e:
            raise HostingServiceError(e.reason)

        return response.read(), response.headers
    def process_http_error(self, request, e):
        """Process an HTTP error, raising a result.

        This will look at the error, raising a more suitable exception
        in its place.

        Args:
            request (reviewboard.hostingsvcs.service.HostingServiceHTTPRequest,
                     unused):
                The request that resulted in an error.

            e (urllib2.URLError):
                The error to check.

        Raises:
            reviewboard.hostingsvcs.errors.AuthorizationError:
                The credentials provided were not valid.

            reviewboard.hostingsvcs.errors.HostingServiceAPIError:
                An error occurred communicating with the API. An unparsed
                payload is available.

            reviewboard.hostingsvcs.errors.HostingServiceError:
                There was an unexpected error performing the request.

            reviewboard.scmtools.errors.UnverifiedCertificateError:
                The SSL certificate was not able to be verified.
        """
        # Perform any default checks.
        super(ReviewBoardGatewayClient, self).process_http_error(request, e)

        if isinstance(e, HTTPError):
            code = e.getcode()

            if e.code == 401:
                raise AuthorizationError(
                    ugettext('The username or password is incorrect.'))
            elif e.code == 404:
                raise HostingServiceAPIError(
                    ugettext('The API endpoint was not found.'),
                    http_code=code)
            else:
                msg = e.read()

                raise HostingServiceAPIError(msg, http_code=code, rsp=msg)
        else:
            raise HostingServiceError(e.reason)
    def api_authenticate(self, username, password):
        """Authenticate against the RB Gateway server.

        This will attempt to authenticate with the given credentials. If
        successful, information on the session, including an API token for
        further API requests, will be returned.

        Args:
            username (unicode):
                The username to authenticate with.

            password (unicode):
                The password to authenticate with.

        Returns:
            dict:
            The new session information.

        Raises:
            reviewboard.hostingsvcs.errors.AuthorizationError:
                The credentials provided were not valid.

            reviewboard.hostingsvcs.errors.HostingServiceError:
                Error retrieving the file contents. There may be a more
                specific subclass raised. See :py:meth:`process_http_error`.

            reviewboard.scmtools.errors.UnverifiedCertificateError:
                The SSL certificate was not able to be verified.
        """
        try:
            response = self.http_post('%s/session' % self.api_url,
                                      username=username,
                                      password=password)

            return response.json
        except HostingServiceAPIError as e:
            if e.http_code == 404:
                raise HostingServiceAPIError(
                    ugettext('A Review Board Gateway server was not found at '
                             'the provided URL. Make sure you are providing '
                             'the root of the server, and not a path '
                             'within it.'))

            raise
Esempio n. 8
0
    def get_commits(self, repository, branch=None, start=None, limit=None):
        """Return a list of commits from the API.

        Args:
            repository (reviewboard.scmtools.models.Repository):
                The repository configured to use Gerrit.

            branch (unicode, optional):
                The branch to retrieve commits for.

            start (unicode, optional):
                The commit SHA1 to start retrieving commits at.

            limit (int, optional):
                The number of commits to retrieve. If unspecified, the default
                is 30 (which is also the maximum).

        Returns:
            list of reviewboard.scmtools.core.Commit:
            The commits returned by the API. These commits will not have diffs
            attached.

        Raises:
            reviewboard.hostingsvcs.errors.HostingServiceAPIError:
                An error occurred communicating with the Gerrit API.
        """
        if not start:
            start = branch

        query = {
            field: six.text_type(value).encode('utf-8')
            for field, value in (('start', start), ('limit', limit))
            if value is not None
        }

        url = self._build_project_api_url(repository, ('all-commits',),
                                          query=query)

        try:
            rsp = self.client.api_get(url)
        except HostingServiceAPIError as e:
            # get_change uses this under the hood to retrieve a single commit,
            # so we can specialize the error message to make it more useful in
            # that case.
            if limit == 1:
                raise HostingServiceAPIError(
                    ugettext('Could not retrieve commit "%(rev)s": %(error)s')
                    % {
                        'rev': start,
                        'error': e.message,
                    },
                    http_code=e.http_code,
                    rsp=e.rsp)
            else:
                raise HostingServiceAPIError(
                    ugettext('Could not retrieve commits starting at '
                             '"%(rev)s": %(error)s')
                    % {
                        'rev': start,
                        'error': e.message,
                    },
                    http_code=e.getcode(),
                    rsp=e.rsp)

        return [
            self._parse_commit(meta)
            for meta in rsp
        ]
Esempio n. 9
0
 def _http_request(client, *args, **kwargs):
     raise HostingServiceAPIError('', http_code=404)