Example #1
0
    def merge(self):
        """Tries to merge the new content from the remote repository.

        If there is a merge conflict, sets state to ALERT_CONFLICT, otherwise
        sets state to EXPORT.
        """
        result, stdout, _ = utils.capture_command('git',
                                                  'merge',
                                                  '--squash',
                                                  self.__last_synced,
                                                  expect_success=False)
        print stdout
        if result == 0:
            sync_commit_message = 'Syncing review %s at %s.' % (
                self.__branch, self.__last_synced)
            # TODO(dhermes): Catch error here.
            print utils.capture_command('git',
                                        'commit',
                                        '-m',
                                        sync_commit_message,
                                        single_line=False)
            self.state = self.EXPORT
        else:
            self.state = self.ALERT_CONFLICT
        self.advance()
Example #2
0
    def check_environment(self):
        """Checks that a sync can be performed.

        If a sync can't be performed, sets state to FINISHED. If it can be,
        sets state to CHECK_CONTINUE or CHECK_NEW, depending on whether the sync
        is a continue sync or a new sync.
        """
        # Make sure branch is clean
        if not utils.in_clean_state():
            print 'Branch %r not in clean state:' % (self.__branch,)
            print utils.capture_command('git', 'diff', single_line=False)
            self.state = self.FINISHED
        else:
            # TODO(dhermes): This assumes review_info is not None. Fix this.
            self.__last_commit = self.__rietveld_info.review_info.last_commit
            # Using getattr since SYNC_HALTED is not an explicit attribute in
            # RietveldInfo, hence accessing rietveld_info.sync_halted may result
            # in an AttributeError.
            self.__sync_halted = getattr(self.__rietveld_info,
                                         utils.SYNC_HALTED, False)
            if self.__continue:
                self.state = self.CHECK_CONTINUE
            else:
                self.state = self.CHECK_NEW
        self.advance()
Example #3
0
    def check_environment(self):
        """Checks that a sync can be performed.

        If a sync can't be performed, sets state to FINISHED. If it can be,
        sets state to CHECK_CONTINUE or CHECK_NEW, depending on whether the sync
        is a continue sync or a new sync.
        """
        # Make sure branch is clean
        if not utils.in_clean_state():
            print 'Branch %r not in clean state:' % (self.__branch, )
            print utils.capture_command('git', 'diff', single_line=False)
            self.state = self.FINISHED
        else:
            # TODO(dhermes): This assumes review_info is not None. Fix this.
            self.__last_commit = self.__rietveld_info.review_info.last_commit
            # Using getattr since SYNC_HALTED is not an explicit attribute in
            # RietveldInfo, hence accessing rietveld_info.sync_halted may result
            # in an AttributeError.
            self.__sync_halted = getattr(self.__rietveld_info,
                                         utils.SYNC_HALTED, False)
            if self.__continue:
                self.state = self.CHECK_CONTINUE
            else:
                self.state = self.CHECK_NEW
        self.advance()
Example #4
0
    def rename(self, rietveld_info):
        """Renames the source branch and moves the Rietveld info as well.

        If successful, sets state to FINISHED.

        Args:
            rietveld_info: RietveldInfo object for the branch. Is copied over
                to the new branch.

        Raises:
            GitRvException: If rietveld_info is None.
        """
        if rietveld_info is None:
            raise utils.GitRvException('Rename command received unexpected '
                                       'branch info.')

        print 'Renaming branch...'
        print utils.capture_command('git',
                                    'branch',
                                    '-m',
                                    self.__source_branch,
                                    self.__target_branch,
                                    single_line=False)

        print 'Moving review info.'
        rietveld_info._branch_name = self.__target_branch
        rietveld_info.save()
        utils.RietveldInfo.remove(branch_name=self.__source_branch)
