Пример #1
0
    def run(self, arguments, *args, **kwargs):
        account_id = self.parse_command_line(arguments)

        try:
            account = Gerrit.get_account(account_id or 'self')
            emails = Gerrit.get_emails(account_id or 'self')

        except PyCRError as why:
            fail('cannot list account emails', why)

        table = PrettyTable(['Email', 'Preferred', 'Confirmed'])
        table.align = 'l'

        for email in emails:
            table.add_row([
                email.email,
                checkmark(True) if email.preferred else '',
                'No' if email.pending_confirmation else 'Yes'
            ])

        with Pager(command=self.name):
            print 'Account: {}'.format(account.username)
            if emails:
                print table
            else:
                print 'No email address'
Пример #2
0
    def parse_command_line(arguments):
        """Parse the SHOW command command-line arguments

        Returns a tuple containing three lists:
                - the list of ChangeInfo
                - the list of reviewers to add
                - the list of reviewers to delete

        :param arguments: a list of command-line arguments to parse
        :type arguments: list[str]
        :rtype: tuple[ChangeInfo, list[str], list[str]]
        """

        changes, to_add, to_del = [], [], []

        for argument in arguments:
            if argument in ('-h', '--help'):
                # Manually handle the --help flag
                Assign.display_help()

            if argument[0] == '+':
                to_add.append(argument[1:])
            elif argument[0] == '-':
                to_del.append(argument[1:])
            else:
                changes.append(argument)

        if not to_add and not to_del:
            fail('please specify reviewer(s) to add or delete')

        return fetch_change_list_or_fail(changes), to_add, to_del
Пример #3
0
    def run(self, arguments, *args, **kwargs):
        account_id = self.parse_command_line(arguments)

        try:
            account = Gerrit.get_account(account_id or 'self')
            keys = Gerrit.get_ssh_keys(account_id or 'self')

        except PyCRError as why:
            fail('cannot list account SSH keys', why)

        table = PrettyTable(
            ['Id', 'Algorithm', 'Comment', 'Valid', 'Encoded key'])
        table.align = 'l'

        for key in keys:
            table.add_row([
                key.seq, key.algorithm, key.comment,
                checkmark(key.valid), key.encoded_key
            ])

        with Pager(command=self.name):
            print 'Account: {}'.format(account.username)
            if keys:
                print table
            else:
                print 'No SSH keys'
Пример #4
0
    def get_remote_base_url(cls):
        """
        Return the Gerrit Code Review server base URL.

        RETURNS
            the Gerrit Code Review server base URL as a string
        """

        url = Config.get('gerrit.host')
        unsecure = Config.get('gerrit.unsecure', False)

        if url is None:
            fail('gerrit.host not set')

        # From Gerrit Code Review Documentation (section Authentication):
        # https://gerrit-review.googlesource.com/Documentation/rest-api.html
        #
        # Users (and programs) may authenticate using HTTP authentication by
        # supplying the HTTP password from the user's account settings page.
        # Gerrit by default uses HTTP digest authentication. To authenticate,
        # prefix the endpoint URL with /a/. For example to authenticate to
        # /projects/ request URL /a/projects/.

        if RequestFactory.require_auth():
            url = '%s/a' % url

        if not url.startswith('http://') or not url.startswith('https://'):
            return '%s://%s' % ('http' if unsecure else 'https', url)

        return url
Пример #5
0
    def parse_command_line(arguments):
        """
        Parse the LIST command command-line arguments.

        PARAMETERS
            arguments: a list of command-line arguments to parse

        RETURNS
            a list of ChangeInfo
        """

        parser = argparse.ArgumentParser(
            description='List changes by owner and status.')
        parser.add_argument(
            '--status', default='open',
            help='the status of the changes (default: open)')

        exclusive = parser.add_mutually_exclusive_group()
        exclusive.add_argument(
            '--owner', default='self',
            help='the owner of the changes (default: self)')
        exclusive.add_argument(
            '--watched', default=False, action='store_true',
            help='list only watched changes')

        cmdline = parser.parse_args(arguments)

        if cmdline.status not in Gerrit.get_all_statuses():
            fail('argument --status: invalid choice "%s" (choose from %s)' %
                (cmdline.status,
                 ', '.join(["'%s'" % st for st in Gerrit.get_all_statuses()])))

        # Fetch changes details
        return cmdline.owner, cmdline.status, cmdline.watched
