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)
def test_verbosity(self): self._create_simple_commit( u"WIP: Thïs is a title.\nContënt on the second line") output = gitlint("-v", _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[3]) expected = u"1: T3\n1: T5\n2: B4\n" self.assertEqualStdout(output, expected) output = gitlint("-vv", _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[3]) self.assertEqualStdout( output, self.get_expected("test_config/test_verbosity_1")) output = gitlint("-vvv", _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[3]) self.assertEqualStdout( output, self.get_expected("test_config/test_verbosity_2")) # test silent mode output = gitlint("--silent", _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[3]) self.assertEqualStdout(output, "")
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}
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)
def test_config_from_file_debug(self): # Test both on existing and new repo (we've had a bug in the past that was unique to empty repos) repos = [self.tmp_git_repo, self.create_tmp_git_repo()] for target_repo in repos: commit_msg = "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" filename = self.create_simple_commit(commit_msg, git_repo=target_repo) config_path = self.get_sample_path("config/gitlintconfig") output = gitlint("--config", config_path, "--debug", _cwd=target_repo, _tty_in=True, _ok_code=[5]) expected_kwargs = self.get_debug_vars_last_commit( git_repo=target_repo) expected_kwargs.update({ 'config_path': config_path, 'changed_files': [filename] }) self.assertEqualStdout( output, self.get_expected("test_config/test_config_from_file_debug_1", expected_kwargs))
def test_user_defined_rules_extra(self): extra_path = self.get_sample_path("user_rules/extra") commit_msg = "WIP: Thi$ is å title\nContent on the second line" self.create_simple_commit(commit_msg) output = gitlint("--extra-path", extra_path, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[9]) self.assertEqualStdout(output, self.get_expected("test_user_defined/test_user_defined_rules_extra_1", {'repo-path': self.tmp_git_repo}))
def test_user_defined_rules_examples1(self): """ Test the user defined rules in the top-level `examples/` directory """ extra_path = self.get_example_path() commit_msg = "WIP: Thi$ is å title\nContent on the second line" self.create_simple_commit(commit_msg) output = gitlint("--extra-path", extra_path, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[5]) self.assertEqualStdout(output, self.get_expected("test_user_defined/test_user_defined_rules_examples_1"))
def test_msg_filename(self): tmp_commit_msg_file = self.create_tmpfile(u"WIP: msg-fïlename test.") output = gitlint("--msg-filename", tmp_commit_msg_file, _tty_in=True, _ok_code=[3]) self.assertEqualStdout( output, self.get_expected("test_gitlint/test_msg_filename_1"))
def test_successful(self): # Test for STDIN with and without a TTY attached self.create_simple_commit( u"Sïmple title\n\nSimple bödy describing the commit") output = gitlint(_cwd=self.tmp_git_repo, _tty_in=True, _err_to_out=True) self.assertEqualStdout(output, "")
def test_user_defined_rules_examples_with_config(self): """ Test the user defined rules in the top-level `examples/` directory """ extra_path = self.get_example_path() commit_msg = "WIP: Thi$ is å title\nContent on the second line" self.create_simple_commit(commit_msg) output = gitlint("--extra-path", extra_path, "-c", "body-max-line-count.max-line-count=1", _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[6]) expected_path = "test_user_defined/test_user_defined_rules_examples_with_config_1" self.assertEqualStdout(output, self.get_expected(expected_path))
def test_set_rule_option(self): self._create_simple_commit(u"This ïs a title.") output = gitlint("-c", "title-max-length.line-length=5", _tty_in=True, _cwd=self.tmp_git_repo, _ok_code=[3]) self.assertEqualStdout( output, self.get_expected("test_config/test_set_rule_option_1"))
def test_git_errors(self): # Repo has no commits: caused by `git log` empty_git_repo = self.create_tmp_git_repo() output = gitlint(_cwd=empty_git_repo, _tty_in=True, _ok_code=[self.GIT_CONTEXT_ERROR_CODE]) expected = u"Current branch has no commits. Gitlint requires at least one commit to function.\n" self.assertEqualStdout(output, expected) # Repo has no commits: caused by `git rev-parse` output = gitlint(echo(u"WIP: Pïpe test."), "--staged", _cwd=empty_git_repo, _tty_in=False, _err_to_out=True, _ok_code=[self.GIT_CONTEXT_ERROR_CODE]) self.assertEqualStdout(output, expected)
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)
def test_invalid_contrib_rules(self): self._create_simple_commit("WIP: test") output = gitlint("--contrib", u"föobar,CC1", _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[255]) self.assertEqualStdout( output, u"Config Error: No contrib rule with id or name 'föobar' found.\n")
def test_ignore_by_name(self): self._create_simple_commit( u"WIP: Thïs is a title.\nContënt on the second line") output = gitlint("--ignore", "title-must-not-contain-word,body-first-line-empty", _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[1]) expected = u"1: T3 Title has trailing punctuation (.): \"WIP: Thïs is a title.\"\n" self.assertEqualStdout(output, expected)
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, "")
def test_ignore_by_id(self): self._create_simple_commit( u"WIP: Thïs is a title.\nContënt on the second line") output = gitlint("--ignore", "T5,B4", _tty_in=True, _cwd=self.tmp_git_repo, _ok_code=[1]) expected = u"1: T3 Title has trailing punctuation (.): \"WIP: Thïs is a title.\"\n" self.assertEqualStdout(output, expected)
def setUp(self): self.responses = [] self.response_index = 0 self.githook_output = [] # install git commit-msg hook and assert output output_installed = gitlint("install-hook", _cwd=self.tmp_git_repo) expected_installed = u"Successfully installed gitlint commit-msg hook in %s/.git/hooks/commit-msg\n" % \ self.tmp_git_repo self.assertEqualStdout(output_installed, expected_installed)
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)
def test_lint_single_commit(self): self._create_simple_commit(u"Sïmple title.\n") self._create_simple_commit(u"Sïmple title2.\n") commit_sha = self.get_last_commit_hash() refspec = "{0}^...{0}".format(commit_sha) self._create_simple_commit(u"Sïmple title3.\n") output = gitlint("--commits", refspec, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[2]) expected = (u"1: T3 Title has trailing punctuation (.): \"Sïmple title2.\"\n" + u"3: B6 Body message is missing\n") self.assertEqual(output.exit_code, 2) self.assertEqualStdout(output, expected)
def test_named_rule(self): commit_msg = "WIP: thåt dûr bår\n\nSïmple commit body" self.create_simple_commit(commit_msg) config_path = self.get_sample_path("config/named-rules") output = gitlint("--config", config_path, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[5]) self.assertEqualStdout( output, self.get_expected("test_named_rules/test_named_rule_1"))
def test_contrib_rules(self): self._create_simple_commit( u"WIP Thi$ is å title\n\nMy bödy that is a bit longer than 20 chars" ) output = gitlint("--contrib", "contrib-title-conventional-commits,CC1", _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[4]) self.assertEqualStdout( output, self.get_expected("test_contrib/test_contrib_rules_1"))
def test_lint_single_commit(self): """ Tests `gitlint --commits <sha>` """ self.create_simple_commit("Sïmple title.\n") self.create_simple_commit("Sïmple title2.\n") commit_sha = self.get_last_commit_hash() refspec = f"{commit_sha}^...{commit_sha}" self.create_simple_commit("Sïmple title3.\n") output = gitlint("--commits", refspec, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[2]) expected = ("1: T3 Title has trailing punctuation (.): \"Sïmple title2.\"\n" + "3: B6 Body message is missing\n") self.assertEqual(output.exit_code, 2) self.assertEqualStdout(output, expected)
def test_invalid_user_defined_rules(self): extra_path = self.get_sample_path("user_rules/incorrect_linerule") self.create_simple_commit("WIP: test") output = gitlint("--extra-path", extra_path, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[255]) self.assertEqualStdout( output, "Config Error: User-defined rule class 'MyUserLineRule' must have a 'validate' method\n" )
def test_user_defined_rules(self): extra_path = self.get_example_path() commit_msg = u"WIP: Thi$ is å title\nContent on the second line" self._create_simple_commit(commit_msg) output = gitlint("--extra-path", extra_path, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[4]) self.assertEqualStdout( output, self.get_expected("test_user_defined/test_user_defined_rules_1"))
def test_config_from_file(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) config_path = self.get_sample_path("config/gitlintconfig") output = gitlint("--config", config_path, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[5]) self.assertEqualStdout( output, self.get_expected("test_config/test_config_from_file_1"))
def test_no_git_email_set(self): """ Ensure we print out a helpful message if user.email is not set """ tmp_commit_msg_file = self.create_tmpfile( "WIP: msg-fïlename NO email test.") env = self.create_tmp_git_config("[user]\n name = test åuthor\n") output = gitlint("--staged", "--msg-filename", tmp_commit_msg_file, _ok_code=[self.GIT_CONTEXT_ERROR_CODE], _env=env) expected = "Missing git configuration: please set user.email\n" self.assertEqualStdout(output, expected)
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, "")
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))
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))