Example #5
0
    def clean_up_local(self, success=False):
        """Cleans up the repository after a commit or failure.

        Deletes the dummy branch created and checks back out the review branch.

        If the SubmitAction was successful (success), then the branch metadata
        is removed from the git config. In addition, the review
        branch will be replaced with HEAD at the newly submitted commit.

        If the SubmitAction was not successful, all other cleanup for the
        failure case is considered to have been done before.

        If the SubmitAction was successful, sets state to CLEAN_UP_REVIEW,
        otherwise sets it to FINISHED. In either case, advances the state
        machine.

        Args:
            success: Boolean indicating whether or not the submit succeeded.
        """
        if success:
            print ('Replacing review branch %r with newly '
                   'committed content.' % (self.__branch,))
            # Remove the review branch
            utils.capture_command('git', 'branch', '-D', self.__branch,
                                  single_line=False)
            # TODO(dhermes): The git push will update the locally stored
            #                version of the remote. Is this enough to guarantee
            #                we are doing the right thing here?
            # Add back the review branch with HEAD at the new commit
            utils.capture_command(
                    'git', 'branch', '--track', self.__branch,
                    self.__rietveld_info.remote_info.remote_branch_ref,
                    single_line=False)

            # Remove Rietveld metadata associated with the review branch
            utils.RietveldInfo.remove(branch_name=self.__branch)

        # Check out the review branch. We use -f in case we failed in a detached
        # HEAD or dirty state and want to get back to our clean branch.
        utils.capture_command('git', 'checkout', '-f', self.__branch,
                              single_line=False)

        # This brings the review branch back to a stable state, which it was
        # required to be in by check_environment(). If there are no pending
        # changes left over from the checkout -f, this hard reset does nothing.
        utils.capture_command('git', 'reset', '--hard', 'HEAD',
                              single_line=False)

        # If __review_branch was set, we know we have a dummy branch created
        # by this action which must be deleted.
        if self.__review_branch is not None:
            utils.capture_command('git', 'branch', '-D', self.__review_branch,
                                  single_line=False)

        if success:
            self.state = self.CLEAN_UP_REVIEW
        else:
            self.state = self.FINISHED
        self.advance()
Example #6
0
    def delete(self):
        """Deletes the branch and the Rietveld info as well.

        If successful, sets state to FINISHED.
        """
        print 'Deleting branch...'
        print utils.capture_command('git', 'branch', '-D', self.__branch,
                                    single_line=False)

        print 'Deleting review info.'
        # TODO(dhermes): Consider closing this issue as well, or adding a flag
        #                to do so.
        utils.RietveldInfo.remove(branch_name=self.__branch)
Example #7
0
    def callback(cls, args, argv):
        """A callback to begin an ExportAction after arguments are parsed.

        If the branch is not in a clean state, won't create an ExportAction,
        will just print 'git diff' and proceed.

        Args:
            args: An argparse.Namespace object to extract parameters from.
            argv: The original command line arguments that were parsed to create
                args. These may be used in a call to upload.py.

        Returns:
            An instance of ExportAction. Just by instantiating the instance, the
                state machine will begin working.
        """
        current_branch = utils.get_current_branch()
        if not utils.in_clean_state():
            print 'Branch %r not in clean state:' % (current_branch, )
            print utils.capture_command('git', 'diff', single_line=False)
            return

        if args.no_mail and args.send_patch:
            raise GitRvException('The flags --no_mail and --send_patch are '
                                 'mutually exclusive.')
        # This is to determine whether or not --send_mail should be added to
        # the upload.py call. If --send_patch is set, we don't need to
        # send mail. Similarly if --no_mail is set, we should not send mail.
        no_send_mail = args.no_mail or args.send_patch

        # Rietveld treats an empty string the same as if the value
        # was never set.
        if args.message and not args.title:
            raise GitRvException('A patch description can only be set if it '
                                 'also has a title.')

        commit_subject = commit_description = None
        if args.title:
            if len(args.title) > 100:
                raise GitRvException(utils.SUBJECT_TOO_LONG_TEMPLATE %
                                     (args.title, ))
            # If args.message is '', then both the Title and Description
            # will take the value of the title.
            commit_subject = args.title
            commit_description = args.message or ''

        return cls(current_branch,
                   args,
                   commit_subject=commit_subject,
                   commit_description=commit_description,
                   no_send_mail=no_send_mail,
                   argv=argv)