Пример #6
0
    def get_remote_base_url(cls):
        """Return the Gerrit Code Review server base URL

        :rtype: str
        """

        url = Config.get("gerrit.host")
        unsecure = Config.get("gerrit.unsecure", False)

        if url is None:
            fail("gerrit.host not set")

        # From Gerrit Code Review Documentation (section Authentication):
        # https://gerrit-review.googlesource.com/Documentation/rest-api.html
        #
        # Users (and programs) may authenticate using HTTP authentication by
        # supplying the HTTP password from the user's account settings page.
        # Gerrit by default uses HTTP digest authentication. To authenticate,
        # prefix the endpoint URL with /a/. For example to authenticate to
        # /projects/ request URL /a/projects/.

        if RequestFactory.require_auth():
            url = "{}/a".format(url)

        if not url.startswith("http://") or not url.startswith("https://"):
            return "{}://{}".format("http" if unsecure else "https", url)

        return url
Пример #7
0
    def run(self, arguments, *args, **kwargs):
        change_id, score, message, label = self.parse_command_line(arguments)

        try:
            change = Gerrit.get_change(change_id)

            if message is None:
                initial_content = [
                    '',
                    ('# Please enter the comment message for your review. '
                     'Lines starting'), "# with '#' will be ignored.", '#'
                ]
                initial_content.extend(
                    ['# %s' % line for line in change.raw_str().splitlines()])
                initial_content.append('#')

                message = raw_input_editor(os.linesep.join(initial_content))
                message = strip_comments(message)

            if score is None:
                score = ask('Please enter your review score', Gerrit.SCORES)

            review = Gerrit.set_review(score, message, change.uuid, label)

        except NoSuchChangeError as why:
            self.log.debug(str(why))
            fail('invalid change')

        except PyCRError as why:
            fail('cannot post review', why)

        print Formatter.format(self.tokenize(change, review))
Пример #8
0
    def run(self, arguments, *args, **kwargs):
        change_id, score, message, label = self.parse_command_line(arguments)

        try:
            change = Gerrit.get_change(change_id)

            if message is None:
                initial_content = [
                    '',
                    ('# Please enter the comment message for your review. '
                     'Lines starting'),
                    "# with '#' will be ignored.",
                    '#'
                ]
                initial_content.extend(
                    ['# %s' % line for line in change.raw_str().splitlines()])
                initial_content.append('#')

                message = raw_input_editor(os.linesep.join(initial_content))
                message = strip_comments(message)

            if score is None:
                score = ask('Please enter your review score', Gerrit.SCORES)

            review = Gerrit.set_review(score, message, change.uuid, label)

        except NoSuchChangeError as why:
            self.log.debug(str(why))
            fail('invalid change')

        except PyCRError as why:
            fail('cannot post review', why)

        print Formatter.format(self.tokenize(change, review))
Пример #9
0
    def parse_command_line(arguments):
        """
        Parse the SHOW command command-line arguments.

        PARAMETERS
            arguments: a list of command-line arguments to parse

        RETURNS
            a tuple containing three lists:
                - the list of ChangeInfo
                - the list of reviewers to add
                - the list of reviewers to delete
        """

        changes, to_add, to_del = [], [], []

        for argument in arguments:
            if argument in ('-h', '--help'):
                # Manually handle the --help flag
                Assign.display_help()

            if argument[0] == '+':
                to_add.append(argument[1:])
            elif argument[0] == '-':
                to_del.append(argument[1:])
            else:
                changes.append(argument)

        if not to_add and not to_del:
            fail('please specify reviewer(s) to add or delete')

        return fetch_change_list_or_fail(changes), to_add, to_del
Пример #10
0
    def get_remote_base_url(cls):
        """Return the Gerrit Code Review server base URL

        :rtype: str
        """

        url = Config.get('gerrit.host')
        unsecure = Config.get('gerrit.unsecure', False)

        if url is None:
            fail('gerrit.host not set')

        # From Gerrit Code Review Documentation (section Authentication):
        # https://gerrit-review.googlesource.com/Documentation/rest-api.html
        #
        # Users (and programs) may authenticate using HTTP authentication by
        # supplying the HTTP password from the user's account settings page.
        # Gerrit by default uses HTTP digest authentication. To authenticate,
        # prefix the endpoint URL with /a/. For example to authenticate to
        # /projects/ request URL /a/projects/.

        if RequestFactory.require_auth():
            url = '{}/a'.format(url)

        if not url.startswith('http://') or not url.startswith('https://'):
            return '{}://{}'.format('http' if unsecure else 'https', url)

        return url
