示例#1
0
    def test_lint_staged_stdin(self):
        """ Tests linting a staged commit. Gitint should lint the passed commit message andfetch additional meta-data
            from the underlying repository. The easiest way to test this is by inspecting `--debug` output.
            This is the equivalent of doing:
            echo "WIP: Pïpe test." | gitlint --staged --debug
        """
        # Create a commit first, before we stage changes. This ensures the repo is properly initialized.
        self.create_simple_commit(u"Sïmple title.\n")

        # Add some files, stage them: they should show up in the debug output as changed file
        filename1 = self.create_file(self.tmp_git_repo)
        git("add", filename1, _cwd=self.tmp_git_repo)
        filename2 = self.create_file(self.tmp_git_repo)
        git("add", filename2, _cwd=self.tmp_git_repo)

        output = gitlint(echo(u"WIP: Pïpe test."), "--staged", "--debug",
                         _cwd=self.tmp_git_repo, _tty_in=False, _err_to_out=True, _ok_code=[3])

        # Determine variable parts of expected output
        expected_kwargs = self.get_debug_vars_last_commit()
        expected_kwargs.update({'changed_files': sstr(sorted([filename1, filename2]))})

        # It's not really possible to determine the "Date: ..." line that is part of the debug output as this date
        # is not taken from git but instead generated by gitlint itself. As a workaround, we extract the date from the
        # gitlint output using a regex, parse the date to ensure the format is correct, and then pass that as an
        # expected variable.
        matches = re.search(r'^Date:\s+(.*)', str(output), re.MULTILINE)
        if matches:
            expected_date = arrow.get(str(matches.group(1)), "YYYY-MM-DD HH:mm:ss Z").format("YYYY-MM-DD HH:mm:ss Z")
            expected_kwargs['staged_date'] = expected_date

        self.assertEqualStdout(output, self.get_expected("test_commits/test_lint_staged_stdin_1", expected_kwargs))
        self.assertEqual(output.exit_code, 3)
示例#2
0
    def test_commit_hook_worktree(self):
        """ Tests that hook installation and un-installation also work in git worktrees.
        Test steps:
            ```sh
            git init <tmpdir>
            cd <tmpdir>
            git worktree add <worktree-tempdir>
            cd <worktree-tempdir>
            gitlint install-hook
            gitlint uninstall-hook
            ```
        """
        tmp_git_repo = self.create_tmp_git_repo()
        self.create_simple_commit("Simple title\n\nContënt in the body",
                                  git_repo=tmp_git_repo)

        worktree_dir = self.generate_temp_path()
        self.tmp_git_repos.append(
            worktree_dir)  # make sure we clean up the worktree afterwards

        git("worktree", "add", worktree_dir, _cwd=tmp_git_repo, _tty_in=True)

        output_installed = gitlint("install-hook", _cwd=worktree_dir)
        expected_hook_path = os.path.join(tmp_git_repo, ".git", "hooks",
                                          "commit-msg")
        expected_msg = f"Successfully installed gitlint commit-msg hook in {expected_hook_path}\r\n"
        self.assertEqual(output_installed, expected_msg)

        output_uninstalled = gitlint("uninstall-hook", _cwd=worktree_dir)
        expected_hook_path = os.path.join(tmp_git_repo, ".git", "hooks",
                                          "commit-msg")
        expected_msg = f"Successfully uninstalled gitlint commit-msg hook from {expected_hook_path}\r\n"
        self.assertEqual(output_uninstalled, expected_msg)
示例#3
0
 def test_successful(self):
     """ Test linting multiple commits without violations """
     git("checkout", "-b", "test-branch-commits-base", _cwd=self.tmp_git_repo)
     self.create_simple_commit(u"Sïmple title\n\nSimple bödy describing the commit")
     git("checkout", "-b", "test-branch-commits", _cwd=self.tmp_git_repo)
     self.create_simple_commit(u"Sïmple title2\n\nSimple bödy describing the commit2")
     self.create_simple_commit(u"Sïmple title3\n\nSimple bödy describing the commit3")
     output = gitlint("--commits", "test-branch-commits-base...test-branch-commits",
                      _cwd=self.tmp_git_repo, _tty_in=True)
     self.assertEqualStdout(output, "")