Example #8
0
    def callback(cls, args, argv):
        """A callback to begin an ExportAction after arguments are parsed.

        If the branch is not in a clean state, won't create an ExportAction,
        will just print 'git diff' and proceed.

        Args:
            args: An argparse.Namespace object to extract parameters from.
            argv: The original command line arguments that were parsed to create
                args. These may be used in a call to upload.py.

        Returns:
            An instance of ExportAction. Just by instantiating the instance, the
                state machine will begin working.
        """
        current_branch = utils.get_current_branch()
        if not utils.in_clean_state():
            print 'Branch %r not in clean state:' % (current_branch,)
            print utils.capture_command('git', 'diff', single_line=False)
            return

        if args.no_mail and args.send_patch:
            raise GitRvException('The flags --no_mail and --send_patch are '
                                 'mutually exclusive.')
        # This is to determine whether or not --send_mail should be added to
        # the upload.py call. If --send_patch is set, we don't need to
        # send mail. Similarly if --no_mail is set, we should not send mail.
        no_send_mail = args.no_mail or args.send_patch

        # Rietveld treats an empty string the same as if the value
        # was never set.
        if args.message and not args.title:
            raise GitRvException('A patch description can only be set if it '
                                 'also has a title.')

        commit_subject = commit_description = None
        if args.title:
            if len(args.title) > 100:
                raise GitRvException(utils.SUBJECT_TOO_LONG_TEMPLATE %
                                     (args.title,))
            # If args.message is '', then both the Title and Description
            # will take the value of the title.
            commit_subject = args.title
            commit_description = args.message or ''

        return cls(current_branch, args, commit_subject=commit_subject,
                   commit_description=commit_description,
                   no_send_mail=no_send_mail, argv=argv)
Example #9
0
    def set_history_from_remote(self):
        """Sets history in detached HEAD to the remote history.

        Uses a soft reset to add the commit history from the last synced commit
        in the remote branch.

        Thanks to http://stackoverflow.com/a/4481621/1068170 for the merge
        strategy.

        If successful, sets state to CREATE_BRANCH; if not, saves the error
        message and sets state to NOTIFY_FAILURE. In either case, advances the
        state machine.
        """
        # Dictionary to pass along state to advance()
        next_state_kwargs = {}

        # Soft reset to add remote branch commit history
        print 'Setting head at %s.' % (self.__last_synced, )
        result, _, stderr = utils.capture_command('git',
                                                  'reset',
                                                  '--soft',
                                                  self.__last_synced,
                                                  expect_success=False)

        if result != 0:
            next_state_kwargs['error_message'] = stderr
            self.state = self.NOTIFY_FAILURE
        else:
            self.state = self.CREATE_BRANCH

        self.advance(**next_state_kwargs)
Example #10
0
    def check_environment(self):
        """Checks that the current review branch is in a clean state.

        If not, we can't submit, so sets state to FINISHED after notifying the
        user of the issue. If it can be, sets state to VERIFY_APPROVAL. In
        either case, advances the state machine.
        """
        # Make sure branch is clean
        if not utils.in_clean_state():
            print 'Branch %r not in clean state:' % (self.__branch, )
            print utils.capture_command('git', 'diff', single_line=False)
            self.state = self.FINISHED
        else:
            self.state = self.VERIFY_APPROVAL

        self.advance()
Example #11
0
    def push_commit(self):
        """Pushes the squashed commit to the remote repository.

        If the push fails, saves the error message so it can be used to
        notify the user.

        If successful, sets state to CLEAN_UP_LOCAL, otherwise to
        NOTIFY_FAILURE. In either case, advances the state machine.
        """
        # Dictionary to pass along state to advance()
        next_state_kwargs = {}

        branch_mapping = '%s:%s' % (self.__review_branch, self.__remote_branch)
        result, _, stderr = utils.capture_command('git',
                                                  'push',
                                                  self.__remote,
                                                  branch_mapping,
                                                  expect_success=False)
        if result != 0:
            # TODO(dhermes): Should we try a sync and proceed if no failure?
            next_state_kwargs['error_message'] = stderr
            self.state = self.NOTIFY_FAILURE
        else:
            next_state_kwargs['success'] = True
            self.state = self.CLEAN_UP_LOCAL

        self.advance(**next_state_kwargs)