Пример #11
0
    def run(self, arguments, *args, **kwargs):
        account_id = self.parse_command_line(arguments)

        try:
            changes = Gerrit.get_starred_changes(account_id or 'self')

        except PyCRError as why:
            fail('cannot list account starred changes', why)

        with Pager(command=self.name):
            for idx, change in enumerate(changes):
                print Formatter.format(self.tokenize(idx, change))
Пример #12
0
    def run(self, arguments, *args, **kwargs):
        change_id = self.parse_command_line(arguments)

        try:
            change = Gerrit.rebase(change_id)

        except NoSuchChangeError as why:
            self.log.debug(str(why))
            fail('invalid change')

        except PyCRError as why:
            fail('cannot rebase', why)

        print Formatter.format(self.tokenize(change))
Пример #13
0
    def run_get(arguments, *args, **kwargs):
        """???"""

        del args, kwargs

        parser = argparse.ArgumentParser(description='Display ssh key')
        parser.add_argument('account', type=str, help='account ID')
        parser.add_argument('uuid', type=int, help='SSH key ID')
        cmdline = parser.parse_args(arguments)

        try:
            key = Gerrit.get_ssh_key(cmdline.account, cmdline.uuid)

        except PyCRError as why:
            fail('cannot list account SSH keys', why)

        print key.ssh_public_key.strip()
Пример #14
0
    def run(self, arguments, *args, **kwargs):
        account_ids = self.parse_command_line(arguments)

        try:
            accounts = (Gerrit.get_account(a) for a in account_ids or ['self'])

        except PyCRError as why:
            fail('cannot list accounts', why)

        table = PrettyTable(['Username', 'Name', 'Email'])
        table.align = 'l'

        for account in set(accounts):
            table.add_row([account.username, account.name, account.email])

        with Pager(command=self.name):
            print table
Пример #15
0
def fetch_change_list_or_fail(change_list):
    """Same as fetch_change_list, but fail if the final change list is empty

    :param change_list: the list of changes
    :type change_list: list[str]
    :rtype: list[ChangeInfo]
    """

    changes = fetch_change_list(change_list)

    # If no correct changes found
    if not changes:
        message = 'no valid change-id provided'
        if not RequestFactory.require_auth():
            message += ' (missing authentication?)'
        fail(message)

    return changes
Пример #16
0
def fetch_change_list_or_fail(change_list):
    """Same as fetch_change_list, but fail if the final change list is empty

    :param change_list: the list of changes
    :type change_list: list[str]
    :rtype: list[ChangeInfo]
    """

    changes = fetch_change_list(change_list)

    # If no correct changes found
    if not changes:
        message = 'no valid change-id provided'
        if not RequestFactory.require_auth():
            message += ' (missing authentication?)'
        fail(message)

    return changes
Пример #17
0
    def run(self, arguments, *args, **kwargs):
        account_id = self.parse_command_line(arguments)

        try:
            account = Gerrit.get_account(account_id or 'self')
            prefs = Gerrit.get_diff_prefs(account_id or 'self')

        except PyCRError as why:
            fail('cannot list account diff preferences', why)

        table = PrettyTable(['Preference', 'Value'])
        table.align['Preference'] = 'l'
        table.align['Value'] = 'c'

        table.add_row(['Context', prefs.context])
        table.add_row(
            ['Expand all comments',
             checkmark(prefs.expand_all_comments)])
        table.add_row(['Ignore whitespace', prefs.ignore_whitespace])
        table.add_row(
            ['Intraline difference',
             checkmark(prefs.intraline_difference)])
        table.add_row(['Line length', prefs.line_length])
        table.add_row(['Manual review', checkmark(prefs.manual_review)])
        table.add_row(['Retain header', checkmark(prefs.retain_header)])
        table.add_row(
            ['Show line endings',
             checkmark(prefs.show_line_endings)])
        table.add_row(['Show tabs', checkmark(prefs.show_tabs)])
        table.add_row([
            'Show whitespace errors',
            checkmark(prefs.show_whitespace_errors)
        ])
        table.add_row(['Skip deleted', checkmark(prefs.skip_deleted)])
        table.add_row(['Skip uncommented', checkmark(prefs.skip_uncommented)])
        table.add_row(
            ['Syntax highlighting',
             checkmark(prefs.syntax_highlighting)])
        table.add_row(['Tab size', prefs.tab_size])

        with Pager(command=self.name):
            print 'Account: {}'.format(account.username)
            print table
