示例#1
0
    def main(self, *args):
        """Add the review request URL to a commit message."""
        self.cmd_args = list(args)

        repository_info, self.tool = self.initialize_scm_tool(
            client_name=self.options.repository_type)
        server_url = self.get_server_url(repository_info, self.tool)
        api_client, api_root = self.get_api(server_url)
        self.setup_tool(self.tool, api_root=api_root)

        if not self.tool.can_amend_commit:
            raise NotImplementedError('rbt stamp is not supported with %s.'
                                      % self.tool.name)

        try:
            if self.tool.has_pending_changes():
                raise CommandError('Working directory is not clean.')
        except NotImplementedError:
            pass

        revisions = get_revisions(self.tool, self.cmd_args)

        # Use the ID from the command line options if present.
        if self.options.rid:
            review_request_id = self.options.rid

            try:
                review_request = api_root.get_review_request(
                    review_request_id=review_request_id)
            except APIError as e:
                raise CommandError('Error getting review request %s: %s'
                                   % (review_request_id, e))

            review_request_url = review_request.absolute_url
        else:
            review_request_id, review_request_url = \
                self. determine_review_request(
                    api_client, api_root, repository_info,
                    self.options.repository_name, revisions)

        if not review_request_url:
            raise CommandError('Could not determine the existing review '
                               'request URL to stamp with.')

        stamp_commit_with_review_url(revisions, review_request_url, self.tool)

        print('Successfully stamped change with the URL:')
        print(review_request_url)
示例#2
0
    def post_request(self, repository_info, repository, server_url, api_root,
                     review_request_id=None, changenum=None, diff_content=None,
                     parent_diff_content=None, commit_id=None,
                     base_commit_id=None,
                     submit_as=None, retries=3, base_dir=None):
        """Creates or updates a review request, and uploads a diff.

        On success the review request id and url are returned.
        """
        supports_posting_commit_ids = \
            self.tool.capabilities.has_capability('review_requests',
                                                  'commit_ids')

        if review_request_id:
            review_request = get_review_request(
                review_request_id, api_root,
                only_fields='absolute_url,bugs_closed,id,status',
                only_links='diffs,draft')

            if review_request.status == 'submitted':
                raise CommandError(
                    'Review request %s is marked as %s. In order to update '
                    'it, please reopen the review request and try again.'
                    % (review_request_id, review_request.status))
        else:
            # No review_request_id, so we will create a new review request.
            try:
                request_data = {
                    'repository': repository
                }

                if changenum:
                    request_data['changenum'] = changenum
                elif commit_id and supports_posting_commit_ids:
                    request_data['commit_id'] = commit_id

                if submit_as:
                    request_data['submit_as'] = submit_as

                review_requests = api_root.get_review_requests(
                    only_fields='',
                    only_links='create')
                review_request = review_requests.create(**request_data)
            except APIError as e:
                if e.error_code == 204 and changenum:
                    # The change number is already in use. Get the review
                    # request for that change and update it instead.
                    rid = e.rsp['review_request']['id']
                    review_request = api_root.get_review_request(
                        review_request_id=rid,
                        only_fields='absolute_url,bugs_closed,id,status',
                        only_links='diffs,draft')

                    if not self.options.diff_only:
                        review_request = review_request.update(
                            changenum=changenum)
                else:
                    raise CommandError('Error creating review request: %s' % e)

        if (not repository_info.supports_changesets or
            not self.options.change_only):
            try:
                diff_kwargs = {
                    'parent_diff': parent_diff_content,
                    'base_dir': base_dir,
                }

                if (base_commit_id and
                    self.tool.capabilities.has_capability('diffs',
                                                          'base_commit_ids')):
                    # Both the Review Board server and SCMClient support
                    # base commit IDs, so pass that along when creating
                    # the diff.
                    diff_kwargs['base_commit_id'] = base_commit_id

                review_request.get_diffs(only_fields='').upload_diff(
                    diff_content, **diff_kwargs)
            except APIError as e:
                error_msg = [
                    u'Error uploading diff\n\n',
                ]

                if e.error_code == 101 and e.http_status == 403:
                    error_msg.append(
                        u'You do not have permissions to modify '
                        u'this review request\n')
                elif e.error_code == 219:
                    error_msg.append(
                        u'The generated diff file was empty. This '
                        u'usually means no files were\n'
                        u'modified in this change.\n')
                else:
                    error_msg.append(str(e).decode('utf-8') + u'\n')

                error_msg.append(
                    u'Your review request still exists, but the diff is '
                    u'not attached.\n')

                error_msg.append(u'%s\n' % review_request.absolute_url)

                raise CommandError(u'\n'.join(error_msg))

        try:
            draft = review_request.get_draft(only_fields='commit_id')
        except APIError as e:
            raise CommandError('Error retrieving review request draft: %s' % e)

        # Stamp the commit message with the review request URL before posting
        # the review, so that we can use the stamped commit message when
        # guessing the description. This enables the stamped message to be
        # present on the review if the user has chosen to publish immediately
        # upon posting.
        if self.options.stamp_when_posting:
            if not self.tool.can_amend_commit:
                print('Cannot stamp review URL onto the commit message; '
                      'stamping is not supported with %s.' % self.tool.name)

            else:
                try:
                    stamp_commit_with_review_url(self.revisions,
                                                 review_request.absolute_url,
                                                 self.tool)
                    print('Stamped review URL onto the commit message.')
                except AlreadyStampedError:
                    print('Commit message has already been stamped')
                except Exception as e:
                    logging.debug('Caught exception while stamping the '
                                  'commit message. Proceeding to post '
                                  'without stamping.', exc_info=True)
                    print('Could not stamp review URL onto the commit '
                          'message.')

        # If the user has requested to guess the summary or description,
        # get the commit message and override the summary and description
        # options. The guessing takes place after stamping so that the
        # guessed description matches the commit when rbt exits.
        if not self.options.diff_filename:
            self.check_guess_fields()

        # Update the review request draft fields based on options set
        # by the user, or configuration.
        update_fields = {}

        if self.options.target_groups:
            update_fields['target_groups'] = self.options.target_groups

        if self.options.target_people:
            update_fields['target_people'] = self.options.target_people

        if self.options.depends_on:
            update_fields['depends_on'] = self.options.depends_on

        if self.options.summary:
            update_fields['summary'] = self.options.summary

        if self.options.branch:
            update_fields['branch'] = self.options.branch

        if self.options.bugs_closed:
            # Append to the existing list of bugs.
            self.options.bugs_closed = self.options.bugs_closed.strip(', ')
            bug_set = (set(re.split('[, ]+', self.options.bugs_closed)) |
                       set(review_request.bugs_closed))
            self.options.bugs_closed = ','.join(bug_set)
            update_fields['bugs_closed'] = self.options.bugs_closed

        if self.options.description:
            update_fields['description'] = self.options.description

        if self.options.testing_done:
            update_fields['testing_done'] = self.options.testing_done

        if ((self.options.description or self.options.testing_done) and
            self.options.markdown and
            self.tool.capabilities.has_capability('text', 'markdown')):
            # The user specified that their Description/Testing Done are
            # valid Markdown, so tell the server so it won't escape the text.
            update_fields['text_type'] = 'markdown'

        if self.options.change_description:
            update_fields['changedescription'] = \
                self.options.change_description

        if self.options.publish:
            update_fields['public'] = True

        if supports_posting_commit_ids and commit_id != draft.commit_id:
            update_fields['commit_id'] = commit_id or ''

        if update_fields:
            try:
                draft = draft.update(**update_fields)
            except APIError as e:
                raise CommandError(u'\n'.join([
                    u'Error updating review request draft: %s\n' % e,
                    u'Your review request still exists, but the diff is '
                    u'not attached.\n',
                    u'%s\n' % review_request.absolute_url,
                ]))

        return review_request.id, review_request.absolute_url