Example #12
0
    def check_environment(self):
        """Checks that the current review branch is in a clean state.

        If not, we can't submit, so sets state to FINISHED after notifying the
        user of the issue. If it can be, sets state to VERIFY_APPROVAL. In
        either case, advances the state machine.
        """
        # Make sure branch is clean
        if not utils.in_clean_state():
            print 'Branch %r not in clean state:' % (self.__branch,)
            print utils.capture_command('git', 'diff', single_line=False)
            self.state = self.FINISHED
        else:
            self.state = self.VERIFY_APPROVAL

        self.advance()
Example #13
0
    def set_history_from_remote(self):
        """Sets history in detached HEAD to the remote history.

        Uses a soft reset to add the commit history from the last synced commit
        in the remote branch.

        Thanks to http://stackoverflow.com/a/4481621/1068170 for the merge
        strategy.

        If successful, sets state to CREATE_BRANCH; if not, saves the error
        message and sets state to NOTIFY_FAILURE. In either case, advances the
        state machine.
        """
        # Dictionary to pass along state to advance()
        next_state_kwargs = {}

        # Soft reset to add remote branch commit history
        print 'Setting head at %s.' % (self.__last_synced,)
        result, _, stderr = utils.capture_command(
                'git', 'reset', '--soft', self.__last_synced,
                expect_success=False)

        if result != 0:
            next_state_kwargs['error_message'] = stderr
            self.state = self.NOTIFY_FAILURE
        else:
            self.state = self.CREATE_BRANCH

        self.advance(**next_state_kwargs)
Example #14
0
    def delete(self):
        """Deletes the branch and the Rietveld info as well.

        If successful, sets state to FINISHED.
        """
        print 'Deleting branch...'
        print utils.capture_command('git',
                                    'branch',
                                    '-D',
                                    self.__branch,
                                    single_line=False)

        print 'Deleting review info.'
        # TODO(dhermes): Consider closing this issue as well, or adding a flag
        #                to do so.
        utils.RietveldInfo.remove(branch_name=self.__branch)
Example #15
0
    def enter_detached_state(self):
        """Enters detached HEAD state with review contents.

        Enters a detached HEAD state holding the contents of the review branch,
        but none of the history. This is so we can rewrite the history to apply
        the reviewed work to the existing history of the remote branch.

        Thanks to http://stackoverflow.com/a/4481621/1068170 for the merge
        strategy.

        If successful, sets state to SET_HISTORY_FROM_REMOTE; if not, saves the
        error message and sets state to NOTIFY_FAILURE. In either case, advances
        the state machine.
        """
        # Dictionary to pass along state to advance()
        next_state_kwargs = {}

        # Enter detached HEAD state
        print 'Entering detached HEAD state with contents from %s.' % (
                self.__branch,)
        current_branch_detached = '%s@{0}' % (self.__branch,)
        result, _, stderr = utils.capture_command(
                'git', 'checkout', current_branch_detached,
                expect_success=False)

        if result != 0:
            next_state_kwargs['error_message'] = stderr
            self.state = self.NOTIFY_FAILURE
        else:
            self.state = self.SET_HISTORY_FROM_REMOTE

        self.advance(**next_state_kwargs)
Example #16
0
    def push_commit(self):
        """Pushes the squashed commit to the remote repository.

        If the push fails, saves the error message so it can be used to
        notify the user.

        If successful, sets state to CLEAN_UP_LOCAL, otherwise to
        NOTIFY_FAILURE. In either case, advances the state machine.
        """
        # Dictionary to pass along state to advance()
        next_state_kwargs = {}

        branch_mapping = '%s:%s' % (self.__review_branch, self.__remote_branch)
        result, _, stderr = utils.capture_command(
                'git', 'push', self.__remote, branch_mapping,
                expect_success=False)
        if result != 0:
            # TODO(dhermes): Should we try a sync and proceed if no failure?
            next_state_kwargs['error_message'] = stderr
            self.state = self.NOTIFY_FAILURE
        else:
            next_state_kwargs['success'] = True
            self.state = self.CLEAN_UP_LOCAL

        self.advance(**next_state_kwargs)