示例#4
0
    def test_successful_gitconfig(self):
        """ Test gitlint when the underlying repo has specific git config set.
        In the past, we've had issues with gitlint failing on some of these, so this acts as a regression test. """

        # Different commentchar (Note: tried setting this to a special unicode char, but git doesn't like that)
        git("config", "--add", "core.commentchar", "$", _cwd=self.tmp_git_repo)
        self.create_simple_commit(
            u"Sïmple title\n\nSimple bödy describing the commit\n$after commentchar\t ignored"
        )
        output = gitlint(_cwd=self.tmp_git_repo,
                         _tty_in=True,
                         _err_to_out=True)
        self.assertEqualStdout(output, "")
示例#5
0
    def test_commit_hook_continue(self):
        self.responses = ["y"]
        test_filename = self._create_simple_commit(
            u"WIP: This ïs a title.\nContënt on the second line",
            out=self._interact,
            tty_in=True)

        # Determine short commit-msg hash, needed to determine expected output
        short_hash = git("rev-parse",
                         "--short",
                         "HEAD",
                         _cwd=self.tmp_git_repo,
                         _tty_in=True).replace("\n", "")

        expected_output = self._violations()
        expected_output += [
            "Continue with commit anyways (this keeps the current commit message)? "
            + "[y(es)/n(no)/e(dit)] " +
            u"[master (root-commit) %s] WIP: This ïs a title. Contënt on the second line\n"
            % short_hash, " 1 file changed, 0 insertions(+), 0 deletions(-)\n",
            u" create mode 100644 %s\n" % test_filename
        ]

        assert len(self.githook_output) == len(expected_output)
        for output, expected in zip(self.githook_output, expected_output):
            self.assertMultiLineEqual(output.replace('\r', ''),
                                      expected.replace('\r', ''))
示例#6
0
 def get_system_info_dict():
     """ Returns a dict with items related to system values logged by `gitlint --debug` """
     expected_gitlint_version = gitlint("--version").replace("gitlint, version ", "").strip()
     expected_git_version = git("--version").strip()
     return {'platform': platform.platform(), 'python_version': sys.version,
             'git_version': expected_git_version, 'gitlint_version': expected_gitlint_version,
             'GITLINT_USE_SH_LIB': BaseTestCase.GITLINT_USE_SH_LIB, 'DEFAULT_ENCODING': DEFAULT_ENCODING}
示例#7
0
 def get_last_commit_short_hash(self, git_repo=None):
     git_repo = self.tmp_git_repo if git_repo is None else git_repo
     return git("rev-parse",
                "--short",
                "HEAD",
                _cwd=git_repo,
                _err_to_out=True).replace("\n", "")
示例#8
0
    def test_violations(self):
        """ Test linting multiple commits with violations """
        git("checkout", "-b", "test-branch-commits-violations-base", _cwd=self.tmp_git_repo)
        self.create_simple_commit(u"Sïmple title.\n")
        git("checkout", "-b", "test-branch-commits-violations", _cwd=self.tmp_git_repo)

        self.create_simple_commit(u"Sïmple title2.\n")
        commit_sha1 = self.get_last_commit_hash()[:10]
        self.create_simple_commit(u"Sïmple title3.\n")
        commit_sha2 = self.get_last_commit_hash()[:10]
        output = gitlint("--commits", "test-branch-commits-violations-base...test-branch-commits-violations",
                         _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[4])

        self.assertEqual(output.exit_code, 4)
        expected_kwargs = {'commit_sha1': commit_sha1, 'commit_sha2': commit_sha2}
        self.assertEqualStdout(output, self.get_expected("test_commits/test_violations_1", expected_kwargs))
