Changeset 58261 in webkit


Ignore:
Timestamp:
Apr 26, 2010 10:48:19 AM (14 years ago)
Author:
ojan@chromium.org
Message:

2010-04-06 Ojan Vafai <ojan@chromium.org>

Reviewed by Adam Barth.

Include git commits in the diff for webkit-patch upload/land.
https://bugs.webkit.org/show_bug.cgi?id=36394

Adds --squash, --no-squash and --git-commit.

--git-commit will use a specific local commit for land/upload.
If a commit-range is specified, then that range is treated as
a single squashed commit.

--squash will squash all local changes including working copy changes
into a single patch.

--no-squash is the legacy behavior (upload only considers the working copy,
land commits the working copy and then each local commit separately to SVN)

If neither is specified, then an informative error is raised if there is
more than one local commit or when there are local commit(s) and working
copy changes.

If the webkit-patch.squash git config parameter is set, then
that will be respected instead of raising an error.

  • Scripts/check-webkit-style:
  • Scripts/webkitpy/common/checkout/api.py:
  • Scripts/webkitpy/common/checkout/api_unittest.py:
  • Scripts/webkitpy/common/checkout/scm.py:
  • Scripts/webkitpy/common/checkout/scm_unittest.py:
  • Scripts/webkitpy/style/optparser.py: --git-since is removed and --git-commit no longer implies commit_id.. Instead, it treats that individual commit, but also supports commit ranges (e.g. commit_id..) as arguments.
  • Scripts/webkitpy/style/optparser_unittest.py:
  • Scripts/webkitpy/style_references.py:
  • Scripts/webkitpy/tool/commands/download.py:
  • Scripts/webkitpy/tool/commands/upload.py:
  • Scripts/webkitpy/tool/main.py:
  • Scripts/webkitpy/tool/mocktool.py:
  • Scripts/webkitpy/tool/steps/abstractstep.py:
  • Scripts/webkitpy/tool/steps/applypatchwithlocalcommit.py:
  • Scripts/webkitpy/tool/steps/checkstyle.py:
  • Scripts/webkitpy/tool/steps/commit.py:
  • Scripts/webkitpy/tool/steps/options.py:
  • Scripts/webkitpy/tool/steps/postdiff.py:
  • Scripts/webkitpy/tool/steps/preparechangelog.py:
  • Scripts/webkitpy/tool/steps/preparechangelogforrevert.py:
  • Scripts/webkitpy/tool/steps/updatechangelogswithreviewer.py:
  • Scripts/webkitpy/tool/steps/validatereviewer.py:
Location:
trunk/WebKitTools
Files:
26 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebKitTools/ChangeLog

    r58251 r58261  
     12010-04-06  Ojan Vafai  <ojan@chromium.org>
     2
     3        Reviewed by Adam Barth.
     4
     5        Include git commits in the diff for webkit-patch upload/land.
     6        https://bugs.webkit.org/show_bug.cgi?id=36394
     7
     8        Adds --squash, --no-squash and --git-commit.
     9
     10        --git-commit will use a specific local commit for land/upload.
     11        If a commit-range is specified, then that range is treated as
     12        a single squashed commit.
     13
     14        --squash will squash all local changes including working copy changes
     15        into a single patch.
     16
     17        --no-squash is the legacy behavior (upload only considers the working copy,
     18        land commits the working copy and then each local commit separately to SVN)
     19
     20        If neither is specified, then an informative error is raised if there is
     21        more than one local commit or when there are local commit(s) and working
     22        copy changes.
     23
     24        If the webkit-patch.squash git config parameter is set, then
     25        that will be respected instead of raising an error.
     26
     27        * Scripts/check-webkit-style:
     28        * Scripts/webkitpy/common/checkout/api.py:
     29        * Scripts/webkitpy/common/checkout/api_unittest.py:
     30        * Scripts/webkitpy/common/checkout/scm.py:
     31        * Scripts/webkitpy/common/checkout/scm_unittest.py:
     32        * Scripts/webkitpy/style/optparser.py:
     33        --git-since is removed and --git-commit no longer implies commit_id..
     34        Instead, it treats that individual commit, but also supports commit ranges
     35        (e.g. commit_id..) as arguments.
     36        * Scripts/webkitpy/style/optparser_unittest.py:
     37        * Scripts/webkitpy/style_references.py:
     38        * Scripts/webkitpy/tool/commands/download.py:
     39        * Scripts/webkitpy/tool/commands/upload.py:
     40        * Scripts/webkitpy/tool/main.py:
     41        * Scripts/webkitpy/tool/mocktool.py:
     42        * Scripts/webkitpy/tool/steps/abstractstep.py:
     43        * Scripts/webkitpy/tool/steps/applypatchwithlocalcommit.py:
     44        * Scripts/webkitpy/tool/steps/checkstyle.py:
     45        * Scripts/webkitpy/tool/steps/commit.py:
     46        * Scripts/webkitpy/tool/steps/options.py:
     47        * Scripts/webkitpy/tool/steps/postdiff.py:
     48        * Scripts/webkitpy/tool/steps/preparechangelog.py:
     49        * Scripts/webkitpy/tool/steps/preparechangelogforrevert.py:
     50        * Scripts/webkitpy/tool/steps/updatechangelogswithreviewer.py:
     51        * Scripts/webkitpy/tool/steps/validatereviewer.py:
     52
    1532010-04-26  Chris Jerdonek  <cjerdonek@webkit.org>
    254
  • trunk/WebKitTools/Scripts/check-webkit-style

    r58249 r58261  
    8787    _log.debug("Verbose logging enabled.")
    8888
     89    parser = checker.check_webkit_style_parser()
     90    (paths, options) = parser.parse(args)
     91
    8992    checkout = detect_checkout()
    9093
    9194    if checkout is None:
     95        if not paths:
     96            _log.error("WebKit checkout not found: You must run this script "
     97                       "from within a WebKit checkout if you are not passing "
     98                       "specific paths to check.")
     99            sys.exit(1)
     100
    92101        checkout_root = None
    93102        _log.debug("WebKit checkout not found for current directory.")
     
    95104        checkout_root = checkout.root_path()
    96105        _log.debug("WebKit checkout found with root: %s" % checkout_root)
    97 
    98     parser = checker.check_webkit_style_parser()
    99     (paths, options) = parser.parse(args)
    100 
    101     if checkout is None and not paths:
    102         _log.error("WebKit checkout not found: You must run this script "
    103                    "from within a WebKit checkout if you are not passing "
    104                    "specific paths to check.")
    105         sys.exit(1)
    106106
    107107    configuration = checker.check_webkit_style_configuration(options)
     
    116116        file_reader.process_paths(paths)
    117117    else:
    118         if options.git_commit:
    119             patch = checkout.create_patch_since_local_commit(options.git_commit)
    120         else:
    121             patch = checkout.create_patch()
     118        patch = checkout.create_patch(options.git_commit, options.squash)
    122119        patch_checker = PatchChecker(file_reader)
    123120        patch_checker.check(patch)
  • trunk/WebKitTools/Scripts/webkitpy/common/checkout/api.py

    r58210 r58261  
    8585        return self.commit_info_for_revision(revision).bug_id()
    8686
    87     def modified_changelogs(self):
     87    def modified_changelogs(self, git_commit, squash):
    8888        # SCM returns paths relative to scm.checkout_root
    8989        # Callers (especially those using the ChangeLog class) may
    9090        # expect absolute paths, so this method returns absolute paths.
    91         changed_files = self._scm.changed_files()
     91        changed_files = self._scm.changed_files(git_commit, squash)
    9292        absolute_paths = [os.path.join(self._scm.checkout_root, path) for path in changed_files]
    9393        return [path for path in absolute_paths if self._is_path_to_changelog(path)]
    9494
    95     def commit_message_for_this_commit(self):
    96         changelog_paths = self.modified_changelogs()
     95    def commit_message_for_this_commit(self, git_commit, squash):
     96        changelog_paths = self.modified_changelogs(git_commit, squash)
    9797        if not len(changelog_paths):
    9898            raise ScriptError(message="Found no modified ChangeLogs, cannot create a commit message.\n"
     
    111111        return CommitMessage("".join(changelog_messages).splitlines())
    112112
    113     def bug_id_for_this_commit(self):
     113    def bug_id_for_this_commit(self, git_commit, squash):
    114114        try:
    115             return parse_bug_id(self.commit_message_for_this_commit().message())
     115            return parse_bug_id(self.commit_message_for_this_commit(git_commit, squash).message())
    116116        except ScriptError, e:
    117117            pass # We might not have ChangeLogs.
     
    133133        # We revert the ChangeLogs because removing lines from a ChangeLog
    134134        # doesn't make sense.  ChangeLogs are append only.
    135         changelog_paths = self.modified_changelogs()
     135        changelog_paths = self.modified_changelogs(git_commit=None, squash=False)
    136136        if len(changelog_paths):
    137137            self._scm.revert_files(changelog_paths)
  • trunk/WebKitTools/Scripts/webkitpy/common/checkout/api_unittest.py

    r58210 r58261  
    115115    def test_commit_message_for_this_commit(self):
    116116        checkout = Checkout(None)
    117         checkout.modified_changelogs = lambda: ["ChangeLog1", "ChangeLog2"]
     117        checkout.modified_changelogs = lambda git_commit, squash: ["ChangeLog1", "ChangeLog2"]
    118118        output = OutputCapture()
    119119        expected_stderr = "Parsing ChangeLog: ChangeLog1\nParsing ChangeLog: ChangeLog2\n"
    120         commit_message = output.assert_outputs(self, checkout.commit_message_for_this_commit, expected_stderr=expected_stderr)
     120        commit_message = output.assert_outputs(self, checkout.commit_message_for_this_commit,
     121            kwargs={"git_commit": None, "squash": False}, expected_stderr=expected_stderr)
    121122        self.assertEqual(commit_message.message(), self.expected_commit_message)
    122123
     
    163164        scm = Mock()
    164165        checkout = Checkout(scm)
    165         checkout.commit_message_for_this_commit = lambda: CommitMessage(ChangeLogEntry(_changelog1entry1).contents().splitlines())
    166         self.assertEqual(checkout.bug_id_for_this_commit(), 36629)
     166        checkout.commit_message_for_this_commit = lambda git_commit, squash: CommitMessage(ChangeLogEntry(_changelog1entry1).contents().splitlines())
     167        self.assertEqual(checkout.bug_id_for_this_commit(git_commit=None, squash=False), 36629)
    167168
    168169    def test_modified_changelogs(self):
    169170        scm = Mock()
    170171        scm.checkout_root = "/foo/bar"
    171         scm.changed_files = lambda:["file1", "ChangeLog", "relative/path/ChangeLog"]
     172        scm.changed_files = lambda git_commit, squash: ["file1", "ChangeLog", "relative/path/ChangeLog"]
    172173        checkout = Checkout(scm)
    173174        expected_changlogs = ["/foo/bar/ChangeLog", "/foo/bar/relative/path/ChangeLog"]
    174         self.assertEqual(checkout.modified_changelogs(), expected_changlogs)
     175        self.assertEqual(checkout.modified_changelogs(git_commit=None, squash=False), expected_changlogs)
  • trunk/WebKitTools/Scripts/webkitpy/common/checkout/scm.py

    r58210 r58261  
    179179        raise NotImplementedError, "subclasses must implement"
    180180
    181     def changed_files(self):
     181    def changed_files(self, git_commit=None, squash=None):
    182182        raise NotImplementedError, "subclasses must implement"
    183183
     
    194194        raise NotImplementedError, "subclasses must implement"
    195195
    196     def create_patch(self):
     196    def create_patch(self, git_commit=None, squash=None):
    197197        raise NotImplementedError, "subclasses must implement"
    198198
     
    212212        raise NotImplementedError, "subclasses must implement"
    213213
    214     def commit_with_message(self, message, username=None):
     214    def commit_with_message(self, message, username=None, git_commit=None, squash=None):
    215215        raise NotImplementedError, "subclasses must implement"
    216216
     
    229229    def svn_merge_base():
    230230        raise NotImplementedError, "subclasses must implement"
    231 
    232     def create_patch_from_local_commit(self, commit_id):
    233         error("Your source control manager does not support creating a patch from a local commit.")
    234 
    235     def create_patch_since_local_commit(self, commit_id):
    236         error("Your source control manager does not support creating a patch from a local commit.")
    237231
    238232    def commit_locally_with_message(self, message):
     
    340334        run_command(["svn", "add", path])
    341335
    342     def changed_files(self):
     336    def changed_files(self, git_commit=None, squash=None):
    343337        return self.run_status_and_extract_filenames(self.status_command(), self._status_regexp("ACDMR"))
    344338
     
    362356        return "svn"
    363357
    364     def create_patch(self):
     358    def create_patch(self, git_commit=None, squash=None):
    365359        """Returns a byte array (str()) representing the patch file.
    366360        Patch files are effectively binary since they may contain
     
    398392        run_command(['svn', 'revert'] + file_paths)
    399393
    400     def commit_with_message(self, message, username=None):
     394    def commit_with_message(self, message, username=None, git_commit=None, squash=None):
     395        # squash and git-commit are not used by SVN.
    401396        if self.dryrun:
    402397            # Return a string which looks like a commit so that things which parse this output will succeed.
     
    485480        run_command(["git", "add", path])
    486481
    487     def changed_files(self):
    488         status_command = ['git', 'diff', '-r', '--name-status', '-C', '-M', 'HEAD']
     482    def _merge_base(self, git_commit, squash):
     483        if git_commit:
     484            # FIXME: Calling code should turn commit ranges into a list of commit IDs
     485            # and then treat each commit separately.
     486            if '..' not in git_commit:
     487                git_commit = git_commit + "^.." + git_commit
     488            return git_commit
     489
     490        if self.should_squash(squash):
     491            return self.svn_merge_base()
     492
     493        # FIXME: Non-squash behavior should match commit_with_message. It raises an error
     494        # if there are working copy changes and --squash or --no-squash wasn't passed in.
     495        # If --no-squash, then it should proceed with each local commit as a separate patch.
     496        return 'HEAD'
     497
     498    def changed_files(self, git_commit=None, squash=None):
     499        status_command = ['git', 'diff', '-r', '--name-status', '-C', '-M', "--no-ext-diff", "--full-index", self._merge_base(git_commit, squash)]
    489500        return self.run_status_and_extract_filenames(status_command, self._status_regexp("ADM"))
    490501
     
    515526        return "git"
    516527
    517     def create_patch(self):
     528    def create_patch(self, git_commit=None, squash=None):
    518529        """Returns a byte array (str()) representing the patch file.
    519530        Patch files are effectively binary since they may contain
    520531        files of multiple different encodings."""
    521532        # FIXME: This should probably use cwd=self.checkout_root
    522         return run_command(['git', 'diff', '--binary', 'HEAD'], decode_output=False)
     533        return run_command(['git', 'diff', '--binary', "--no-ext-diff", "--full-index", "-M", self._merge_base(git_commit, squash)], decode_output=False)
    523534
    524535    @classmethod
     
    538549    def diff_for_revision(self, revision):
    539550        git_commit = self.git_commit_from_svn_revision(revision)
    540         return self.create_patch_from_local_commit(git_commit)
     551        return self.create_patch(git_commit)
    541552
    542553    def committer_email_for_revision(self, revision):
     
    555566        run_command(['git', 'checkout', 'HEAD'] + file_paths)
    556567
    557     def commit_with_message(self, message, username=None):
     568    def should_squash(self, squash):
     569        if squash is not None:
     570            # Squash is specified on the command-line.
     571            return squash
     572
     573        config_squash = Git.read_git_config('webkit-patch.squash')
     574        if (config_squash and config_squash is not ""):
     575            return config_squash.lower() == "true"
     576
     577        # Only raise an error if there are actually multiple commits to squash.
     578        num_local_commits = len(self.local_commits())
     579        if num_local_commits > 1 or num_local_commits > 0 and not self.working_directory_is_clean():
     580            working_directory_message = "" if self.working_directory_is_clean() else " and working copy changes"
     581            raise ScriptError(message="""There are %s local commits%s. Do one of the following:
     5821) Use --squash or --no-squash
     5832) git config webkit-patch.squash true/false
     584""" % (num_local_commits, working_directory_message))
     585
     586        return None
     587
     588    def commit_with_message(self, message, username=None, git_commit=None, squash=None):
    558589        # Username is ignored during Git commits.
    559         self.commit_locally_with_message(message)
     590        if git_commit:
     591            # Need working directory changes to be committed so we can checkout the merge branch.
     592            if not self.working_directory_is_clean():
     593                # FIXME: webkit-patch land will modify the ChangeLogs to correct the reviewer.
     594                # That will modify the working-copy and cause us to hit this error.
     595                # The ChangeLog modification could be made to modify the existing local commit?
     596                raise ScriptError(message="Working copy is modified. Cannot commit individual git_commits.")
     597            return self._commit_on_branch(message, git_commit)
     598
     599        squash = self.should_squash(squash)
     600        if squash:
     601            run_command(['git', 'reset', '--soft', self.svn_branch_name()])
     602            self.commit_locally_with_message(message)
     603        elif not self.working_directory_is_clean():
     604            if not len(self.local_commits()):
     605                # There are only working copy changes. Assume they should be committed.
     606                self.commit_locally_with_message(message)
     607            elif squash is None:
     608                # The user didn't explicitly say to squash or not squash. There are local commits
     609                # and working copy changes. Not clear what the user wants.
     610                raise ScriptError(message="""There are local commits and working copy changes. Do one of the following:
     6111) Commit/revert working copy changes.
     6122) Use --squash or --no-squash
     6133) git config webkit-patch.squash true/false
     614""")
     615
     616        # FIXME: This will commit all local commits, each with it's own message. We should restructure
     617        # so that each local commit has the appropriate commit message based off it's ChangeLogs.
    560618        return self.push_local_commits_to_server()
     619
     620    def _commit_on_branch(self, message, git_commit):
     621        branch_ref = run_command(['git', 'symbolic-ref', 'HEAD']).strip()
     622        branch_name = branch_ref.replace('refs/heads/', '')
     623        commit_ids = self.commit_ids_from_commitish_arguments([git_commit])
     624
     625        # We want to squash all this branch's commits into one commit with the proper description.
     626        # We do this by doing a "merge --squash" into a new commit branch, then dcommitting that.
     627        MERGE_BRANCH = 'webkit-patch-land'
     628        self.delete_branch(MERGE_BRANCH)
     629
     630        # We might be in a directory that's present in this branch but not in the
     631        # trunk.  Move up to the top of the tree so that git commands that expect a
     632        # valid CWD won't fail after we check out the merge branch.
     633        os.chdir(self.checkout_root)
     634
     635        # Stuff our change into the merge branch.
     636        # We wrap in a try...finally block so if anything goes wrong, we clean up the branches.
     637        commit_succeeded = True
     638        try:
     639            run_command(['git', 'checkout', '-q', '-b', MERGE_BRANCH, self.svn_branch_name()])
     640
     641            for commit in commit_ids:
     642                # We're on a different branch now, so convert "head" to the branch name.
     643                commit = re.sub(r'(?i)head', branch_name, commit)
     644                # FIXME: Once changed_files and create_patch are modified to separately handle each
     645                # commit in a commit range, commit each cherry pick so they'll get dcommitted separately.
     646                run_command(['git', 'cherry-pick', '--no-commit', commit])
     647
     648            run_command(['git', 'commit', '-m', message])
     649            output = self.push_local_commits_to_server()
     650        except Exception, e:
     651            log("COMMIT FAILED: " + str(e))
     652            output = "Commit failed."
     653            commit_succeeded = False
     654        finally:
     655            # And then swap back to the original branch and clean up.
     656            self.clean_working_directory()
     657            run_command(['git', 'checkout', '-q', branch_name])
     658            self.delete_branch(MERGE_BRANCH)
     659
     660        return output
    561661
    562662    def svn_commit_log(self, svn_revision):
     
    578678    def svn_branch_name(self):
    579679        return Git.read_git_config('svn-remote.svn.fetch').split(':')[1]
    580 
    581     def create_patch_from_local_commit(self, commit_id):
    582         """Returns a byte array (str()) representing the patch file.
    583         Patch files are effectively binary since they may contain
    584         files of multiple different encodings."""
    585         return run_command(['git', 'diff', '--binary', commit_id + "^.." + commit_id], decode_output=False)
    586 
    587     def create_patch_since_local_commit(self, commit_id):
    588         """Returns a byte array (str()) representing the patch file.
    589         Patch files are effectively binary since they may contain
    590         files of multiple different encodings."""
    591         return run_command(['git', 'diff', '--binary', commit_id], decode_output=False)
    592680
    593681    def commit_locally_with_message(self, message):
  • trunk/WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py

    r58210 r58261  
    222222    # Tests which both GitTest and SVNTest should run.
    223223    # FIXME: There must be a simpler way to add these w/o adding a wrapper method to both subclasses
    224     def _shared_test_commit_with_message(self, username="dbates@webkit.org"):
    225         write_into_file_at_path('test_file', 'more test content')
    226         commit_text = self.scm.commit_with_message("another test commit", username)
    227         self.assertEqual(self.scm.svn_revision_from_commit_text(commit_text), '5')
    228 
    229         self.scm.dryrun = True
    230         write_into_file_at_path('test_file', 'still more test content')
    231         commit_text = self.scm.commit_with_message("yet another test commit", username)
    232         self.assertEqual(self.scm.svn_revision_from_commit_text(commit_text), '0')
    233224
    234225    def _shared_test_changed_files(self):
     
    561552        self.assertTrue(re.search('second commit', self.scm.svn_commit_log(2)))
    562553
     554    def _shared_test_commit_with_message(self, username=None):
     555        write_into_file_at_path('test_file', 'more test content')
     556        commit_text = self.scm.commit_with_message("another test commit", username)
     557        self.assertEqual(self.scm.svn_revision_from_commit_text(commit_text), '5')
     558
     559        self.scm.dryrun = True
     560        write_into_file_at_path('test_file', 'still more test content')
     561        commit_text = self.scm.commit_with_message("yet another test commit", username)
     562        self.assertEqual(self.scm.svn_revision_from_commit_text(commit_text), '0')
     563
    563564    def test_commit_text_parsing(self):
    564565        self._shared_test_commit_with_message()
     
    745746
    746747    def test_commit_text_parsing(self):
    747         self._shared_test_commit_with_message()
     748        write_into_file_at_path('test_file', 'more test content')
     749        self.scm.commit_locally_with_message("another test commit")
     750        commit_text = self.scm.commit_with_message("another test commit")
     751        self.assertEqual(self.scm.svn_revision_from_commit_text(commit_text), '5')
     752
     753        self.scm.dryrun = True
     754        write_into_file_at_path('test_file', 'still more test content')
     755        self.scm.commit_locally_with_message("yet another test commit")
     756        commit_text = self.scm.commit_with_message("yet another test commit")
     757        self.assertEqual(self.scm.svn_revision_from_commit_text(commit_text), '0')
     758
     759    def _one_local_commit_plus_working_copy_changes(self):
     760        write_into_file_at_path('test_file_commit1', 'more test content')
     761        run_command(['git', 'add', 'test_file_commit1'])
     762        self.scm.commit_locally_with_message("another test commit")
     763
     764        write_into_file_at_path('test_file_commit2', 'still more test content')
     765        run_command(['git', 'add', 'test_file_commit2'])
     766
     767    def test_commit_with_message_working_copy_only(self):
     768        write_into_file_at_path('test_file_commit1', 'more test content')
     769        run_command(['git', 'add', 'test_file_commit1'])
     770        scm = detect_scm_system(self.git_checkout_path)
     771        commit_text = scm.commit_with_message("yet another test commit")
     772
     773        self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '5')
     774        svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
     775        self.assertTrue(re.search(r'test_file_commit1', svn_log))
     776
     777    def test_commit_with_message_squashed(self):
     778        self._one_local_commit_plus_working_copy_changes()
     779        scm = detect_scm_system(self.git_checkout_path)
     780        commit_text = scm.commit_with_message("yet another test commit", squash=True)
     781
     782        self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '5')
     783        svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
     784        self.assertTrue(re.search(r'test_file_commit2', svn_log))
     785        self.assertTrue(re.search(r'test_file_commit1', svn_log))
     786
     787    def _two_local_commits(self):
     788        write_into_file_at_path('test_file_commit1', 'more test content')
     789        run_command(['git', 'add', 'test_file_commit1'])
     790        self.scm.commit_locally_with_message("another test commit")
     791
     792        write_into_file_at_path('test_file_commit2', 'still more test content')
     793        run_command(['git', 'add', 'test_file_commit2'])
     794        self.scm.commit_locally_with_message("yet another test commit")
     795
     796    def test_commit_with_message_git_commit(self):
     797        self._two_local_commits()
     798
     799        scm = detect_scm_system(self.git_checkout_path)
     800        commit_text = scm.commit_with_message("another test commit", git_commit="HEAD^")
     801        self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '5')
     802
     803        svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
     804        self.assertTrue(re.search(r'test_file_commit1', svn_log))
     805        self.assertFalse(re.search(r'test_file_commit2', svn_log))
     806
     807    def test_commit_with_message_git_commit_range(self):
     808        self._two_local_commits()
     809
     810        scm = detect_scm_system(self.git_checkout_path)
     811        commit_text = scm.commit_with_message("another test commit", git_commit="HEAD~2..HEAD")
     812        self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '5')
     813
     814        svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
     815        self.assertTrue(re.search(r'test_file_commit1', svn_log))
     816        self.assertTrue(re.search(r'test_file_commit2', svn_log))
     817
     818    def test_commit_with_message_multiple_local_commits(self):
     819        self._two_local_commits()
     820        scm = detect_scm_system(self.git_checkout_path)
     821        self.assertRaises(ScriptError, scm.commit_with_message, ["another test commit"])
     822
     823    def test_commit_with_message_multiple_local_commits_and_working_copy(self):
     824        self._two_local_commits()
     825        write_into_file_at_path('test_file_commit1', 'working copy change')
     826        scm = detect_scm_system(self.git_checkout_path)
     827        self.assertRaises(ScriptError, scm.commit_with_message, ["another test commit"])
     828
     829    def test_commit_with_message_git_commit_and_working_copy(self):
     830        self._two_local_commits()
     831        write_into_file_at_path('test_file_commit1', 'working copy change')
     832        scm = detect_scm_system(self.git_checkout_path)
     833        self.assertRaises(ScriptError, scm.commit_with_message, ["another test commit", 'git_commit="HEAD^"'])
     834
     835    def test_commit_with_message_multiple_local_commits_no_squash(self):
     836        self._two_local_commits()
     837        scm = detect_scm_system(self.git_checkout_path)
     838        commit_text = scm.commit_with_message("yet another test commit", squash=False)
     839        self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '5')
     840
     841        svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
     842        self.assertTrue(re.search(r'test_file_commit2', svn_log))
     843        self.assertFalse(re.search(r'test_file_commit1', svn_log))
     844
     845        svn_log = run_command(['git', 'svn', 'log', '--limit=2', '--verbose'])
     846        self.assertTrue(re.search(r'test_file_commit1', svn_log))
     847
     848    def test_commit_with_message_multiple_local_commits_squash(self):
     849        self._two_local_commits()
     850        scm = detect_scm_system(self.git_checkout_path)
     851        commit_text = scm.commit_with_message("yet another test commit", squash=True)
     852        self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '5')
     853
     854        svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
     855        self.assertTrue(re.search(r'test_file_commit2', svn_log))
     856        self.assertTrue(re.search(r'test_file_commit1', svn_log))
    748857
    749858    def test_reverse_diff(self):
     
    755864    def test_svn_apply_git_patch(self):
    756865        self._shared_test_svn_apply_git_patch()
     866
     867    def test_create_patch_local_plus_working_copy(self):
     868        self._one_local_commit_plus_working_copy_changes()
     869        scm = detect_scm_system(self.git_checkout_path)
     870        self.assertRaises(ScriptError, scm.create_patch)
     871
     872    def test_create_patch_multiple_local_commits(self):
     873        self._two_local_commits()
     874        scm = detect_scm_system(self.git_checkout_path)
     875        self.assertRaises(ScriptError, scm.create_patch)
     876
     877    def test_create_patch_squashed(self):
     878        self._one_local_commit_plus_working_copy_changes()
     879        scm = detect_scm_system(self.git_checkout_path)
     880        patch = scm.create_patch(squash=True)
     881        self.assertTrue(re.search(r'test_file_commit2', patch))
     882        self.assertTrue(re.search(r'test_file_commit1', patch))
     883
     884    def test_create_patch_not_squashed(self):
     885        self._one_local_commit_plus_working_copy_changes()
     886        scm = detect_scm_system(self.git_checkout_path)
     887        patch = scm.create_patch(squash=False)
     888        self.assertTrue(re.search(r'test_file_commit2', patch))
     889        self.assertFalse(re.search(r'test_file_commit1', patch))
     890
     891    def test_create_patch_git_commit(self):
     892        self._two_local_commits()
     893        scm = detect_scm_system(self.git_checkout_path)
     894        patch = scm.create_patch(git_commit="HEAD^")
     895        self.assertTrue(re.search(r'test_file_commit1', patch))
     896        self.assertFalse(re.search(r'test_file_commit2', patch))
     897
     898    def test_create_patch_git_commit_range(self):
     899        self._two_local_commits()
     900        scm = detect_scm_system(self.git_checkout_path)
     901        patch = scm.create_patch(git_commit="HEAD~2..HEAD")
     902        self.assertTrue(re.search(r'test_file_commit2', patch))
     903        self.assertTrue(re.search(r'test_file_commit1', patch))
     904
     905    def test_create_patch_multiple_local_commits_no_squash(self):
     906        self._two_local_commits()
     907        scm = detect_scm_system(self.git_checkout_path)
     908        patch = scm.create_patch(squash=False)
     909        # FIXME: It's weird that with squash=False, create_patch/changed_files ignores local commits,
     910        # but commit_with_message commits them.
     911        self.assertTrue(patch == "")
     912
     913    def test_create_patch_multiple_local_commits_squash(self):
     914        self._two_local_commits()
     915        scm = detect_scm_system(self.git_checkout_path)
     916        patch = scm.create_patch(squash=True)
     917        self.assertTrue(re.search(r'test_file_commit2', patch))
     918        self.assertTrue(re.search(r'test_file_commit1', patch))
    757919
    758920    def test_create_binary_patch(self):
     
    778940        run_command(['git', 'add', test_file_name])
    779941        run_command(['git', 'commit', '-m', 'binary diff'])
    780         patch_from_local_commit = scm.create_patch_from_local_commit('HEAD')
     942        patch_from_local_commit = scm.create_patch('HEAD')
    781943        self.assertTrue(re.search(r'\nliteral 0\n', patch_from_local_commit))
    782944        self.assertTrue(re.search(r'\nliteral 256\n', patch_from_local_commit))
    783         patch_since_local_commit = scm.create_patch_since_local_commit('HEAD^1')
    784         self.assertTrue(re.search(r'\nliteral 0\n', patch_since_local_commit))
    785         self.assertTrue(re.search(r'\nliteral 256\n', patch_since_local_commit))
    786         self.assertEqual(patch_from_local_commit, patch_since_local_commit)
     945
     946    def test_changed_files_local_plus_working_copy(self):
     947        self._one_local_commit_plus_working_copy_changes()
     948        scm = detect_scm_system(self.git_checkout_path)
     949        self.assertRaises(ScriptError, scm.changed_files)
     950
     951    def test_changed_files_multiple_local_commits(self):
     952        self._two_local_commits()
     953        scm = detect_scm_system(self.git_checkout_path)
     954        self.assertRaises(ScriptError, scm.changed_files)
     955
     956    def test_changed_files_squashed(self):
     957        self._one_local_commit_plus_working_copy_changes()
     958        scm = detect_scm_system(self.git_checkout_path)
     959        files = scm.changed_files(squash=True)
     960        self.assertTrue('test_file_commit2' in files)
     961        self.assertTrue('test_file_commit1' in files)
     962
     963    def test_changed_files_not_squashed(self):
     964        self._one_local_commit_plus_working_copy_changes()
     965        scm = detect_scm_system(self.git_checkout_path)
     966        files = scm.changed_files(squash=False)
     967        self.assertTrue('test_file_commit2' in files)
     968        self.assertFalse('test_file_commit1' in files)
     969
     970    def test_changed_files_git_commit(self):
     971        self._two_local_commits()
     972        scm = detect_scm_system(self.git_checkout_path)
     973        files = scm.changed_files(git_commit="HEAD^")
     974        self.assertTrue('test_file_commit1' in files)
     975        self.assertFalse('test_file_commit2' in files)
     976
     977    def test_changed_files_git_commit_range(self):
     978        self._two_local_commits()
     979        scm = detect_scm_system(self.git_checkout_path)
     980        files = scm.changed_files(git_commit="HEAD~2..HEAD")
     981        self.assertTrue('test_file_commit1' in files)
     982        self.assertTrue('test_file_commit2' in files)
     983
     984    def test_changed_files_multiple_local_commits_no_squash(self):
     985        self._two_local_commits()
     986        scm = detect_scm_system(self.git_checkout_path)
     987        files = scm.changed_files(squash=False)
     988        # FIXME: It's weird that with squash=False, create_patch/changed_files ignores local commits,
     989        # but commit_with_message commits them.
     990        self.assertTrue(len(files) == 0)
     991
     992    def test_changed_files_multiple_local_commits_squash(self):
     993        self._two_local_commits()
     994        scm = detect_scm_system(self.git_checkout_path)
     995        files = scm.changed_files(squash=True)
     996        self.assertTrue('test_file_commit2' in files)
     997        self.assertTrue('test_file_commit1' in files)
    787998
    788999    def test_changed_files(self):
  • trunk/WebKitTools/Scripts/webkitpy/common/net/rietveld.py

    r57552 r58261  
    2727# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2828
     29import logging
    2930import os
    3031import re
     
    5152        self.dryrun = dryrun
    5253        self._executive = executive
    53         self._upload_py = upload.__file__
    54         # Chop off the last character so we modify permissions on the py file instead of the pyc.
    55         if os.path.splitext(self._upload_py)[1] == ".pyc":
    56             self._upload_py = self._upload_py[:-1]
    57         os.chmod(self._upload_py, os.stat(self._upload_py).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
    5854
    5955    def url_for_issue(self, codereview_issue):
     
    6258        return "%s%s" % (config.codereview_server_url, codereview_issue)
    6359
    64     def post(self, message=None, codereview_issue=None, cc=None):
     60    def post(self, diff, message=None, codereview_issue=None, cc=None):
    6561        if not message:
    6662            raise ScriptError("Rietveld requires a message.")
    6763
    6864        args = [
    69             self._upload_py,
     65            # First argument is empty string to mimic sys.argv.
     66            "",
    7067            "--assume_yes",
    7168            "--server=%s" % config.codereview_server_host,
     
    8178            return
    8279
    83         output = self._executive.run_and_throw_if_fail(args)
    84         match = re.search("Issue created\. URL: " +
    85                           config.codereview_server_regex +
    86                           "(?P<codereview_issue>\d+)",
    87                           output)
    88         if match:
    89             return int(match.group('codereview_issue'))
     80        # Set logging level to avoid rietveld's logging spew.
     81        old_level_name = logging.getLogger().getEffectiveLevel()
     82        logging.getLogger().setLevel(logging.ERROR)
     83
     84        # Use RealMain instead of calling upload from the commandline so that
     85        # we can pass in the diff ourselves. Otherwise, upload will just use
     86        # git diff for git checkouts, which doesn't respect --squash and --git-commit.
     87        issue, patchset = upload.RealMain(args[1:], data=diff)
     88
     89        # Reset logging level to the original value.
     90        logging.getLogger().setLevel(old_level_name)
     91        return issue
  • trunk/WebKitTools/Scripts/webkitpy/style/optparser.py

    r57056 r58261  
    148148                 is_verbose=False,
    149149                 min_confidence=1,
    150                  output_format="emacs"):
     150                 output_format="emacs",
     151                 squash=False):
    151152        if filter_rules is None:
    152153            filter_rules = []
     
    167168        self.min_confidence = min_confidence
    168169        self.output_format = output_format
     170        self.squash = squash
    169171
    170172    # Useful for unit testing.
     
    180182            return False
    181183        if self.output_format != other.output_format:
     184            return False
     185        if self.squash != other.squash:
    182186            return False
    183187
     
    215219        if options.git_commit:
    216220            flags['git-commit'] = options.git_commit
     221        if options.squash:
     222            flags['squash'] = options.squash
    217223
    218224        flag_string = ''
     
    304310                          dest="filter_value", help=filter_help)
    305311
    306         git_help = "check all changes after the given git commit."
    307         parser.add_option("-g", "--git-commit", "--git-diff", "--git-since",
    308                           metavar="COMMIT", dest="git_since", help=git_help,)
     312        git_commit_help = ("check all changes in the given git commit. "
     313                           "Use 'commit_id..' to check all changes after commmit_id")
     314        parser.add_option("-g", "--git-diff", "--git-commit",
     315                          metavar="COMMIT", dest="git_commit", help=git_commit_help,)
    309316
    310317        min_confidence_help = ("set the minimum confidence of style errors "
     
    323330                          dest="output_format", default=default_output_format,
    324331                          help=output_format_help)
     332
     333        squash_help = ("All diffs from the remote branch are checked."
     334                       "If excluded, prompts whether to squash when there are multiple commits.")
     335        parser.add_option("-s", "--squash", action="store_true", dest="squash", help=squash_help)
     336
     337        squash_help = ("Only working copy diffs are checked."
     338                       "If excluded, prompts whether to squash when there are multiple commits.")
     339        parser.add_option("--no-squash", action="store_false", dest="squash", help=squash_help)
    325340
    326341        verbose_help = "enable verbose logging."
     
    408423
    409424        filter_value = options.filter_value
    410         git_commit = options.git_since
     425        git_commit = options.git_commit
    411426        is_verbose = options.is_verbose
    412427        min_confidence = options.min_confidence
     
    423438            self._parse_error('You cannot provide both paths and a git '
    424439                              'commit at the same time.')
    425 
    426         # FIXME: Add unit tests.
    427         if git_commit and '..' in git_commit:
    428             # FIXME: If the range is a "...", the code should find the common
    429             #        ancestor and start there.  See git diff --help for how
    430             #        "..." usually works.
    431             self._parse_error('invalid --git-commit option: option does '
    432                               'not support ranges "..": %s' % git_commit)
    433440
    434441        min_confidence = int(min_confidence)
     
    452459                                      is_verbose=is_verbose,
    453460                                      min_confidence=min_confidence,
    454                                       output_format=output_format)
     461                                      output_format=output_format,
     462                                      squash=options.squash)
    455463
    456464        return (paths, options)
  • trunk/WebKitTools/Scripts/webkitpy/style/optparser_unittest.py

    r57056 r58261  
    115115        self.assertLog(['ERROR: no such option: --bad\n'])
    116116
    117         self.assertRaises(SystemExit, parse, ['--git-diff=aa..bb'])
    118         self.assertLog(['ERROR: invalid --git-commit option: '
    119                         'option does not support ranges "..": aa..bb\n'])
    120 
    121117        self.assertRaises(SystemExit, parse, ['--min-confidence=bad'])
    122118        self.assertLog(['ERROR: option --min-confidence: '
     
    174170        (files, options) = parse(['--git-diff=commit'])
    175171        self.assertEquals(options.git_commit, 'commit')
    176         (files, options) = parse(['--git-since=commit'])
    177         self.assertEquals(options.git_commit, 'commit')
    178172        (files, options) = parse(['--verbose'])
    179173        self.assertEquals(options.is_verbose, True)
  • trunk/WebKitTools/Scripts/webkitpy/style_references.py

    r56899 r58261  
    7676        return self._scm.checkout_root
    7777
    78     def create_patch(self):
    79         return self._scm.create_patch()
     78    def create_patch(self, git_commit, squash):
     79        return self._scm.create_patch(git_commit, squash)
    8080
    81     def create_patch_since_local_commit(self, commit):
    82         return self._scm.create_patch_since_local_commit(commit)
    83 
  • trunk/WebKitTools/Scripts/webkitpy/tool/commands/download.py

    r57572 r58261  
    9595    def _prepare_state(self, options, args, tool):
    9696        return {
    97             "bug_id" : (args and args[0]) or tool.checkout().bug_id_for_this_commit()
     97            "bug_id": (args and args[0]) or tool.checkout().bug_id_for_this_commit(options.git_commit, options.squash),
    9898        }
    9999
  • trunk/WebKitTools/Scripts/webkitpy/tool/commands/upload.py

    r58036 r58261  
    141141
    142142class AbstractPatchUploadingCommand(AbstractSequencedCommand):
    143     def _bug_id(self, args, tool, state):
     143    def _bug_id(self, options, args, tool, state):
    144144        # Perfer a bug id passed as an argument over a bug url in the diff (i.e. ChangeLogs).
    145145        bug_id = args and args[0]
    146146        if not bug_id:
    147             bug_id = tool.checkout().bug_id_for_this_commit()
     147            bug_id = tool.checkout().bug_id_for_this_commit(options.git_commit, options.squash)
    148148        return bug_id
    149149
    150150    def _prepare_state(self, options, args, tool):
    151151        state = {}
    152         state["bug_id"] = self._bug_id(args, tool, state)
     152        state["bug_id"] = self._bug_id(options, args, tool, state)
    153153        if not state["bug_id"]:
    154154            error("No bug id passed and no bug url found in ChangeLogs.")
     
    223223    def _prepare_state(self, options, args, tool):
    224224        state = {}
    225         state["bug_id"] = self._bug_id(args, tool, state)
     225        state["bug_id"] = self._bug_id(options, args, tool, state)
    226226        return state
    227227
     
    270270
    271271            # Prefer --bug-id=, then a bug url in the commit message, then a bug url in the entire commit diff (i.e. ChangeLogs).
    272             bug_id = options.bug_id or parse_bug_id(commit_message.message()) or parse_bug_id(tool.scm().create_patch_from_local_commit(commit_id))
     272            bug_id = options.bug_id or parse_bug_id(commit_message.message()) or parse_bug_id(tool.scm().create_patch(git_commit=commit_id))
    273273            if not bug_id:
    274274                log("Skipping %s: No bug id found in commit or specified with --bug-id." % commit_id)
     
    280280                have_obsoleted_patches.add(bug_id)
    281281
    282             diff = tool.scm().create_patch_from_local_commit(commit_id)
     282            diff = tool.scm().create_patch(git_commit=commit_id)
    283283            description = options.description or commit_message.description(lstrip=True, strip_url=True)
    284284            comment_text = self._comment_text_for_commit(options, commit_message, tool, commit_id)
     
    399399            comment_text += tool.scm().files_changed_summary_for_commit(commit_id)
    400400
    401         diff = tool.scm().create_patch_from_local_commit(commit_id)
     401        diff = tool.scm().create_patch(git_commit=commit_id)
    402402        bug_id = tool.bugs.create_bug(bug_title, comment_text, options.component, diff, "Patch", cc=options.cc, mark_for_review=options.review, mark_for_commit_queue=options.request_commit)
    403403
     
    414414            (bug_title, comment_text) = self.prompt_for_bug_title_and_comment()
    415415        else:
    416             commit_message = tool.checkout().commit_message_for_this_commit()
     416            commit_message = tool.checkout().commit_message_for_this_commit(options.git_commit, options.squash)
    417417            bug_title = commit_message.description(lstrip=True, strip_url=True)
    418418            comment_text = commit_message.body(lstrip=True)
    419419
    420         diff = tool.scm().create_patch()
     420        diff = tool.scm().create_patch(options.git_commit, options.squash)
    421421        bug_id = tool.bugs.create_bug(bug_title, comment_text, options.component, diff, "Patch", cc=options.cc, mark_for_review=options.review, mark_for_commit_queue=options.request_commit)
    422422
  • trunk/WebKitTools/Scripts/webkitpy/tool/commands/upload_unittest.py

    r57788 r58261  
    5959        options.request_commit = False
    6060        options.review = True
     61        # Rietveld upload code requires a real SCM checkout.
     62        options.fancy_review = False
    6163        options.cc = None
    6264        expected_stderr = """Running check-webkit-style
     
    8789        options.request_commit = False
    8890        options.review = True
     91        # Rietveld upload code requires a real SCM checkout.
     92        options.fancy_review = False
    8993        options.cc = None
    9094        expected_stderr = """Running check-webkit-style
  • trunk/WebKitTools/Scripts/webkitpy/tool/main.py

    r57977 r58261  
    124124    # FIXME: This may be unnecessary since we pass global options to all commands during execute() as well.
    125125    def handle_global_options(self, options):
     126        self._options = options
    126127        if options.dry_run:
    127128            self.scm().dryrun = True
  • trunk/WebKitTools/Scripts/webkitpy/tool/mocktool.py

    r58210 r58261  
    385385        self.checkout_root = self.fake_checkout_root
    386386
    387     def create_patch(self):
     387    def create_patch(self, git_commit, squash):
    388388        return "Patch1"
    389389
     
    398398            return CommitMessage("CommitMessage2\n" \
    399399                "https://bugs.example.org/show_bug.cgi?id=75\n")
    400         raise Exception("Bogus commit_id in commit_message_for_local_commit.")
    401 
    402     def create_patch_from_local_commit(self, commit_id):
    403         if commit_id == "Commitish1":
    404             return "Patch1"
    405         if commit_id == "Commitish2":
    406             return "Patch2"
    407400        raise Exception("Bogus commit_id in commit_message_for_local_commit.")
    408401
     
    432425        return 12345
    433426
    434     def modified_changelogs(self):
     427    def modified_changelogs(self, git_commit, squash):
    435428        # Ideally we'd return something more interesting here.  The problem is
    436429        # that LandDiff will try to actually read the patch from disk!
    437430        return []
    438431
    439     def commit_message_for_this_commit(self):
     432    def commit_message_for_this_commit(self, git_commit, squash):
    440433        commit_message = Mock()
    441434        commit_message.message = lambda:"This is a fake commit message that is at least 50 characters."
  • trunk/WebKitTools/Scripts/webkitpy/tool/steps/abstractstep.py

    r58036 r58261  
    3737        self._port = None
    3838
    39     def _run_script(self, script_name, quiet=False, port=WebKitPort):
     39    def _run_script(self, script_name, args=None, quiet=False, port=WebKitPort):
    4040        log("Running %s" % script_name)
     41        command = [port.script_path(script_name)]
     42        if args:
     43            command.extend(args)
    4144        # FIXME: This should use self.port()
    42         self._tool.executive.run_and_throw_if_fail([port.script_path(script_name)], quiet)
     45        self._tool.executive.run_and_throw_if_fail(command, quiet)
    4346
    4447    # FIXME: The port should live on the tool.
     
    5053
    5154    _well_known_keys = {
    52         "diff" : lambda self: self._tool.scm().create_patch(),
    53         "changelogs" : lambda self: self._tool.checkout().modified_changelogs(),
     55        "diff": lambda self: self._tool.scm().create_patch(self._options.git_commit, self._options.squash),
     56        "changelogs": lambda self: self._tool.checkout().modified_changelogs(self._options.git_commit, self._options.squash),
    5457    }
    5558
  • trunk/WebKitTools/Scripts/webkitpy/tool/steps/applypatchwithlocalcommit.py

    r56592 r58261  
    4040        ApplyPatch.run(self, state)
    4141        if self._options.local_commit:
    42             commit_message = self._tool.checkout().commit_message_for_this_commit()
     42            commit_message = self._tool.checkout().commit_message_for_this_commit(git_commit=None, squash=False)
    4343            self._tool.scm().commit_locally_with_message(commit_message.message() or state["patch"].name())
  • trunk/WebKitTools/Scripts/webkitpy/tool/steps/checkstyle.py

    r56544 r58261  
    4040            Options.non_interactive,
    4141            Options.check_style,
     42            Options.git_commit,
     43            Options.no_squash,
     44            Options.squash,
    4245        ]
    4346
     
    4750        os.chdir(self._tool.scm().checkout_root)
    4851        try:
    49             self._run_script("check-webkit-style")
     52            args = []
     53            if self._options.git_commit:
     54                args.append("--git-commit")
     55                args.append(self._options.git_commit)
     56            if self._tool.scm().should_squash(self._options.squash):
     57                args.append("--squash")
     58            else:
     59                args.append("--no-squash")
     60
     61            self._run_script("check-webkit-style", args)
    5062        except ScriptError, e:
    5163            if self._options.non_interactive:
  • trunk/WebKitTools/Scripts/webkitpy/tool/steps/commit.py

    r57550 r58261  
    2828
    2929from webkitpy.tool.steps.abstractstep import AbstractStep
     30from webkitpy.tool.steps.options import Options
    3031
    3132
    3233class Commit(AbstractStep):
     34    @classmethod
     35    def options(cls):
     36        return [
     37            Options.git_commit,
     38            Options.no_squash,
     39            Options.squash,
     40        ]
     41
    3342    def run(self, state):
    34         commit_message = self._tool.checkout().commit_message_for_this_commit()
     43        commit_message = self._tool.checkout().commit_message_for_this_commit(self._options.git_commit, self._options.squash)
    3544        if len(commit_message.message()) < 50:
    3645            raise Exception("Attempted to commit with a commit message shorter than 50 characters.  Either your patch is missing a ChangeLog or webkit-patch may have a bug.")
    37         state["commit_text"] =  self._tool.scm().commit_with_message(commit_message.message())
     46        state["commit_text"] = self._tool.scm().commit_with_message(commit_message.message(),
     47            git_commit=self._options.git_commit, squash=self._options.squash)
  • trunk/WebKitTools/Scripts/webkitpy/tool/steps/options.py

    r57552 r58261  
    4343    fancy_review = make_option("--fancy-review", action="store_true", dest="fancy_review", default=False, help="(Experimental) Upload the patch to Rietveld code review tool.")
    4444    force_clean = make_option("--force-clean", action="store_true", dest="force_clean", default=False, help="Clean working directory before applying patches (removes local changes and commits)")
     45# FIXME: Make commit ranges treat each commit separately instead of squashing them into one.
     46    git_commit = make_option("--git-commit", action="store", dest="git_commit", help="Local git commit to upload/land. If a range, the commits are squashed into one.")
    4547    local_commit = make_option("--local-commit", action="store_true", dest="local_commit", default=False, help="Make a local commit for each applied patch")
     48    no_squash = make_option("--no-squash", action="store_false", dest="squash", help="Don't squash local commits into one on upload/land (git-only).")
    4649    non_interactive = make_option("--non-interactive", action="store_true", dest="non_interactive", default=False, help="Never prompt the user, fail as fast as possible.")
    4750    obsolete_patches = make_option("--no-obsolete", action="store_false", dest="obsolete_patches", default=True, help="Do not obsolete old patches before posting this one.")
     
    5356    review = make_option("--no-review", action="store_false", dest="review", default=True, help="Do not mark the patch for review.")
    5457    reviewer = make_option("-r", "--reviewer", action="store", type="string", dest="reviewer", help="Update ChangeLogs to say Reviewed by REVIEWER.")
    55     test = make_option("--test", action="store_true", dest="test", default=False, help="Commit without running run-webkit-tests")
     58    squash = make_option("-s", "--squash", action="store_true", dest="squash", help="Squash all local commits into one on upload/land (git-only).")
     59    test = make_option("--test", action="store_true", dest="test", default=False, help="Run run-webkit-tests before committing.")
    5660    update = make_option("--no-update", action="store_false", dest="update", default=True, help="Don't update the working directory.")
  • trunk/WebKitTools/Scripts/webkitpy/tool/steps/postcodereview.py

    r57679 r58261  
    3838            Options.description,
    3939            Options.fancy_review,
    40             Options.review,
     40            Options.git_commit,
     41            Options.no_squash,
     42            Options.squash,
    4143        ]
    4244
     
    6769                # this case if we support bug-less code reviews.
    6870                message = "Code review"
    69         created_issue = self._tool.codereview.post(message=message,
     71        created_issue = self._tool.codereview.post(diff=self.cached_lookup(state, "diff"),
     72                                                   message=message,
    7073                                                   codereview_issue=codereview_issue,
    7174                                                   cc=self._options.cc)
  • trunk/WebKitTools/Scripts/webkitpy/tool/steps/postdiff.py

    r58036 r58261  
    3939            Options.request_commit,
    4040            Options.open_bug,
     41            Options.git_commit,
     42            Options.no_squash,
     43            Options.squash,
    4144        ]
    4245
  • trunk/WebKitTools/Scripts/webkitpy/tool/steps/preparechangelog.py

    r56544 r58261  
    4242            Options.quiet,
    4343            Options.email,
     44            Options.git_commit,
     45            Options.no_squash,
     46            Options.squash,
    4447        ]
    4548
     
    5356        if self._options.email:
    5457            args.append("--email=%s" % self._options.email)
     58        if (self._tool.scm().supports_local_commits() and
     59            self._tool.scm().should_squash(self._options.squash)):
     60            args.append("--merge-base=%s" % self._tool.scm().svn_merge_base())
     61        if self._options.git_commit:
     62            args.append("--git-commit=%s" % self._options.git_commit)
     63
    5564        try:
    5665            self._tool.executive.run_and_throw_if_fail(args, self._options.quiet)
  • trunk/WebKitTools/Scripts/webkitpy/tool/steps/preparechangelogforrevert.py

    r56993 r58261  
    3737        # This could move to prepare-ChangeLog by adding a --revert= option.
    3838        self._run_script("prepare-ChangeLog")
    39         changelog_paths = self._tool.checkout().modified_changelogs()
     39        changelog_paths = self._tool.checkout().modified_changelogs(git_commit=None, squash=False)
    4040        bug_url = self._tool.bugs.bug_url_for_bug_id(state["bug_id"]) if state["bug_id"] else None
    4141        for changelog_path in changelog_paths:
  • trunk/WebKitTools/Scripts/webkitpy/tool/steps/updatechangelogswithreviewer.py

    r56601 r58261  
    3939    def options(cls):
    4040        return [
     41            Options.git_commit,
    4142            Options.reviewer,
     43            Options.no_squash,
     44            Options.squash,
    4245        ]
    4346
     
    6871
    6972        os.chdir(self._tool.scm().checkout_root)
    70         for changelog_path in self._tool.checkout().modified_changelogs():
     73        for changelog_path in self._tool.checkout().modified_changelogs(self._options.git_commit, self._options.squash):
    7174            ChangeLog(changelog_path).set_reviewer(reviewer)
  • trunk/WebKitTools/Scripts/webkitpy/tool/steps/validatereviewer.py

    r56765 r58261  
    3232from webkitpy.common.checkout.changelog import ChangeLog
    3333from webkitpy.tool.steps.abstractstep import AbstractStep
     34from webkitpy.tool.steps.options import Options
    3435from webkitpy.common.system.deprecated_logging import error, log
    3536
     
    3738# FIXME: Some of this logic should probably be unified with CommitterValidator?
    3839class ValidateReviewer(AbstractStep):
     40    @classmethod
     41    def options(cls):
     42        return [
     43            Options.git_commit,
     44            Options.no_squash,
     45            Options.squash,
     46        ]
     47
    3948    # FIXME: This should probably move onto ChangeLogEntry
    4049    def _has_valid_reviewer(self, changelog_entry):
     
    5564        #        directory issue more globally.
    5665        os.chdir(self._tool.scm().checkout_root)
    57         for changelog_path in self._tool.checkout().modified_changelogs():
     66        for changelog_path in self._tool.checkout().modified_changelogs(self._options.git_commit, self._options.squash):
    5867            changelog_entry = ChangeLog(changelog_path).latest_entry()
    5968            if self._has_valid_reviewer(changelog_entry):
Note: See TracChangeset for help on using the changeset viewer.