Example #17
0
    def enter_detached_state(self):
        """Enters detached HEAD state with review contents.

        Enters a detached HEAD state holding the contents of the review branch,
        but none of the history. This is so we can rewrite the history to apply
        the reviewed work to the existing history of the remote branch.

        Thanks to http://stackoverflow.com/a/4481621/1068170 for the merge
        strategy.

        If successful, sets state to SET_HISTORY_FROM_REMOTE; if not, saves the
        error message and sets state to NOTIFY_FAILURE. In either case, advances
        the state machine.
        """
        # Dictionary to pass along state to advance()
        next_state_kwargs = {}

        # Enter detached HEAD state
        print 'Entering detached HEAD state with contents from %s.' % (
            self.__branch, )
        current_branch_detached = '%s@{0}' % (self.__branch, )
        result, _, stderr = utils.capture_command('git',
                                                  'checkout',
                                                  current_branch_detached,
                                                  expect_success=False)

        if result != 0:
            next_state_kwargs['error_message'] = stderr
            self.state = self.NOTIFY_FAILURE
        else:
            self.state = self.SET_HISTORY_FROM_REMOTE

        self.advance(**next_state_kwargs)
Example #18
0
    def fetch_remote(self):
        """Fetchs the remote associated with the current review.

        If the fetched remote has no new commits, sets state to FINISHED,
        otherwise sets state to MERGE_REMOTE_IN.
        """
        # TODO(dhermes): This assumes remote_info is not None. Fix this.
        remote_info = self.__rietveld_info.remote_info
        print utils.capture_command('git', 'fetch', remote_info.remote,
                                    single_line=False)

        new_head_in_remote = remote_info.head_in_remote_branch
        if new_head_in_remote == self.__rietveld_info.remote_info.last_synced:
            print 'No new changes in %s.' % (remote_info.remote_branch_ref,)
            self.state = self.FINISHED
        else:
            self.state = self.MERGE_REMOTE_IN
        self.__last_synced = new_head_in_remote
        self.advance()
Example #19
0
    def merge(self):
        """Tries to merge the new content from the remote repository.

        If there is a merge conflict, sets state to ALERT_CONFLICT, otherwise
        sets state to EXPORT.
        """
        result, stdout, _ = utils.capture_command(
                'git', 'merge', '--squash',
                self.__last_synced, expect_success=False)
        print stdout
        if result == 0:
            sync_commit_message = 'Syncing review %s at %s.' % (
                    self.__branch, self.__last_synced)
            # TODO(dhermes): Catch error here.
            print utils.capture_command('git', 'commit', '-m',
                                        sync_commit_message, single_line=False)
            self.state = self.EXPORT
        else:
            self.state = self.ALERT_CONFLICT
        self.advance()
Example #20
0
    def fetch_remote(self):
        """Fetchs the remote associated with the current review.

        If the fetched remote has no new commits, sets state to FINISHED,
        otherwise sets state to MERGE_REMOTE_IN.
        """
        # TODO(dhermes): This assumes remote_info is not None. Fix this.
        remote_info = self.__rietveld_info.remote_info
        print utils.capture_command('git',
                                    'fetch',
                                    remote_info.remote,
                                    single_line=False)

        new_head_in_remote = remote_info.head_in_remote_branch
        if new_head_in_remote == self.__rietveld_info.remote_info.last_synced:
            print 'No new changes in %s.' % (remote_info.remote_branch_ref, )
            self.state = self.FINISHED
        else:
            self.state = self.MERGE_REMOTE_IN
        self.__last_synced = new_head_in_remote
        self.advance()