示例#9
0
    def test_revert_commit(self):
        self.create_simple_commit(u"WIP: Cömmit on master.\n\nSimple bödy")
        hash = self.get_last_commit_hash()
        git("revert", hash, _cwd=self.tmp_git_repo)

        # Run gitlint and assert output is empty
        output = gitlint(_cwd=self.tmp_git_repo, _tty_in=True)
        self.assertEqualStdout(output, "")

        # Assert that we do see the error if we disable the ignore-revert-commits option
        output = gitlint("-c",
                         "general.ignore-revert-commits=false",
                         _cwd=self.tmp_git_repo,
                         _tty_in=True,
                         _ok_code=[1])
        self.assertEqual(output.exit_code, 1)
        expected = u"1: T5 Title contains the word 'WIP' (case-insensitive): \"Revert \"WIP: Cömmit on master.\"\"\n"
        self.assertEqualStdout(output, expected)
示例#10
0
    def get_debug_vars_last_commit(self, git_repo=None):
        """ Returns a dict with items related to `gitlint --debug` output for the last commit. """
        target_repo = git_repo if git_repo else self.tmp_git_repo
        commit_sha = self.get_last_commit_hash(git_repo=target_repo)
        expected_date = git("log", "-1", "--pretty=%ai", _tty_out=False, _cwd=target_repo)
        expected_date = arrow.get(str(expected_date), "YYYY-MM-DD HH:mm:ss Z").format("YYYY-MM-DD HH:mm:ss Z")

        expected_kwargs = self.get_system_info_dict()
        expected_kwargs.update({'target': target_repo, 'commit_sha': commit_sha, 'commit_date': expected_date})
        return expected_kwargs
示例#11
0
    def test_squash_commit(self):
        # Create a normal commit and assert that it has a violation
        test_filename = self.create_simple_commit(
            u"Cömmit on WIP master\n\nSimple bödy that is long enough")
        output = gitlint(_cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[1])
        expected = u"1: T5 Title contains the word 'WIP' (case-insensitive): \"Cömmit on WIP master\"\n"
        self.assertEqualStdout(output, expected)

        # Make a small modification to the commit and commit it using squash commit
        with io.open(os.path.join(self.tmp_git_repo, test_filename),
                     "a",
                     encoding=DEFAULT_ENCODING) as fh:
            # Wanted to write a unicode string, but that's obnoxious if you want to do it across Python 2 and 3.
            # https://stackoverflow.com/questions/22392377/
            # error-writing-a-file-with-file-write-in-python-unicodeencodeerror
            # So just keeping it simple - ASCII will here
            fh.write(u"Appending some stuff\n")

        git("add", test_filename, _cwd=self.tmp_git_repo)

        git("commit",
            "--squash",
            self.get_last_commit_hash(),
            "-m",
            u"Töo short body",
            _cwd=self.tmp_git_repo)

        # Assert that gitlint does not show an error for the fixup commit
        output = gitlint(_cwd=self.tmp_git_repo, _tty_in=True)
        # No need to check exit code, the command above throws an exception on > 0 exit codes
        self.assertEqualStdout(output, "")

        # Make sure that if we set the ignore-squash-commits option to false that we do still see the violations
        output = gitlint("-c",
                         "general.ignore-squash-commits=false",
                         _cwd=self.tmp_git_repo,
                         _tty_in=True,
                         _ok_code=[2])
        expected = u"1: T5 Title contains the word 'WIP' (case-insensitive): \"squash! Cömmit on WIP master\"\n" + \
            u"3: B5 Body message is too short (14<20): \"Töo short body\"\n"

        self.assertEqualStdout(output, expected)
示例#12
0
    def create_tmp_git_repo(cls):
        """ Creates a temporary git repository and returns its directory path """
        tmp_git_repo = cls.generate_temp_path()
        cls.tmp_git_repos.append(tmp_git_repo)

        git("init", tmp_git_repo)
        # configuring name and email is required in every git repot
        git("config", "user.name", "gitlint-test-user", _cwd=tmp_git_repo)
        git("config", "user.email", "*****@*****.**", _cwd=tmp_git_repo)

        # Git does not by default print unicode paths, fix that by setting core.quotePath to false
        # http://stackoverflow.com/questions/34549040/git-not-displaying-unicode-file-names
        # ftp://www.kernel.org/pub/software/scm/git/docs/git-config.html
        git("config", "core.quotePath", "false", _cwd=tmp_git_repo)

        # Git on mac doesn't like unicode characters by default, so we need to set this option
        # http://stackoverflow.com/questions/5581857/git-and-the-umlaut-problem-on-mac-os-x
        git("config", "core.precomposeunicode", "true", _cwd=tmp_git_repo)

        return tmp_git_repo