Пример #18
0
    def run(self, arguments, *args, **kwargs):
        if not arguments:
            fail('No command given.')

        command = arguments[0]
        arguments = arguments[1:]

        if command in ('-h', '--help'):
            sys.exit(self.get_usage())

        if command not in self.subcommands:
            fail('Unknown subcommand: {}'.format(command))

        if command == 'get':
            self.run_get(arguments, *args, **kwargs)
        elif command == 'add':
            self.run_add(arguments, *args, **kwargs)
        elif command == 'remove':
            self.run_remove(arguments, *args, **kwargs)
Пример #19
0
    def run(self, arguments, *args, **kwargs):
        account_id = self.parse_command_line(arguments)

        try:
            groups = Gerrit.get_groups(account_id or 'self')

        except PyCRError as why:
            fail('cannot list account groups', why)

        table = PrettyTable(['Group', 'Description', 'Visible to all'])
        table.align = 'l'
        table.align['Visible to all'] = 'c'

        for group in groups:
            table.add_row([group.name, group.description or '',
                           checkmark(group.options.visible_to_all)])

        with Pager(command=self.name):
            print table
Пример #20
0
    def run(self, arguments, *args, **kwargs):
        owner, status, watched = self.parse_command_line(arguments)

        try:
            if watched:
                changes = Gerrit.list_watched_changes(status=status)
            else:
                changes = Gerrit.list_changes(status=status, owner=owner)

        except QueryError as why:
            # No result, not an error
            self.log.debug(str(why))
            return

        except PyCRError as why:
            fail('cannot list changes', why)

        with Pager(command=self.name):
            for idx, change in enumerate(changes):
                print Formatter.format(self.tokenize(idx, change))
Пример #21
0
    def run(self, arguments, *args, **kwargs):
        owner, status, watched = self.parse_command_line(arguments)

        try:
            if watched:
                changes = Gerrit.list_watched_changes(status=status)
            else:
                changes = Gerrit.list_changes(status=status, owner=owner)

        except QueryError as why:
            # No result, not an error
            self.log.debug(str(why))
            return

        except PyCRError as why:
            fail('cannot list changes', why)

        with Pager(command=self.name):
            for idx, change in enumerate(changes):
                print Formatter.format(self.tokenize(idx, change))
Пример #22
0
    def run(self, arguments, *args, **kwargs):
        account_id = self.parse_command_line(arguments)

        try:
            groups = Gerrit.get_groups(account_id or 'self')

        except PyCRError as why:
            fail('cannot list account groups', why)

        table = PrettyTable(['Group', 'Description', 'Visible to all'])
        table.align = 'l'
        table.align['Visible to all'] = 'c'

        for group in groups:
            table.add_row([
                group.name, group.description or '',
                checkmark(group.options.visible_to_all)
            ])

        with Pager(command=self.name):
            print table
Пример #23
0
    def run(self, arguments, *args, **kwargs):
        """
        The entry point for the SUBMIT command.

        Rebase revision.

        PARAMETERS
            arguments: a list of command-line arguments to parse
        """

        change_id = Submit.parse_command_line(arguments)

        try:
            change = Gerrit.get_change(change_id)

            if not Gerrit.submit(change.uuid):
                fail('submit could not be merged')

        except NoSuchChangeError as why:
            self.log.debug(str(why))
            fail('invalid change')

        except PyCRError as why:
            fail('cannot submit', why)

        print Formatter.format(Submit.tokenize(change))
Пример #24
0
    def load(cls, filename, quiet=False):
        """Parse a configuration file and extract this script's configuration

        :param filename: the path to the config file
        :type filename: str
        """

        if not os.path.isfile(filename):
            if not quiet:
                warn('{}: No such file or directory'.format(filename))

            return

        parser = SafeConfigParser()

        try:
            with open(filename, 'r') as config:
                parser.readfp(config, filename)
        except ParsingError as why:
            fail('failed to parse configuration: {}'.format(config), why)

        cls._store_config(parser)