示例#3
0
文件: post.py 项目: hunz-dev/rbtools
    def post_request(self,
                     repository_info,
                     repository,
                     server_url,
                     api_root,
                     review_request_id=None,
                     changenum=None,
                     diff_content=None,
                     parent_diff_content=None,
                     commit_id=None,
                     base_commit_id=None,
                     submit_as=None,
                     retries=3,
                     base_dir=None):
        """Creates or updates a review request, and uploads a diff.

        On success the review request id and url are returned.
        """
        supports_posting_commit_ids = \
            self.tool.capabilities.has_capability('review_requests',
                                                  'commit_ids')

        if review_request_id:
            review_request = get_review_request(
                review_request_id,
                api_root,
                only_fields='absolute_url,bugs_closed,id,status,public',
                only_links='diffs,draft')

            if review_request.status == 'submitted':
                raise CommandError(
                    'Review request %s is marked as %s. In order to update '
                    'it, please reopen the review request and try again.' %
                    (review_request_id, review_request.status))
        else:
            # No review_request_id, so we will create a new review request.
            try:
                # Until we are Python 2.7+ only, the keys in request_data have
                # to be bytes. See bug 3753 for details.
                request_data = {b'repository': repository}

                if changenum:
                    request_data[b'changenum'] = changenum
                elif commit_id and supports_posting_commit_ids:
                    request_data[b'commit_id'] = commit_id

                if submit_as:
                    request_data[b'submit_as'] = submit_as

                if self.tool.can_bookmark:
                    bookmark = self.tool.get_current_bookmark()
                    request_data[b'extra_data__local_bookmark'] = bookmark
                elif self.tool.can_branch:
                    branch = self.tool.get_current_branch()
                    request_data[b'extra_data__local_branch'] = branch

                review_requests = api_root.get_review_requests(
                    only_fields='', only_links='create')
                review_request = review_requests.create(**request_data)
            except APIError as e:
                if e.error_code == 204 and changenum:
                    # The change number is already in use. Get the review
                    # request for that change and update it instead.
                    rid = e.rsp['review_request']['id']
                    review_request = api_root.get_review_request(
                        review_request_id=rid,
                        only_fields='absolute_url,bugs_closed,id,status',
                        only_links='diffs,draft')
                else:
                    raise CommandError('Error creating review request: %s' % e)

        if (not repository_info.supports_changesets
                or not self.options.change_only):
            try:
                diff_kwargs = {
                    'parent_diff': parent_diff_content,
                    'base_dir': base_dir,
                }

                if (base_commit_id and self.tool.capabilities.has_capability(
                        'diffs', 'base_commit_ids')):
                    # Both the Review Board server and SCMClient support
                    # base commit IDs, so pass that along when creating
                    # the diff.
                    diff_kwargs['base_commit_id'] = base_commit_id

                review_request.get_diffs(only_fields='').upload_diff(
                    diff_content, **diff_kwargs)
            except APIError as e:
                error_msg = [
                    u'Error uploading diff\n\n',
                ]

                if e.error_code == 101 and e.http_status == 403:
                    error_msg.append(u'You do not have permissions to modify '
                                     u'this review request\n')
                elif e.error_code == 219:
                    error_msg.append(
                        u'The generated diff file was empty. This '
                        u'usually means no files were\n'
                        u'modified in this change.\n')
                else:
                    error_msg.append(str(e).decode('utf-8') + u'\n')

                error_msg.append(
                    u'Your review request still exists, but the diff is '
                    u'not attached.\n')

                error_msg.append(u'%s\n' % review_request.absolute_url)

                raise CommandError(u'\n'.join(error_msg))

        try:
            draft = review_request.get_draft(only_fields='commit_id')
        except APIError as e:
            raise CommandError('Error retrieving review request draft: %s' % e)

        # Stamp the commit message with the review request URL before posting
        # the review, so that we can use the stamped commit message when
        # guessing the description. This enables the stamped message to be
        # present on the review if the user has chosen to publish immediately
        # upon posting.
        if self.options.stamp_when_posting:
            if not self.tool.can_amend_commit:
                print('Cannot stamp review URL onto the commit message; '
                      'stamping is not supported with %s.' % self.tool.name)

            else:
                try:
                    stamp_commit_with_review_url(self.revisions,
                                                 review_request.absolute_url,
                                                 self.tool)
                    print('Stamped review URL onto the commit message.')
                except AlreadyStampedError:
                    print('Commit message has already been stamped')
                except Exception as e:
                    logging.debug(
                        'Caught exception while stamping the '
                        'commit message. Proceeding to post '
                        'without stamping.',
                        exc_info=True)
                    print('Could not stamp review URL onto the commit '
                          'message.')

        # If the user has requested to guess the summary or description,
        # get the commit message and override the summary and description
        # options. The guessing takes place after stamping so that the
        # guessed description matches the commit when rbt exits.
        if not self.options.diff_filename:
            self.check_guess_fields()

        # Update the review request draft fields based on options set
        # by the user, or configuration.
        update_fields = {}

        if self.options.target_groups:
            update_fields['target_groups'] = self.options.target_groups

        if self.options.target_people:
            update_fields['target_people'] = self.options.target_people

        if self.options.depends_on:
            update_fields['depends_on'] = self.options.depends_on

        if self.options.summary:
            update_fields['summary'] = self.options.summary

        if self.options.branch:
            update_fields['branch'] = self.options.branch

        if self.options.bugs_closed:
            # Append to the existing list of bugs.
            self.options.bugs_closed = self.options.bugs_closed.strip(', ')
            bug_set = (set(re.split('[, ]+', self.options.bugs_closed))
                       | set(review_request.bugs_closed))
            self.options.bugs_closed = ','.join(bug_set)
            update_fields['bugs_closed'] = self.options.bugs_closed

        if self.options.description:
            update_fields['description'] = self.options.description

        if self.options.testing_done:
            update_fields['testing_done'] = self.options.testing_done

        if ((self.options.description or self.options.testing_done)
                and self.options.markdown
                and self.tool.capabilities.has_capability('text', 'markdown')):
            # The user specified that their Description/Testing Done are
            # valid Markdown, so tell the server so it won't escape the text.
            update_fields['text_type'] = 'markdown'

        if self.options.publish:
            update_fields['public'] = True

            if (self.options.trivial_publish
                    and self.tool.capabilities.has_capability(
                        'review_requests', 'trivial_publish')):
                update_fields['trivial'] = True

        if self.options.change_description is not None:
            if review_request.public:
                update_fields['changedescription'] = \
                    self.options.change_description

                if (self.options.markdown
                        and self.tool.capabilities.has_capability(
                            'text', 'markdown')):
                    update_fields['changedescription_text_type'] = 'markdown'
                else:
                    update_fields['changedescription_text_type'] = 'plain'
            else:
                logging.error(
                    'The change description field can only be set when '
                    'publishing an update. Use --description instead.')

        if supports_posting_commit_ids and commit_id != draft.commit_id:
            update_fields['commit_id'] = commit_id or ''

        if update_fields:
            try:
                draft = draft.update(**update_fields)
            except APIError as e:
                raise CommandError(
                    'Error updating review request draft: %s\n\n'
                    'Your review request still exists, but the diff is not '
                    'attached.\n\n'
                    '%s\n' % (e, review_request.absolute_url))

        return review_request.id, review_request.absolute_url