示例#13
0
    def _create_simple_commit(self,
                              message,
                              out=None,
                              ok_code=None,
                              env=None,
                              git_repo=None,
                              tty_in=False):
        """ Creates a simple commit with an empty test file.
            :param message: Commit message for the commit. """

        git_repo = self.tmp_git_repo if git_repo is None else git_repo

        # Let's make sure that we copy the environment in which this python code was executed as environment
        # variables can influence how git runs.
        # This was needed to fix https://github.com/jorisroovers/gitlint/issues/15 as we need to make sure to use
        # the PATH variable that contains the virtualenv's python binary.
        environment = os.environ
        if env:
            environment.update(env)

        # Create file and add to git
        test_filename = u"test-fïle-" + str(uuid4())
        io.open(os.path.join(git_repo, test_filename),
                'a',
                encoding=DEFAULT_ENCODING).close()
        git("add", test_filename, _cwd=git_repo)
        # https://amoffat.github.io/sh/#interactive-callbacks
        if not ok_code:
            ok_code = [0]

        git("commit",
            "-m",
            message,
            _cwd=git_repo,
            _err_to_out=True,
            _out=out,
            _tty_in=tty_in,
            _ok_code=ok_code,
            _env=environment)
        return test_filename
示例#14
0
    def test_commit_hook_abort(self):
        self.responses = ["n"]
        test_filename = self.create_simple_commit(
            "WIP: This ïs a title.\nContënt on the second line",
            out=self._interact,
            ok_code=1,
            tty_in=True)
        git("rm", "-f", test_filename, _cwd=self.tmp_git_repo)

        # Determine short commit-msg hash, needed to determine expected output

        expected_output = self._violations()
        expected_output += [
            "Continue with commit anyways (this keeps the current commit message)? "
            + "[y(es)/n(no)/e(dit)] " + "Commit aborted.\n",
            "Your commit message: \n",
            "-----------------------------------------------\n",
            "WIP: This ïs a title.\n", "Contënt on the second line\n",
            "-----------------------------------------------\n"
        ]

        self.assertListEqual(expected_output, self.githook_output)
示例#15
0
    def test_lint_head(self):
        """ Testing whether we can also recognize special refs like 'HEAD' """
        tmp_git_repo = self.create_tmp_git_repo()
        self.create_simple_commit(u"Sïmple title.\n\nSimple bödy describing the commit", git_repo=tmp_git_repo)
        self.create_simple_commit(u"Sïmple title", git_repo=tmp_git_repo)
        self.create_simple_commit(u"WIP: Sïmple title\n\nSimple bödy describing the commit", git_repo=tmp_git_repo)
        output = gitlint("--commits", "HEAD", _cwd=tmp_git_repo, _tty_in=True, _ok_code=[3])
        revlist = git("rev-list", "HEAD", _tty_in=True, _cwd=tmp_git_repo).split()

        expected_kwargs = {"commit_sha0": revlist[0][:10], "commit_sha1": revlist[1][:10],
                           "commit_sha2": revlist[2][:10]}

        self.assertEqualStdout(output, self.get_expected("test_commits/test_lint_head_1", expected_kwargs))