Пример #25
0
def fetch_change_list_or_fail(change_list):
    """
    Same as fetch_change_list, but fail if the final change list is empty.

    PARAMETERS
        change_list: list of string

    RETURNS
        a tuple with a list of ChangeInfo, and a list of unknown changes
    """

    changes = fetch_change_list(change_list)

    # If no correct change found
    if not changes:
        message = 'no valid change-id provided'

        if not RequestFactory.require_auth():
            message += ' (missing authentication?)'

        fail(message)

    return changes
Пример #26
0
    def run(self, arguments, *args, **kwargs):
        account_id = self.parse_command_line(arguments)

        try:
            account = Gerrit.get_account(account_id or 'self')
            prefs = Gerrit.get_diff_prefs(account_id or 'self')

        except PyCRError as why:
            fail('cannot list account diff preferences', why)

        table = PrettyTable(['Preference', 'Value'])
        table.align['Preference'] = 'l'
        table.align['Value'] = 'c'

        table.add_row(['Context', prefs.context])
        table.add_row(['Expand all comments',
                       checkmark(prefs.expand_all_comments)])
        table.add_row(['Ignore whitespace', prefs.ignore_whitespace])
        table.add_row(['Intraline difference',
                       checkmark(prefs.intraline_difference)])
        table.add_row(['Line length', prefs.line_length])
        table.add_row(['Manual review', checkmark(prefs.manual_review)])
        table.add_row(['Retain header', checkmark(prefs.retain_header)])
        table.add_row(['Show line endings',
                       checkmark(prefs.show_line_endings)])
        table.add_row(['Show tabs', checkmark(prefs.show_tabs)])
        table.add_row(['Show whitespace errors',
                       checkmark(prefs.show_whitespace_errors)])
        table.add_row(['Skip deleted', checkmark(prefs.skip_deleted)])
        table.add_row(['Skip uncommented', checkmark(prefs.skip_uncommented)])
        table.add_row(['Syntax highlighting',
                       checkmark(prefs.syntax_highlighting)])
        table.add_row(['Tab size', prefs.tab_size])

        with Pager(command=self.name):
            print 'Account: {}'.format(account.username)
            print table
Пример #27
0
    def run(self, arguments, *args, **kwargs):
        account_id = self.parse_command_line(arguments)

        try:
            account = Gerrit.get_account(account_id or 'self')
            capabilities = Gerrit.get_capabilities(account_id or 'self')

        except PyCRError as why:
            fail('cannot list account capabilities', why)

        table = PrettyTable(['Capability', 'Value'])
        table.align['Capability'] = 'l'
        table.align['Value'] = 'c'

        table.add_row(['Administrate server',
                       checkmark(capabilities.administrate_server)])
        table.add_row(['Min Query limit', capabilities.query_limit.min])
        table.add_row(['Max Query limit', capabilities.query_limit.max])
        table.add_row(['Create account',
                       checkmark(capabilities.create_account)])
        table.add_row(['Create group', checkmark(capabilities.create_group)])
        table.add_row(['Create project',
                       checkmark(capabilities.create_project)])
        table.add_row(['Email reviewers',
                       checkmark(capabilities.email_reviewers)])
        table.add_row(['Kill task', checkmark(capabilities.kill_task)])
        table.add_row(['View caches', checkmark(capabilities.view_caches)])
        table.add_row(['Flush caches', checkmark(capabilities.flush_caches)])
        table.add_row(['View connections',
                       checkmark(capabilities.view_connections)])
        table.add_row(['View queue', checkmark(capabilities.view_queue)])
        table.add_row(['Run GC', checkmark(capabilities.run_gc)])

        with Pager(command=self.name):
            print 'Account: {}'.format(account.username)
            print table
Пример #28
0
    def run(self, arguments, *args, **kwargs):
        account_id = self.parse_command_line(arguments)

        try:
            account = Gerrit.get_account(account_id or 'self')
            emails = Gerrit.get_emails(account_id or 'self')

        except PyCRError as why:
            fail('cannot list account emails', why)

        table = PrettyTable(['Email', 'Preferred', 'Confirmed'])
        table.align = 'l'

        for email in emails:
            table.add_row([email.email,
                           checkmark(True) if email.preferred else '',
                           'No' if email.pending_confirmation else 'Yes'])

        with Pager(command=self.name):
            print 'Account: {}'.format(account.username)
            if emails:
                print table
            else:
                print 'No email address'