Example #21
0
    def rename(self, rietveld_info):
        """Renames the source branch and moves the Rietveld info as well.

        If successful, sets state to FINISHED.

        Args:
            rietveld_info: RietveldInfo object for the branch. Is copied over
                to the new branch.

        Raises:
            GitRvException: If rietveld_info is None.
        """
        if rietveld_info is None:
            raise utils.GitRvException('Rename command received unexpected '
                                       'branch info.')

        print 'Renaming branch...'
        print utils.capture_command('git', 'branch', '-m', self.__source_branch,
                                    self.__target_branch, single_line=False)

        print 'Moving review info.'
        rietveld_info._branch_name = self.__target_branch
        rietveld_info.save()
        utils.RietveldInfo.remove(branch_name=self.__source_branch)
Example #22
0
    def create_branch(self):
        """Creates dummy branch with contents from detached HEAD.

        - Finds a dummy name by using BRANCH_NAME_TEMPLATE and the current issue
          and then adding '_0' until it finds a branch name which doesn't
          already exist.
        - Creates and checks out (via checkout -b) the contents using the dummy
          name.

        Thanks to http://stackoverflow.com/a/4481621/1068170 for the merge
        strategy.

        If successful, sets state to COMMIT; if not, saves the error message and
        state to NOTIFY_FAILURE. In either case, advances the state machine.
        """
        # Find dummy branch name
        review_branch = BRANCH_NAME_TEMPLATE % self.__issue
        while utils.branch_exists(review_branch):
            review_branch += '_0'

        # Dictionary to pass along state to advance()
        next_state_kwargs = {}

        # Create and checkout review branch
        print 'Checking out %s at %s.' % (review_branch, self.__last_synced)
        result, _, stderr = utils.capture_command('git',
                                                  'checkout',
                                                  '-b',
                                                  review_branch,
                                                  expect_success=False)

        if result != 0:
            next_state_kwargs['error_message'] = stderr
            self.state = self.NOTIFY_FAILURE
        else:
            # Only set the review branch if it is created.
            self.__review_branch = review_branch
            self.state = self.COMMIT

        self.advance(**next_state_kwargs)
Example #23
0
    def commit(self):
        """Adds reviewed changes to stable contents in dummy branch.

        Commits the current content as a single commit (extra) in this
        remote branch history (but in the local branch). Uses the issue
        description (from the review) and adds a note about the review.

        If successful, sets state to PUSHING; if not, saves the error message
        and state to NOTIFY_FAILURE. In either case, advances the state machine.
        """
        # Dictionary to pass along state to advance()
        next_state_kwargs = {}

        # Commit the current content
        description_newline = ''
        if self.__description:
            description_newline = '\n\n'
        final_commit_message = utils.SQUASH_COMMIT_TEMPLATE % {
            utils.SUBJECT: self.__subject,
            utils.DESCRIPTION_NEWLINE: description_newline,
            utils.ISSUE_DESCRIPTION: self.__description,
            utils.ISSUE: self.__issue,
            utils.SERVER: self.__server,
        }
        print 'Adding commit:'
        print final_commit_message
        result, _, stderr = utils.capture_command('git',
                                                  'commit',
                                                  '-m',
                                                  final_commit_message,
                                                  expect_success=False)
        if result != 0:
            next_state_kwargs['error_message'] = stderr
            self.state = self.NOTIFY_FAILURE
        else:
            self.state = self.PUSHING

        # Advance
        self.advance(**next_state_kwargs)
Example #24
0
    def create_branch(self):
        """Creates dummy branch with contents from detached HEAD.

        - Finds a dummy name by using BRANCH_NAME_TEMPLATE and the current issue
          and then adding '_0' until it finds a branch name which doesn't
          already exist.
        - Creates and checks out (via checkout -b) the contents using the dummy
          name.

        Thanks to http://stackoverflow.com/a/4481621/1068170 for the merge
        strategy.

        If successful, sets state to COMMIT; if not, saves the error message and
        state to NOTIFY_FAILURE. In either case, advances the state machine.
        """
        # Find dummy branch name
        review_branch = BRANCH_NAME_TEMPLATE % self.__issue
        while utils.branch_exists(review_branch):
            review_branch += '_0'

        # Dictionary to pass along state to advance()
        next_state_kwargs = {}

        # Create and checkout review branch
        print 'Checking out %s at %s.' % (review_branch, self.__last_synced)
        result, _, stderr = utils.capture_command(
                'git', 'checkout', '-b', review_branch,
                expect_success=False)

        if result != 0:
            next_state_kwargs['error_message'] = stderr
            self.state = self.NOTIFY_FAILURE
        else:
            # Only set the review branch if it is created.
            self.__review_branch = review_branch
            self.state = self.COMMIT

        self.advance(**next_state_kwargs)