示例#16
0
    def test_config_from_file_debug(self):
        commit_msg = u"WIP: Thïs is a title thåt is a bit longer.\nContent on the second line\n" + \
                     "This line of the body is here because we need it"
        self._create_simple_commit(commit_msg)
        commit_sha = self.get_last_commit_hash()
        config_path = self.get_sample_path("config/gitlintconfig")
        output = gitlint("--config",
                         config_path,
                         "--debug",
                         _cwd=self.tmp_git_repo,
                         _tty_in=True,
                         _ok_code=[5])

        expected_date = git("log",
                            "-1",
                            "--pretty=%ai",
                            _cwd=self.tmp_git_repo)
        expected_date = arrow.get(str(expected_date),
                                  "YYYY-MM-DD HH:mm:ss Z").datetime
        expected_gitlint_version = gitlint("--version").replace(
            "gitlint, version ", "").replace("\n", "")
        expected_git_version = git("--version").replace("\n", "")

        expected_kwargs = {
            'platform': platform.platform(),
            'python_version': sys.version,
            'git_version': expected_git_version,
            'gitlint_version': expected_gitlint_version,
            'GITLINT_USE_SH_LIB': self.GITLINT_USE_SH_LIB,
            'config_path': config_path,
            'target': self.tmp_git_repo,
            'commit_sha': commit_sha,
            'commit_date': expected_date
        }
        self.assertEqualStdout(
            output,
            self.get_expected("test_config/test_config_from_file_debug_1",
                              expected_kwargs))
示例#17
0
    def test_ignore_commits(self):
        """ Tests multiple commits of which some rules get igonored because of ignore-* rules """
        # Create repo and some commits
        tmp_git_repo = self.create_tmp_git_repo()
        self.create_simple_commit(u"Sïmple title.\n\nSimple bödy describing the commit", git_repo=tmp_git_repo)
        # Normally, this commit will give T3 (trailing-punctuation), T5 (WIP) and B5 (bod-too-short) violations
        # But in this case only B5 because T3 and T5 are being ignored because of config
        self.create_simple_commit(u"Release: WIP tïtle.\n\nShort", git_repo=tmp_git_repo)
        # In the following 2 commits, the T3 violations are as normal
        self.create_simple_commit(
            u"Sïmple WIP title3.\n\nThis is \ta relëase commit\nMore info", git_repo=tmp_git_repo)
        self.create_simple_commit(u"Sïmple title4.\n\nSimple bödy describing the commit4", git_repo=tmp_git_repo)
        revlist = git("rev-list", "HEAD", _tty_in=True, _cwd=tmp_git_repo).split()

        config_path = self.get_sample_path("config/ignore-release-commits")
        output = gitlint("--commits", "HEAD", "--config", config_path, _cwd=tmp_git_repo, _tty_in=True, _ok_code=[4])

        expected_kwargs = {"commit_sha0": revlist[0][:10], "commit_sha1": revlist[1][:10],
                           "commit_sha2": revlist[2][:10], "commit_sha3": revlist[3][:10]}
        self.assertEqualStdout(output, self.get_expected("test_commits/test_ignore_commits_1", expected_kwargs))
示例#18
0
    def test_successful_merge_commit(self):
        # Create branch on master
        self.create_simple_commit(u"Cömmit on master\n\nSimple bödy")

        # Create test branch, add a commit and determine the commit hash
        git("checkout", "-b", "test-branch", _cwd=self.tmp_git_repo)
        git("checkout", "test-branch", _cwd=self.tmp_git_repo)
        commit_title = u"Commit on test-brånch with a pretty long title that will cause issues when merging"
        self.create_simple_commit(u"{0}\n\nSïmple body".format(commit_title))
        hash = self.get_last_commit_hash()

        # Checkout master and merge the commit
        # We explicitly set the title of the merge commit to the title of the previous commit as this or similar
        # behavior is what many tools do that handle merges (like github, gerrit, etc).
        git("checkout", "master", _cwd=self.tmp_git_repo)
        git("merge",
            "--no-ff",
            "-m",
            u"Merge '{0}'".format(commit_title),
            hash,
            _cwd=self.tmp_git_repo)

        # Run gitlint and assert output is empty
        output = gitlint(_cwd=self.tmp_git_repo, _tty_in=True)
        self.assertEqualStdout(output, "")

        # Assert that we do see the error if we disable the ignore-merge-commits option
        output = gitlint("-c",
                         "general.ignore-merge-commits=false",
                         _cwd=self.tmp_git_repo,
                         _tty_in=True,
                         _ok_code=[1])
        self.assertEqual(output.exit_code, 1)
        self.assertEqualStdout(
            output,
            u"1: T1 Title exceeds max length (90>72): \"Merge '{0}'\"\n".
            format(commit_title))