Пример #29
0
    def run(self, arguments, *args, **kwargs):
        account_id = self.parse_command_line(arguments)

        try:
            account = Gerrit.get_account(account_id or 'self')
            keys = Gerrit.get_ssh_keys(account_id or 'self')

        except PyCRError as why:
            fail('cannot list account SSH keys', why)

        table = PrettyTable(
            ['Id', 'Algorithm', 'Comment', 'Valid', 'Encoded key'])
        table.align = 'l'

        for key in keys:
            table.add_row([key.seq, key.algorithm, key.comment,
                           checkmark(key.valid), key.encoded_key])

        with Pager(command=self.name):
            print 'Account: {}'.format(account.username)
            if keys:
                print table
            else:
                print 'No SSH keys'
Пример #30
0
    def run(self, arguments, *args, **kwargs):
        change_id = self.parse_command_line(arguments)

        try:
            change = Gerrit.get_change(change_id)

            if not Gerrit.submit(change.uuid):
                fail('change could not be merged')

        except NoSuchChangeError as why:
            self.log.debug(str(why))
            fail('invalid change')

        except PyCRError as why:
            fail('cannot submit', why)

        print Formatter.format(self.tokenize(change))
Пример #31
0
    def run(self, arguments, *args, **kwargs):
        change_id = self.parse_command_line(arguments)

        try:
            change = Gerrit.get_change(change_id)

            if not Gerrit.submit(change.uuid):
                fail('change could not be merged')

        except NoSuchChangeError as why:
            self.log.debug(str(why))
            fail('invalid change')

        except PyCRError as why:
            fail('cannot submit', why)

        print Formatter.format(self.tokenize(change))
Пример #32
0
    def send(cls, endpoint, method=GET, encoding=JSON, **kwargs):
        """
        Return the result of a HTTP request.

        PARAMETERS
            endpoint: the endpoint to the request
            method: HTTP protocol method to use (either GET or POST)
            encoding: expected response format (JSON, base64 or plain text)
            **kwargs: any additional arguments to the underlying API call

        RETURNS
            a tuple of two elements: the raw response (stripped from magic for
                the JSON format) and the decoded object of that response, or
                None if expected_encoding is PLAIN. If response is no content
                (status code 204), returns a tuple of None values

        RAISES
            requests.exceptions.RequestException on error
        """

        cls.log.debug('Query URL: %s' % endpoint)

        try:
            response = cls.get_session().request(method, endpoint, **kwargs)

            if response.status_code == 204:
                # No content
                return None, None

            if response.status_code != 200:
                response.raise_for_status()

        except ConnectionError as why:
            fail('Unable to connect to %s' % urlparse(endpoint).netloc)

        except RequestException as why:
            raise RequestError(
                response.status_code, response,
                'HTTP %s request failed: %s' % (method, endpoint), why)

        if encoding == BASE64:
            encoded = response.text

            cls.log.debug('%d bytes to decode', len(encoded))

            pad = -len(encoded) % 4
            if pad == 3:
                b64response = encoded[:-1]
            else:
                b64response = encoded + b'=' * pad

            cls.log.debug('%d padded bytes to decode', len(b64response))
            cls.log.debug(b64response)

            try:
                decoded = base64.decodestring(b64response)
            except TypeError:
                # TypeError: incorrect padding
                cls.log.exception('cannot decode base64 stream')
                fail('invalid response stream (could not decode base64)')

        elif encoding == JSON:
            if not response.text.startswith(GERRIT_MAGIC):
                fail('invalid response stream (magic prefix not found)')

            json_response = response.text[len(GERRIT_MAGIC):]
            decoded = json.loads(json_response)

        else:
            decoded = None

        return response.text, decoded