Example #25
0
    def commit(self):
        """Adds reviewed changes to stable contents in dummy branch.

        Commits the current content as a single commit (extra) in this
        remote branch history (but in the local branch). Uses the issue
        description (from the review) and adds a note about the review.

        If successful, sets state to PUSHING; if not, saves the error message
        and state to NOTIFY_FAILURE. In either case, advances the state machine.
        """
        # Dictionary to pass along state to advance()
        next_state_kwargs = {}

        # Commit the current content
        description_newline = ''
        if self.__description:
            description_newline = '\n\n'
        final_commit_message = utils.SQUASH_COMMIT_TEMPLATE % {
            utils.SUBJECT: self.__subject,
            utils.DESCRIPTION_NEWLINE: description_newline,
            utils.ISSUE_DESCRIPTION: self.__description,
            utils.ISSUE: self.__issue,
            utils.SERVER: self.__server,
        }
        print 'Adding commit:'
        print final_commit_message
        result, _, stderr = utils.capture_command(
                'git', 'commit', '-m', final_commit_message,
                expect_success=False)
        if result != 0:
            next_state_kwargs['error_message'] = stderr
            self.state = self.NOTIFY_FAILURE
        else:
            self.state = self.PUSHING

        # Advance
        self.advance(**next_state_kwargs)
Example #26
0
    def clean_up_local(self, success=False):
        """Cleans up the repository after a commit or failure.

        Deletes the dummy branch created and checks back out the review branch.

        If the SubmitAction was successful (success), then the branch metadata
        is removed from the git config. In addition, the review
        branch will be replaced with HEAD at the newly submitted commit.

        If the SubmitAction was not successful, all other cleanup for the
        failure case is considered to have been done before.

        If the SubmitAction was successful, sets state to CLEAN_UP_REVIEW,
        otherwise sets it to FINISHED. In either case, advances the state
        machine.

        Args:
            success: Boolean indicating whether or not the submit succeeded.
        """
        if success:
            print(
                'Replacing review branch %r with newly '
                'committed content.' % (self.__branch, ))
            # Remove the review branch
            utils.capture_command('git',
                                  'branch',
                                  '-D',
                                  self.__branch,
                                  single_line=False)
            # TODO(dhermes): The git push will update the locally stored
            #                version of the remote. Is this enough to guarantee
            #                we are doing the right thing here?
            # Add back the review branch with HEAD at the new commit
            utils.capture_command(
                'git',
                'branch',
                '--track',
                self.__branch,
                self.__rietveld_info.remote_info.remote_branch_ref,
                single_line=False)

            # Remove Rietveld metadata associated with the review branch
            utils.RietveldInfo.remove(branch_name=self.__branch)

        # Check out the review branch. We use -f in case we failed in a detached
        # HEAD or dirty state and want to get back to our clean branch.
        utils.capture_command('git',
                              'checkout',
                              '-f',
                              self.__branch,
                              single_line=False)

        # This brings the review branch back to a stable state, which it was
        # required to be in by check_environment(). If there are no pending
        # changes left over from the checkout -f, this hard reset does nothing.
        utils.capture_command('git',
                              'reset',
                              '--hard',
                              'HEAD',
                              single_line=False)

        # If __review_branch was set, we know we have a dummy branch created
        # by this action which must be deleted.
        if self.__review_branch is not None:
            utils.capture_command('git',
                                  'branch',
                                  '-D',
                                  self.__review_branch,
                                  single_line=False)

        if success:
            self.state = self.CLEAN_UP_REVIEW
        else:
            self.state = self.FINISHED
        self.advance()