Пример #33
0
    def send(cls, endpoint, method=GET, encoding=JSON, **kwargs):
        """Return the result of a HTTP request

        Returns a tuple of two elements: the raw response (stripped from magic
        for the JSON format) and the decoded object of that response, or None
        if encoding is PLAIN. If response is no content (status code
        204), returns a tuple of None values.

        :param endpoint: the endpoint to the request
        :type endpoint: str
        :param method: HTTP protocol method to use (either GET or POST)
        :type method: str
        :param encoding: expected response format (JSON, base64 or plain text)
        :type encoding: str
        :param **kwargs: any additional arguments to the underlying API call
        :type **kwargs: dict
        :rtype: str, dict | None
        :raise: requests.exceptions.RequestException on error
        """

        cls.log.debug("Query URL: %s", endpoint)
        if cls.log.isEnabledFor(logging.DEBUG) and "data" in kwargs:
            if "headers" in kwargs and kwargs["headers"].get("content-type", "").endswith("json"):
                # Dump the JSON-encoded payload
                data = json.loads(kwargs["data"])
                cls.log.debug("JSON-encoded query payload")
                cls.log.debug(json.dumps(data, indent=2))

        try:
            response = cls.get_session().request(method, endpoint, **kwargs)

            if response.status_code == 204:
                # No content
                return None, None

            if response.status_code != 200:
                response.raise_for_status()

        except ConnectionError as why:
            fail("Unable to connect to %s" % urlparse(endpoint).netloc)

        except RequestException as why:
            raise RequestError(response.status_code, response, "HTTP %s request failed: %s" % (method, endpoint), why)

        if encoding == BASE64:
            encoded = response.text

            cls.log.debug("%d bytes to decode", len(encoded))

            pad = -len(encoded) % 4
            if pad == 3:
                b64response = encoded[:-1]
            else:
                b64response = encoded + b"=" * pad

            cls.log.debug("%d padded bytes to decode", len(b64response))
            cls.log.debug(b64response)

            try:
                decoded = base64.decodestring(b64response)
            except TypeError:
                # TypeError: incorrect padding
                cls.log.exception("cannot decode base64 stream")
                fail("invalid response stream (could not decode base64)")

        elif encoding == JSON:
            if not response.text.startswith(GERRIT_MAGIC):
                fail("invalid response stream (magic prefix not found)")

            json_response = response.text[len(GERRIT_MAGIC) :]
            decoded = json.loads(json_response)
            if cls.log.isEnabledFor(logging.DEBUG):
                cls.log.debug("JSON-encoded server reply")
                cls.log.debug(json.dumps(decoded, indent=2))

        else:
            decoded = None

        return response.text, decoded
Пример #34
0
    def send(cls, endpoint, method=GET, encoding=JSON, **kwargs):
        """Return the result of a HTTP request

        Returns a tuple of two elements: the raw response (stripped from magic
        for the JSON format) and the decoded object of that response, or None
        if encoding is PLAIN. If response is no content (status code
        204), returns a tuple of None values.

        :param endpoint: the endpoint to the request
        :type endpoint: str
        :param method: HTTP protocol method to use (either GET or POST)
        :type method: str
        :param encoding: expected response format (JSON, base64 or plain text)
        :type encoding: str
        :param **kwargs: any additional arguments to the underlying API call
        :type **kwargs: dict
        :rtype: str, dict | None
        :raise: requests.exceptions.RequestException on error
        """

        cls.log.debug('Query URL: %s', endpoint)
        if cls.log.isEnabledFor(logging.DEBUG) and 'data' in kwargs:
            if ('headers' in kwargs and kwargs['headers'].get(
                    'content-type', '').endswith('json')):
                # Dump the JSON-encoded payload
                data = json.loads(kwargs['data'])
                cls.log.debug('JSON-encoded query payload')
                cls.log.debug(json.dumps(data, indent=2))

        try:
            response = cls.get_session().request(method, endpoint, **kwargs)

            if response.status_code == 204:
                # No content
                return None, None

            if response.status_code != 200:
                response.raise_for_status()

        except ConnectionError as why:
            fail('Unable to connect to %s' % urlparse(endpoint).netloc)

        except RequestException as why:
            raise RequestError(
                response.status_code, response,
                'HTTP %s request failed: %s' % (method, endpoint), why)

        if encoding == BASE64:
            encoded = response.text

            cls.log.debug('%d bytes to decode', len(encoded))

            pad = -len(encoded) % 4
            if pad == 3:
                b64response = encoded[:-1]
            else:
                b64response = encoded + b'=' * pad

            cls.log.debug('%d padded bytes to decode', len(b64response))
            cls.log.debug(b64response)

            try:
                decoded = base64.decodestring(b64response)
            except TypeError:
                # TypeError: incorrect padding
                cls.log.exception('cannot decode base64 stream')
                fail('invalid response stream (could not decode base64)')

        elif encoding == JSON:
            if not response.text.startswith(GERRIT_MAGIC):
                fail('invalid response stream (magic prefix not found)')

            json_response = response.text[len(GERRIT_MAGIC):]
            decoded = json.loads(json_response)
            if cls.log.isEnabledFor(logging.DEBUG):
                cls.log.debug('JSON-encoded server reply')
                cls.log.debug(json.dumps(decoded, indent=2))

        else:
            decoded = None

        return response.text, decoded