Beispiel #1
0
    def test_lint_sample3(self):
        linter = GitLinter(LintConfig())
        gitcontext = GitContext()
        gitcontext.set_commit_msg(self.get_sample("commit_message/sample3"))
        violations = linter.lint(gitcontext)

        title = " Commit title containing 'WIP', \tleading and trailing whitespace and longer than 72 characters."
        expected = [
            RuleViolation("T1", "Title exceeds max length (95>72)", title, 1),
            RuleViolation("T3", "Title has trailing punctuation (.)", title, 1),
            RuleViolation("T4", "Title contains hard tab characters (\\t)", title, 1),
            RuleViolation("T5", "Title contains the word 'WIP' (case-insensitive)", title, 1),
            RuleViolation("T6", "Title has leading whitespace", title, 1),
            RuleViolation("B4", "Second line is not empty", "This line should be empty", 2),
            RuleViolation(
                "B1",
                "Line exceeds max length (101>80)",
                "This is the first line is meant to test a line that exceeds the maximum line "
                + "length of 80 characters.",
                3,
            ),
            RuleViolation("B2", "Line has trailing whitespace", "This line has a trailing space. ", 4),
            RuleViolation("B2", "Line has trailing whitespace", "This line has a trailing tab.\t", 5),
            RuleViolation("B3", "Line contains hard tab characters (\\t)", "This line has a trailing tab.\t", 5),
        ]

        self.assertListEqual(violations, expected)
Beispiel #2
0
def lint(ctx):
    """ Lints a git repository [default command] """
    lint_config = ctx.obj[0]
    try:
        if sys.stdin.isatty():
            # If target has not been set explicitly before, fallback to the current directory
            gitcontext = GitContext.from_local_repository(lint_config.target)
        else:
            gitcontext = GitContext.from_commit_msg(sys.stdin.read())
    except GitContextError as e:
        click.echo(str(e))
        ctx.exit(GIT_CONTEXT_ERROR_CODE)

    config_builder = ctx.obj[1]
    last_commit = gitcontext.commits[-1]
    # Apply an additional config that is specified in the last commit message
    config_builder.set_config_from_commit(last_commit)
    lint_config = config_builder.build(lint_config)

    # Let's get linting!
    linter = GitLinter(lint_config)
    violations = linter.lint(last_commit)
    linter.print_violations(violations)
    exit_code = min(MAX_VIOLATION_ERROR_CODE, len(violations))
    ctx.exit(exit_code)
Beispiel #3
0
    def test_gitcontext_ignore_all(self):
        config = LintConfig()
        original_rules = config.rules

        # nothing gitlint
        context = GitContext()
        context.set_commit_msg("test\ngitlint\nfoo")
        config.apply_config_from_gitcontext(context)
        self.assertListEqual(config.rules, original_rules)

        # ignore all rules
        context = GitContext()
        context.set_commit_msg("test\ngitlint-ignore: all\nfoo")
        config.apply_config_from_gitcontext(context)
        self.assertEqual(config.rules, [])

        # ignore all rules, no space
        config = LintConfig()
        context.set_commit_msg("test\ngitlint-ignore:all\nfoo")
        config.apply_config_from_gitcontext(context)
        self.assertEqual(config.rules, [])

        # ignore all rules, more spacing
        config = LintConfig()
        context.set_commit_msg("test\ngitlint-ignore: \t all\nfoo")
        config.apply_config_from_gitcontext(context)
        self.assertEqual(config.rules, [])
Beispiel #4
0
def cli(config, c, ignore, verbose, silent):
    """ Git lint tool, checks your git commit messages for styling issues """

    try:
        # Config precedence:
        # First, load default config or config from configfile
        lint_config = get_lint_config(config)
        # Then process any commandline configuration flags
        try:
            lint_config.apply_config_options(c)
        except LintConfigError as e:
            click.echo("Config Error: {}".format(e.message))
            exit(CONFIG_ERROR_CODE)

        # Finally, overwrite with any convenience commandline flags
        lint_config.apply_on_csv_string(ignore, lint_config.disable_rule)
        if silent:
            lint_config.verbosity = 0
        elif verbose > 0:
            lint_config.verbosity = verbose
    except LintConfigError as e:
        click.echo("Config Error: {0}".format(e.message))
        exit(CONFIG_ERROR_CODE)  # return 10000 on config error

    if sys.stdin.isatty():
        gitcontext = GitContext.from_environment()
    else:
        gitcontext = GitContext()
        gitcontext.set_commit_msg(sys.stdin.read())

    linter = GitLinter(lint_config)
    violations = linter.lint(gitcontext)
    linter.print_violations(violations)
    exit(len(violations))
Beispiel #5
0
    def test_lint_sample1(self):
        linter = GitLinter(LintConfig())
        gitcontext = GitContext()
        gitcontext.set_commit_msg(self.get_sample("commit_message/sample1"))
        violations = linter.lint(gitcontext)
        expected_errors = [
            RuleViolation(
                "T3",
                "Title has trailing punctuation (.)",
                "Commit title containing 'WIP', as well as trailing punctuation.",
                1,
            ),
            RuleViolation(
                "T5",
                "Title contains the word 'WIP' (case-insensitive)",
                "Commit title containing 'WIP', as well as trailing punctuation.",
                1,
            ),
            RuleViolation("B4", "Second line is not empty", "This line should be empty", 2),
            RuleViolation(
                "B1",
                "Line exceeds max length (135>80)",
                "This is the first line of the commit message body and it is meant to test "
                + "a line that exceeds the maximum line length of 80 characters.",
                3,
            ),
            RuleViolation("B2", "Line has trailing whitespace", "This line has a trailing space. ", 4),
            RuleViolation("B2", "Line has trailing whitespace", "This line has a trailing tab.\t", 5),
            RuleViolation("B3", "Line contains hard tab characters (\\t)", "This line has a trailing tab.\t", 5),
        ]

        self.assertListEqual(violations, expected_errors)
Beispiel #6
0
    def test_set_commit_msg_just_title(self):
        gitcontext = GitContext()
        gitcontext.set_commit_msg(self.get_sample("commit_message/sample2"))

        self.assertEqual(gitcontext.commit_msg.title, "Just a title containing WIP")
        self.assertEqual(gitcontext.commit_msg.body, [])
        self.assertEqual(gitcontext.commit_msg.full, "Just a title containing WIP")
        self.assertEqual(gitcontext.commit_msg.original, "Just a title containing WIP")
Beispiel #7
0
 def test_gitcontext_ignore_specific(self):
     # ignore specific rules
     config = LintConfig()
     context = GitContext()
     context.set_commit_msg("test\ngitlint-ignore: T1, body-hard-tab")
     config.apply_config_from_gitcontext(context)
     expected_rules = [rule for rule in config.rules if rule.id not in ["T1", "body-hard-tab"]]
     self.assertEqual(config.rules, expected_rules)
Beispiel #8
0
    def test_get_latest_commit_git_error(self, sh):
        err = b"fatal: Not a git repository (or any of the parent directories): .git"
        sh.git.log.side_effect = ErrorReturnCode("git log -1 --pretty=%B", b"", err)

        with self.assertRaisesRegexp(GitContextError, "fake/path is not a git repository."):
            GitContext.from_local_repository("fake/path")

        # assert that commit message was read using git command
        sh.git.log.assert_called_once_with('-1', '--pretty=%B', _tty_out=False, _cwd="fake/path")
Beispiel #9
0
    def test_get_latest_commit_command_not_found(self, sh):
        sh.git.log.side_effect = CommandNotFound("git")
        expected_msg = "'git' command not found. You need to install git to use gitlint on a local repository. " + \
                       "See https://git-scm.com/book/en/v2/Getting-Started-Installing-Git on how to install git."
        with self.assertRaisesRegexp(GitContextError, expected_msg):
            GitContext.from_local_repository("fake/path")

        # assert that commit message was read using git command
        sh.git.log.assert_called_once_with('-1', '--pretty=%B', _tty_out=False, _cwd="fake/path")
Beispiel #10
0
    def test_lint_sample2(self):
        linter = GitLinter(LintConfig())
        gitcontext = GitContext()
        gitcontext.set_commit_msg(self.get_sample("commit_message/sample2"))
        violations = linter.lint(gitcontext)
        expected = [RuleViolation("T5", "Title contains the word 'WIP' (case-insensitive)",
                                  "Just a title containing WIP", 1),
                    RuleViolation("B6", "Body message is missing", None, 3)]

        self.assertListEqual(violations, expected)
Beispiel #11
0
 def gitcontext(commit_msg_str, changed_files=None):
     """ Utility method to easily create gitcontext objects based on a given commit msg string and set of
     changed files"""
     gitcontext = GitContext()
     gitcontext.set_commit_msg(commit_msg_str)
     if changed_files:
         gitcontext.changed_files = changed_files
     else:
         gitcontext.changed_files = []
     return gitcontext
Beispiel #12
0
 def test_lint_sample4(self):
     gitcontext = GitContext()
     gitcontext.set_commit_msg(self.get_sample("commit_message/sample4"))
     lintconfig = LintConfig()
     lintconfig.apply_config_from_gitcontext(gitcontext)
     linter = GitLinter(lintconfig)
     violations = linter.lint(gitcontext)
     # expect no violations because sample4 has a 'gitlint: disable line'
     expected = []
     self.assertListEqual(violations, expected)
Beispiel #13
0
    def test_get_latest_commit(self, sh):
        def git_log_side_effect(*args, **kwargs):
            return_values = {'--pretty=%B': "commit-title\n\ncommit-body", '--pretty=%aN': "test author",
                             '--pretty=%aE': "*****@*****.**", '--pretty=%aD': "Mon Feb 29 22:19:39 2016 +0100"}
            return return_values[args[1]]

        sh.git.log.side_effect = git_log_side_effect
        sh.git.return_value = "file1.txt\npath/to/file2.txt\n"

        context = GitContext.from_local_repository("fake/path")
        expected_sh_special_args = {
            '_tty_out': False,
            '_cwd': "fake/path"
        }
        # assert that commit info was read using git command
        expected_calls = [call('-1', '--pretty=%B', _cwd='fake/path', _tty_out=False),
                          call('-1', '--pretty=%aN', _cwd='fake/path', _tty_out=False),
                          call('-1', '--pretty=%aE', _cwd='fake/path', _tty_out=False),
                          call('-1', '--pretty=%aD', _cwd='fake/path', _tty_out=False)]

        self.assertListEqual(sh.git.log.mock_calls, expected_calls)

        last_commit = context.commits[-1]
        self.assertEqual(last_commit.message.title, "commit-title")
        self.assertEqual(last_commit.message.body, ["", "commit-body"])
        self.assertEqual(last_commit.author_name, "test author")
        self.assertEqual(last_commit.author_email, "*****@*****.**")

        # assert that changed files are read using git command
        sh.git.assert_called_once_with('diff-tree', '--no-commit-id', '--name-only', '-r', 'HEAD',
                                       **expected_sh_special_args)
        self.assertListEqual(last_commit.changed_files, ["file1.txt", "path/to/file2.txt"])
Beispiel #14
0
 def gitcontext(commit_msg_str, changed_files=None):
     """ Utility method to easily create gitcontext objects based on a given commit msg string and set of
     changed files"""
     gitcontext = GitContext.from_commit_msg(commit_msg_str)
     commit = gitcontext.commits[-1]
     if changed_files:
         commit.changed_files = changed_files
     return gitcontext
Beispiel #15
0
    def test_set_commit_msg_full(self):
        gitcontext = GitContext()
        gitcontext.set_commit_msg(self.get_sample("commit_message/sample1"))

        expected_title = "Commit title containing 'WIP', as well as trailing punctuation."
        expected_body = ["This line should be empty",
                         "This is the first line of the commit message body and it is meant to test a " +
                         "line that exceeds the maximum line length of 80 characters.",
                         "This line has a trailing space. ",
                         "This line has a trailing tab.\t", ""]
        expected_full = expected_title + "\n" + "\n".join(expected_body)
        expected_original = expected_full + "# This is a commented  line\n"

        self.assertEqual(gitcontext.commit_msg.title, expected_title)
        self.assertEqual(gitcontext.commit_msg.body, expected_body)
        self.assertEqual(gitcontext.commit_msg.full, expected_full)
        self.assertEqual(gitcontext.commit_msg.original, expected_original)
Beispiel #16
0
    def test_from_commit_msg_empty(self):
        gitcontext = GitContext.from_commit_msg("")

        self.assertEqual(gitcontext.commits[-1].message.title, "")
        self.assertEqual(gitcontext.commits[-1].message.body, [])
        self.assertEqual(gitcontext.commits[-1].message.full, "")
        self.assertEqual(gitcontext.commits[-1].message.original, "")
        self.assertEqual(gitcontext.commits[-1].author_name, None)
        self.assertEqual(gitcontext.commits[-1].author_email, None)
        self.assertEqual(len(gitcontext.commits), 1)
Beispiel #17
0
    def test_from_commit_msg_comment(self):
        gitcontext = GitContext.from_commit_msg("Title\n\nBody 1\n#Comment\nBody 2")

        self.assertEqual(gitcontext.commits[-1].message.title, "Title")
        self.assertEqual(gitcontext.commits[-1].message.body, ["", "Body 1", "Body 2"])
        self.assertEqual(gitcontext.commits[-1].message.full, "Title\n\nBody 1\nBody 2")
        self.assertEqual(gitcontext.commits[-1].message.original, "Title\n\nBody 1\n#Comment\nBody 2")
        self.assertEqual(gitcontext.commits[-1].author_name, None)
        self.assertEqual(gitcontext.commits[-1].author_email, None)
        self.assertEqual(len(gitcontext.commits), 1)
Beispiel #18
0
    def test_set_commit_msg_just_title(self):
        gitcontext = GitContext.from_commit_msg(self.get_sample("commit_message/sample2"))

        self.assertEqual(gitcontext.commits[-1].message.title, "Just a title containing WIP")
        self.assertEqual(gitcontext.commits[-1].message.body, [])
        self.assertEqual(gitcontext.commits[-1].message.full, "Just a title containing WIP")
        self.assertEqual(gitcontext.commits[-1].message.original, "Just a title containing WIP")
        self.assertEqual(gitcontext.commits[-1].author_name, None)
        self.assertEqual(gitcontext.commits[-1].author_email, None)
        self.assertEqual(len(gitcontext.commits), 1)
Beispiel #19
0
 def test_lint_sample5(self):
     gitcontext = GitContext()
     gitcontext.set_commit_msg(self.get_sample("commit_message/sample5"))
     lintconfig = LintConfig()
     lintconfig.apply_config_from_gitcontext(gitcontext)
     linter = GitLinter(lintconfig)
     violations = linter.lint(gitcontext)
     title = " Commit title containing 'WIP', \tleading and trailing whitespace and longer than 72 characters."
     # expect only certain violations because sample5 has a 'gitlint: T3,'
     expected = [RuleViolation("T1", "Title exceeds max length (95>72)", title, 1),
                 RuleViolation("T4", "Title contains hard tab characters (\\t)", title, 1),
                 RuleViolation("T5", "Title contains the word 'WIP' (case-insensitive)", title, 1),
                 RuleViolation("B4", "Second line is not empty", "This line should be empty", 2),
                 RuleViolation("B2", "Line has trailing whitespace",
                               "This line has a trailing space. ", 4),
                 RuleViolation("B2", "Line has trailing whitespace", "This line has a trailing tab.\t",
                               5),
                 RuleViolation("B3", "Line contains hard tab characters (\\t)",
                               "This line has a trailing tab.\t", 5),
                 ]
     self.assertListEqual(violations, expected)
Beispiel #20
0
    def test_get_latest_commit_git_error(self, sh):
        # Current directory not a git repo
        err = b"fatal: Not a git repository (or any of the parent directories): .git"
        sh.git.log.side_effect = ErrorReturnCode("git log -1 --pretty=%B", b"", err)

        with self.assertRaisesRegex(GitContextError, "fake/path is not a git repository."):
            GitContext.from_local_repository("fake/path")

        # assert that commit message was read using git command
        sh.git.log.assert_called_once_with('-1', '--pretty=%B', _tty_out=False, _cwd="fake/path")

        sh.git.log.reset_mock()
        err = b"fatal: Random git error"
        sh.git.log.side_effect = ErrorReturnCode("git log -1 --pretty=%B", b"", err)

        expected_msg = "An error occurred while executing 'git log -1 --pretty=%B': {0}".format(err)
        with self.assertRaisesRegex(GitContextError, expected_msg):
            GitContext.from_local_repository("fake/path")

        # assert that commit message was read using git command
        sh.git.log.assert_called_once_with('-1', '--pretty=%B', _tty_out=False, _cwd="fake/path")
    def test_from_commit_msg_merge_commit(self):
        commit_msg = "Merge f919b8f34898d9b48048bcd703bc47139f4ff621 into 8b0409a26da6ba8a47c1fd2e746872a8dab15401"
        gitcontext = GitContext.from_commit_msg(commit_msg)

        self.assertEqual(gitcontext.commits[-1].message.title, commit_msg)
        self.assertEqual(gitcontext.commits[-1].message.body, [])
        self.assertEqual(gitcontext.commits[-1].message.full, commit_msg)
        self.assertEqual(gitcontext.commits[-1].message.original, commit_msg)
        self.assertEqual(gitcontext.commits[-1].author_name, None)
        self.assertEqual(gitcontext.commits[-1].author_email, None)
        self.assertListEqual(gitcontext.commits[-1].parents, [])
        self.assertTrue(gitcontext.commits[-1].is_merge_commit)
        self.assertEqual(len(gitcontext.commits), 1)
Beispiel #22
0
def lint(ctx):
    """ Lints a git repository [default command] """
    lint_config = ctx.obj
    try:
        if sys.stdin.isatty():
            gitcontext = GitContext.from_local_repository(lint_config.target)
        else:
            gitcontext = GitContext.from_commit_msg(sys.stdin.read())
    except GitContextError as e:
        click.echo(str(e))
        ctx.exit(GIT_CONTEXT_ERROR_CODE)

    last_commit = gitcontext.commits[-1]
    # Apply an additional config that is specified in the last commit message
    lint_config.apply_config_from_commit(last_commit)

    # Let's get linting!
    linter = GitLinter(lint_config)
    violations = linter.lint(last_commit, gitcontext)
    linter.print_violations(violations)
    exit_code = min(MAX_VIOLATION_ERROR_CODE, len(violations))
    ctx.exit(exit_code)
Beispiel #23
0
    def test_from_commit_msg_comment(self):
        gitcontext = GitContext.from_commit_msg(
            "Title\n\nBody 1\n#Comment\nBody 2")

        self.assertEqual(gitcontext.commits[-1].message.title, "Title")
        self.assertEqual(gitcontext.commits[-1].message.body,
                         ["", "Body 1", "Body 2"])
        self.assertEqual(gitcontext.commits[-1].message.full,
                         "Title\n\nBody 1\nBody 2")
        self.assertEqual(gitcontext.commits[-1].message.original,
                         "Title\n\nBody 1\n#Comment\nBody 2")
        self.assertEqual(gitcontext.commits[-1].author_name, None)
        self.assertEqual(gitcontext.commits[-1].author_email, None)
        self.assertListEqual(gitcontext.commits[-1].parents, [])
        self.assertFalse(gitcontext.commits[-1].is_merge_commit)
        self.assertEqual(len(gitcontext.commits), 1)
Beispiel #24
0
    def test_from_commit_msg_just_title(self):
        gitcontext = GitContext.from_commit_msg(
            self.get_sample("commit_message/sample2"))

        self.assertEqual(gitcontext.commits[-1].message.title,
                         "Just a title containing WIP")
        self.assertEqual(gitcontext.commits[-1].message.body, [])
        self.assertEqual(gitcontext.commits[-1].message.full,
                         "Just a title containing WIP")
        self.assertEqual(gitcontext.commits[-1].message.original,
                         "Just a title containing WIP")
        self.assertEqual(gitcontext.commits[-1].author_name, None)
        self.assertEqual(gitcontext.commits[-1].author_email, None)
        self.assertListEqual(gitcontext.commits[-1].parents, [])
        self.assertFalse(gitcontext.commits[-1].is_merge_commit)
        self.assertEqual(len(gitcontext.commits), 1)
Beispiel #25
0
    def test_from_commit_msg_comment(self):
        gitcontext = GitContext.from_commit_msg(
            u"Tïtle\n\nBödy 1\n#Cömment\nBody 2")
        commit = gitcontext.commits[-1]

        self.assertEqual(commit.message.title, u"Tïtle")
        self.assertEqual(commit.message.body, ["", u"Bödy 1", "Body 2"])
        self.assertEqual(commit.message.full, u"Tïtle\n\nBödy 1\nBody 2")
        self.assertEqual(commit.message.original,
                         u"Tïtle\n\nBödy 1\n#Cömment\nBody 2")
        self.assertEqual(commit.author_name, None)
        self.assertEqual(commit.author_email, None)
        self.assertEqual(commit.date, None)
        self.assertListEqual(commit.parents, [])
        self.assertFalse(commit.is_merge_commit)
        self.assertEqual(len(gitcontext.commits), 1)
Beispiel #26
0
    def test_from_commit_msg_empty(self):
        gitcontext = GitContext.from_commit_msg("")
        commit = gitcontext.commits[-1]

        self.assertEqual(commit.message.title, "")
        self.assertEqual(commit.message.body, [])
        self.assertEqual(commit.message.full, "")
        self.assertEqual(commit.message.original, "")
        self.assertEqual(commit.author_name, None)
        self.assertEqual(commit.author_email, None)
        self.assertEqual(commit.date, None)
        self.assertListEqual(commit.parents, [])
        self.assertFalse(commit.is_merge_commit)
        self.assertFalse(commit.is_fixup_commit)
        self.assertFalse(commit.is_squash_commit)
        self.assertEqual(len(gitcontext.commits), 1)
Beispiel #27
0
    def test_get_latest_commit_merge_commit(self, sh):
        sample_sha = "d8ac47e9f2923c7f22d8668e3a1ed04eb4cdbca9"

        def git_log_side_effect(*_args, **_kwargs):
            return (
                u"test åuthor,test-emå[email protected],2016-12-03 15:28:15 01:00,åbc def\n"
                u"Merge \"foo bår commit\"")

        sh.git.side_effect = [sample_sha, u"file1.txt\npåth/to/file2.txt\n"]
        sh.git.log.side_effect = git_log_side_effect

        context = GitContext.from_local_repository(u"fåke/path")
        expected_sh_special_args = {'_tty_out': False, '_cwd': u"fåke/path"}
        # assert that commit info was read using git command
        expected_calls = [
            call("rev-list", "--max-count=1", "HEAD",
                 **expected_sh_special_args),
            call.log(sample_sha,
                     "-1",
                     "--pretty=%aN,%aE,%ai,%P%n%B",
                     _cwd=u"fåke/path",
                     _tty_out=False),
            call('diff-tree', '--no-commit-id', '--name-only', '-r',
                 sample_sha, **expected_sh_special_args)
        ]

        self.assertEqual(sh.git.mock_calls, expected_calls)

        last_commit = context.commits[-1]
        self.assertEqual(last_commit.message.title,
                         u"Merge \"foo bår commit\"")
        self.assertEqual(last_commit.message.body, [])
        self.assertEqual(last_commit.author_name, u"test åuthor")
        self.assertEqual(last_commit.author_email, u"test-emå[email protected]")
        self.assertEqual(
            last_commit.date,
            datetime.datetime(2016,
                              12,
                              3,
                              15,
                              28,
                              15,
                              tzinfo=dateutil.tz.tzoffset("+0100", 3600)))
        self.assertListEqual(last_commit.parents, [u"åbc", "def"])
        self.assertTrue(last_commit.is_merge_commit)
        self.assertListEqual(last_commit.changed_files,
                             ["file1.txt", u"påth/to/file2.txt"])
Beispiel #28
0
    def test_from_commit_msg_merge_commit(self):
        commit_msg = "Merge f919b8f34898d9b48048bcd703bc47139f4ff621 into 8b0409a26da6ba8a47c1fd2e746872a8dab15401"
        gitcontext = GitContext.from_commit_msg(commit_msg)
        commit = gitcontext.commits[-1]

        self.assertEqual(commit.message.title, commit_msg)
        self.assertEqual(commit.message.body, [])
        self.assertEqual(commit.message.full, commit_msg)
        self.assertEqual(commit.message.original, commit_msg)
        self.assertEqual(commit.author_name, None)
        self.assertEqual(commit.author_email, None)
        self.assertEqual(commit.date, None)
        self.assertListEqual(commit.parents, [])
        self.assertTrue(commit.is_merge_commit)
        self.assertFalse(commit.is_fixup_commit)
        self.assertFalse(commit.is_squash_commit)
        self.assertEqual(len(gitcontext.commits), 1)
Beispiel #29
0
    def test_get_latest_commit(self, sh):
        sh.git.log.return_value = "commit-title\n\ncommit-body"
        sh.git.return_value = "file1.txt\npath/to/file2.txt\n"

        context = GitContext.from_local_repository("fake/path")
        expected_sh_special_args = {
            '_tty_out': False,
            '_cwd': "fake/path"
        }
        # assert that commit message was read using git command
        sh.git.log.assert_called_once_with('-1', '--pretty=%B', **expected_sh_special_args)
        self.assertEqual(context.commit_msg.title, "commit-title")
        self.assertEqual(context.commit_msg.body, ["", "commit-body"])

        # assert that changed files are read using git command
        sh.git.assert_called_once_with('diff-tree', '--no-commit-id', '--name-only', '-r', 'HEAD',
                                       **expected_sh_special_args)
        self.assertListEqual(context.changed_files, ["file1.txt", "path/to/file2.txt"])
Beispiel #30
0
    def test_from_commit_msg_just_title(self):
        gitcontext = GitContext.from_commit_msg(
            self.get_sample("commit_message/sample2"))
        commit = gitcontext.commits[-1]

        self.assertEqual(commit.message.title, u"Just a title contåining WIP")
        self.assertEqual(commit.message.body, [])
        self.assertEqual(commit.message.full, u"Just a title contåining WIP")
        self.assertEqual(commit.message.original,
                         u"Just a title contåining WIP")
        self.assertEqual(commit.author_name, None)
        self.assertEqual(commit.author_email, None)
        self.assertListEqual(commit.parents, [])
        self.assertFalse(commit.is_merge_commit)
        self.assertFalse(commit.is_fixup_commit)
        self.assertFalse(commit.is_squash_commit)
        self.assertFalse(commit.is_revert_commit)
        self.assertEqual(len(gitcontext.commits), 1)
Beispiel #31
0
    def test_get_latest_commit_merge_commit(self, sh):
        sample_sha = "d8ac47e9f2923c7f22d8668e3a1ed04eb4cdbca9"

        sh.git.side_effect = self.GIT_CONFIG_SIDE_EFFECTS + [
            sample_sha,
            u"test åuthor\x00test-emå[email protected]\x002016-12-03 15:28:15 01:00\x00åbc def\n"
            u"Merge \"foo bår commit\"", u"file1.txt\npåth/to/file2.txt\n"
        ]

        context = GitContext.from_local_repository(u"fåke/path")
        # assert that commit info was read using git command
        expected_calls = self.expected_git_config_calls + [
            call("log", "-1", "--pretty=%H", **self.expected_sh_special_args),
            call("log", sample_sha, "-1",
                 "--pretty=%aN%x00%aE%x00%ai%x00%P%n%B", **
                 self.expected_sh_special_args),
            call('diff-tree', '--no-commit-id', '--name-only', '-r',
                 sample_sha, **self.expected_sh_special_args)
        ]

        self.assertEqual(sh.git.mock_calls, expected_calls)

        last_commit = context.commits[-1]
        self.assertEqual(last_commit.message.title,
                         u"Merge \"foo bår commit\"")
        self.assertEqual(last_commit.message.body, [])
        self.assertEqual(last_commit.author_name, u"test åuthor")
        self.assertEqual(last_commit.author_email, u"test-emå[email protected]")
        self.assertEqual(
            last_commit.date,
            datetime.datetime(2016,
                              12,
                              3,
                              15,
                              28,
                              15,
                              tzinfo=dateutil.tz.tzoffset("+0100", 3600)))
        self.assertListEqual(last_commit.parents, [u"åbc", "def"])
        self.assertTrue(last_commit.is_merge_commit)
        self.assertFalse(last_commit.is_fixup_commit)
        self.assertFalse(last_commit.is_squash_commit)
        self.assertFalse(last_commit.is_revert_commit)
        self.assertListEqual(last_commit.changed_files,
                             ["file1.txt", u"påth/to/file2.txt"])
Beispiel #32
0
    def test_from_commit_msg_full(self, commentchar):
        commentchar.return_value = u"#"
        gitcontext = GitContext.from_commit_msg(
            self.get_sample("commit_message/sample1"))

        expected_title = u"Commit title contåining 'WIP', as well as trailing punctuation."
        expected_body = [
            "This line should be empty",
            "This is the first line of the commit message body and it is meant to test a "
            + "line that exceeds the maximum line length of 80 characters.",
            u"This line has a tråiling space. ",
            "This line has a trailing tab.\t"
        ]
        expected_full = expected_title + "\n" + "\n".join(expected_body)
        expected_original = expected_full + (
            u"\n# This is a cömmented  line\n"
            u"# ------------------------ >8 ------------------------\n"
            u"# Anything after this line should be cleaned up\n"
            u"# this line appears on `git commit -v` command\n"
            u"diff --git a/gitlint/tests/samples/commit_message/sample1 "
            u"b/gitlint/tests/samples/commit_message/sample1\n"
            u"index 82dbe7f..ae71a14 100644\n"
            u"--- a/gitlint/tests/samples/commit_message/sample1\n"
            u"+++ b/gitlint/tests/samples/commit_message/sample1\n"
            u"@@ -1 +1 @@\n")

        commit = gitcontext.commits[-1]
        self.assertIsInstance(commit, GitCommit)
        self.assertFalse(isinstance(commit, LocalGitCommit))
        self.assertEqual(commit.message.title, expected_title)
        self.assertEqual(commit.message.body, expected_body)
        self.assertEqual(commit.message.full, expected_full)
        self.assertEqual(commit.message.original, expected_original)
        self.assertEqual(commit.author_name, None)
        self.assertEqual(commit.author_email, None)
        self.assertEqual(commit.date, None)
        self.assertListEqual(commit.parents, [])
        self.assertListEqual(commit.branches, [])
        self.assertFalse(commit.is_merge_commit)
        self.assertFalse(commit.is_fixup_commit)
        self.assertFalse(commit.is_squash_commit)
        self.assertFalse(commit.is_revert_commit)
        self.assertEqual(len(gitcontext.commits), 1)
Beispiel #33
0
    def test_from_local_repository_specific_ref(self, sh):
        sample_sha = "myspecialref"

        sh.git.side_effect = [
            sample_sha,
            u"test åuthor\x00test-emå[email protected]\x002016-12-03 15:28:15 01:00\x00åbc\n"
            u"cömmit-title\n\ncömmit-body", u"file1.txt\npåth/to/file2.txt\n"
        ]

        context = GitContext.from_local_repository(u"fåke/path", sample_sha)
        # assert that commit info was read using git command
        expected_calls = [
            call("rev-list", sample_sha, **self.expected_sh_special_args),
            call("log", sample_sha, "-1",
                 "--pretty=%aN%x00%aE%x00%ai%x00%P%n%B",
                 **self.expected_sh_special_args),
            call('diff-tree', '--no-commit-id', '--name-only', '-r',
                 sample_sha, **self.expected_sh_special_args)
        ]
        self.assertListEqual(sh.git.mock_calls, expected_calls)

        last_commit = context.commits[-1]
        self.assertEqual(last_commit.message.title, u"cömmit-title")
        self.assertEqual(last_commit.message.body, ["", u"cömmit-body"])
        self.assertEqual(last_commit.author_name, u"test åuthor")
        self.assertEqual(last_commit.author_email, u"test-emå[email protected]")
        self.assertEqual(
            last_commit.date,
            datetime.datetime(2016,
                              12,
                              3,
                              15,
                              28,
                              15,
                              tzinfo=dateutil.tz.tzoffset("+0100", 3600)))
        self.assertListEqual(last_commit.parents, [u"åbc"])
        self.assertFalse(last_commit.is_merge_commit)
        self.assertFalse(last_commit.is_fixup_commit)
        self.assertFalse(last_commit.is_squash_commit)
        self.assertListEqual(last_commit.changed_files,
                             ["file1.txt", u"påth/to/file2.txt"])
Beispiel #34
0
    def test_get_latest_commit(self, sh):
        def git_log_side_effect(*args, **_kwargs):
            return_values = {
                '--pretty=%B': "commit-title\n\ncommit-body",
                '--pretty=%aN': "test author",
                '--pretty=%aE': "*****@*****.**",
                '--pretty=%aD': "Mon Feb 29 22:19:39 2016 +0100",
                '--pretty=%P': "abc"
            }
            return return_values[args[1]]

        sh.git.log.side_effect = git_log_side_effect
        sh.git.return_value = "file1.txt\npath/to/file2.txt\n"

        context = GitContext.from_local_repository("fake/path")
        expected_sh_special_args = {'_tty_out': False, '_cwd': "fake/path"}
        # assert that commit info was read using git command
        expected_calls = [
            call('-1', '--pretty=%B', _cwd='fake/path', _tty_out=False),
            call('-1', '--pretty=%aN', _cwd='fake/path', _tty_out=False),
            call('-1', '--pretty=%aE', _cwd='fake/path', _tty_out=False),
            call('-1', '--pretty=%aD', _cwd='fake/path', _tty_out=False),
            call('-1', '--pretty=%P', _cwd='fake/path', _tty_out=False)
        ]

        self.assertListEqual(sh.git.log.mock_calls, expected_calls)

        last_commit = context.commits[-1]
        self.assertEqual(last_commit.message.title, "commit-title")
        self.assertEqual(last_commit.message.body, ["", "commit-body"])
        self.assertEqual(last_commit.author_name, "test author")
        self.assertEqual(last_commit.author_email, "*****@*****.**")
        self.assertListEqual(last_commit.parents, ["abc"])
        self.assertFalse(last_commit.is_merge_commit)

        # assert that changed files are read using git command
        sh.git.assert_called_once_with('diff-tree', '--no-commit-id',
                                       '--name-only', '-r', 'HEAD',
                                       **expected_sh_special_args)
        self.assertListEqual(last_commit.changed_files,
                             ["file1.txt", "path/to/file2.txt"])
Beispiel #35
0
    def test_from_commit_msg_fixup_squash_commit(self):
        commit_types = ["fixup", "squash"]
        for commit_type in commit_types:
            commit_msg = "{0}! Test message".format(commit_type)
            gitcontext = GitContext.from_commit_msg(commit_msg)
            commit = gitcontext.commits[-1]

            self.assertEqual(commit.message.title, commit_msg)
            self.assertEqual(commit.message.body, [])
            self.assertEqual(commit.message.full, commit_msg)
            self.assertEqual(commit.message.original, commit_msg)
            self.assertEqual(commit.author_name, None)
            self.assertEqual(commit.author_email, None)
            self.assertEqual(commit.date, None)
            self.assertListEqual(commit.parents, [])
            self.assertEqual(len(gitcontext.commits), 1)
            self.assertFalse(commit.is_merge_commit)
            # Asserting that squash and fixup are correct
            for type in commit_types:
                attr = "is_" + type + "_commit"
                self.assertEqual(getattr(commit, attr), commit_type == type)
    def test_from_commit_msg_full(self):
        gitcontext = GitContext.from_commit_msg(self.get_sample("commit_message/sample1"))

        expected_title = "Commit title containing 'WIP', as well as trailing punctuation."
        expected_body = ["This line should be empty",
                         "This is the first line of the commit message body and it is meant to test a " +
                         "line that exceeds the maximum line length of 80 characters.",
                         "This line has a trailing space. ",
                         "This line has a trailing tab.\t", ""]
        expected_full = expected_title + "\n" + "\n".join(expected_body)
        expected_original = expected_full + "# This is a commented  line\n"

        self.assertEqual(gitcontext.commits[-1].message.title, expected_title)
        self.assertEqual(gitcontext.commits[-1].message.body, expected_body)
        self.assertEqual(gitcontext.commits[-1].message.full, expected_full)
        self.assertEqual(gitcontext.commits[-1].message.original, expected_original)
        self.assertEqual(gitcontext.commits[-1].author_name, None)
        self.assertEqual(gitcontext.commits[-1].author_email, None)
        self.assertListEqual(gitcontext.commits[-1].parents, [])
        self.assertFalse(gitcontext.commits[-1].is_merge_commit)
        self.assertEqual(len(gitcontext.commits), 1)
Beispiel #37
0
    def test_from_commit_msg_comment(self, commentchar):
        commentchar.return_value = "#"
        gitcontext = GitContext.from_commit_msg("Tïtle\n\nBödy 1\n#Cömment\nBody 2")
        commit = gitcontext.commits[-1]

        self.assertIsInstance(commit, GitCommit)
        self.assertFalse(isinstance(commit, LocalGitCommit))
        self.assertEqual(commit.message.title, "Tïtle")
        self.assertEqual(commit.message.body, ["", "Bödy 1", "Body 2"])
        self.assertEqual(commit.message.full, "Tïtle\n\nBödy 1\nBody 2")
        self.assertEqual(commit.message.original, "Tïtle\n\nBödy 1\n#Cömment\nBody 2")
        self.assertEqual(commit.author_name, None)
        self.assertEqual(commit.author_email, None)
        self.assertEqual(commit.date, None)
        self.assertListEqual(commit.parents, [])
        self.assertListEqual(commit.branches, [])
        self.assertFalse(commit.is_merge_commit)
        self.assertFalse(commit.is_fixup_commit)
        self.assertFalse(commit.is_squash_commit)
        self.assertFalse(commit.is_revert_commit)
        self.assertEqual(len(gitcontext.commits), 1)
Beispiel #38
0
    def test_from_commit_msg_revert_commit(self):
        commit_msg = "Revert \"Prev commit message\"\n\nThis reverts commit a8ad67e04164a537198dea94a4fde81c5592ae9c."
        gitcontext = GitContext.from_commit_msg(commit_msg)
        commit = gitcontext.commits[-1]

        self.assertIsInstance(commit, GitCommit)
        self.assertFalse(isinstance(commit, LocalGitCommit))
        self.assertEqual(commit.message.title, "Revert \"Prev commit message\"")
        self.assertEqual(commit.message.body, ["", "This reverts commit a8ad67e04164a537198dea94a4fde81c5592ae9c."])
        self.assertEqual(commit.message.full, commit_msg)
        self.assertEqual(commit.message.original, commit_msg)
        self.assertEqual(commit.author_name, None)
        self.assertEqual(commit.author_email, None)
        self.assertEqual(commit.date, None)
        self.assertListEqual(commit.parents, [])
        self.assertListEqual(commit.branches, [])
        self.assertFalse(commit.is_merge_commit)
        self.assertFalse(commit.is_fixup_commit)
        self.assertFalse(commit.is_squash_commit)
        self.assertTrue(commit.is_revert_commit)
        self.assertEqual(len(gitcontext.commits), 1)
Beispiel #39
0
    def test_gitcontext(self, sh):

        sh.git.side_effect = [
            "#",  # git config --get core.commentchar
            "\nfoöbar\n"
        ]

        expected_calls = [
            call("config", "--get", "core.commentchar", _ok_code=[0, 1], **self.expected_sh_special_args),
            call("rev-parse", "--abbrev-ref", "HEAD", **self.expected_sh_special_args)
        ]

        context = GitContext("fåke/path")
        self.assertEqual(sh.git.mock_calls, [])

        # gitcontext.comment_branch
        self.assertEqual(context.commentchar, "#")
        self.assertEqual(sh.git.mock_calls, expected_calls[0:1])

        # gitcontext.current_branch
        self.assertEqual(context.current_branch, "foöbar")
        self.assertEqual(sh.git.mock_calls, expected_calls)
Beispiel #40
0
    def test_get_latest_commit_merge_commit(self, sh):
        def git_log_side_effect(*args, **_kwargs):
            return_values = {'--pretty=%B': "Merge \"foo bar commit\"", '--pretty=%aN': "test author",
                             '--pretty=%aE': "*****@*****.**", '--pretty=%ai': "2016-12-03 15:28:15 01:00",
                             '--pretty=%P': "abc def"}
            return return_values[args[1]]

        sh.git.log.side_effect = git_log_side_effect
        sh.git.return_value = "file1.txt\npath/to/file2.txt\n"

        context = GitContext.from_local_repository("fake/path")
        expected_sh_special_args = {
            '_tty_out': False,
            '_cwd': "fake/path"
        }
        # assert that commit info was read using git command
        expected_calls = [call('-1', '--pretty=%B', _cwd='fake/path', _tty_out=False),
                          call('-1', '--pretty=%aN', _cwd='fake/path', _tty_out=False),
                          call('-1', '--pretty=%aE', _cwd='fake/path', _tty_out=False),
                          call('-1', '--pretty=%ai', _cwd='fake/path', _tty_out=False),
                          call('-1', '--pretty=%P', _cwd='fake/path', _tty_out=False)]

        self.assertListEqual(sh.git.log.mock_calls, expected_calls)

        last_commit = context.commits[-1]
        self.assertEqual(last_commit.message.title, "Merge \"foo bar commit\"")
        self.assertEqual(last_commit.message.body, [])
        self.assertEqual(last_commit.author_name, "test author")
        self.assertEqual(last_commit.author_email, "*****@*****.**")
        self.assertEqual(last_commit.date, datetime.datetime(2016, 12, 3, 15, 28, 15,
                                                             tzinfo=dateutil.tz.tzoffset("+0100", 3600)))
        self.assertListEqual(last_commit.parents, ["abc", "def"])
        self.assertTrue(last_commit.is_merge_commit)

        # assert that changed files are read using git command
        sh.git.assert_called_once_with('diff-tree', '--no-commit-id', '--name-only', '-r', 'HEAD',
                                       **expected_sh_special_args)
        self.assertListEqual(last_commit.changed_files, ["file1.txt", "path/to/file2.txt"])
Beispiel #41
0
    def test_get_latest_commit_fixup_squash_commit(self, sh):
        commit_types = ["fixup", "squash"]
        for commit_type in commit_types:
            sample_sha = "d8ac47e9f2923c7f22d8668e3a1ed04eb4cdbca9"

            sh.git.side_effect = [sample_sha,
                                  u"test åuthor\x00test-emå[email protected]\x002016-12-03 15:28:15 01:00\x00åbc\n"
                                  u"{0}! \"foo bår commit\"".format(commit_type),
                                  u"file1.txt\npåth/to/file2.txt\n"]

            context = GitContext.from_local_repository(u"fåke/path")
            # assert that commit info was read using git command
            expected_calls = [
                call("log", "-1", "--pretty=%H", **self.expected_sh_special_args),
                call("log", sample_sha, "-1", "--pretty=%aN%x00%aE%x00%ai%x00%P%n%B", **self.expected_sh_special_args),
                call('diff-tree', '--no-commit-id', '--name-only', '-r', sample_sha, **self.expected_sh_special_args)
            ]

            self.assertEqual(sh.git.mock_calls, expected_calls)

            last_commit = context.commits[-1]
            self.assertEqual(last_commit.message.title, u"{0}! \"foo bår commit\"".format(commit_type))
            self.assertEqual(last_commit.message.body, [])
            self.assertEqual(last_commit.author_name, u"test åuthor")
            self.assertEqual(last_commit.author_email, u"test-emå[email protected]")
            self.assertEqual(last_commit.date, datetime.datetime(2016, 12, 3, 15, 28, 15,
                                                                 tzinfo=dateutil.tz.tzoffset("+0100", 3600)))
            self.assertListEqual(last_commit.parents, [u"åbc"])

            # Asserting that squash and fixup are correct
            for type in commit_types:
                attr = "is_" + type + "_commit"
                self.assertEqual(getattr(last_commit, attr), commit_type == type)

            self.assertFalse(last_commit.is_merge_commit)
            self.assertListEqual(last_commit.changed_files, ["file1.txt", u"påth/to/file2.txt"])

            sh.git.reset_mock()
Beispiel #42
0
    def test_get_latest_commit(self, sh):
        sample_sha = "d8ac47e9f2923c7f22d8668e3a1ed04eb4cdbca9"

        sh.git.side_effect = [
            sample_sha,
            u"test åuthor,test-emå[email protected],2016-12-03 15:28:15 01:00,åbc\n"
            u"cömmit-title\n\ncömmit-body", u"file1.txt\npåth/to/file2.txt\n"
        ]

        context = GitContext.from_local_repository(u"fåke/path")
        # assert that commit info was read using git command
        expected_calls = [
            call("log", "-1", "--pretty=%H", **self.expected_sh_special_args),
            call("log", sample_sha, "-1", "--pretty=%aN,%aE,%ai,%P%n%B",
                 **self.expected_sh_special_args),
            call('diff-tree', '--no-commit-id', '--name-only', '-r',
                 sample_sha, **self.expected_sh_special_args)
        ]
        self.assertListEqual(sh.git.mock_calls, expected_calls)

        last_commit = context.commits[-1]
        self.assertEqual(last_commit.message.title, u"cömmit-title")
        self.assertEqual(last_commit.message.body, ["", u"cömmit-body"])
        self.assertEqual(last_commit.author_name, u"test åuthor")
        self.assertEqual(last_commit.author_email, u"test-emå[email protected]")
        self.assertEqual(
            last_commit.date,
            datetime.datetime(2016,
                              12,
                              3,
                              15,
                              28,
                              15,
                              tzinfo=dateutil.tz.tzoffset("+0100", 3600)))
        self.assertListEqual(last_commit.parents, [u"åbc"])
        self.assertFalse(last_commit.is_merge_commit)
        self.assertListEqual(last_commit.changed_files,
                             ["file1.txt", u"påth/to/file2.txt"])
Beispiel #43
0
    def test_gitcommit_equality(self, git):
        # git will be called to setup the context (commentchar and current_branch), just return the same value
        # This only matters to test gitcontext equality, not gitcommit equality
        git.return_value = "foöbar"

        # Test simple equality case
        now = datetime.datetime.utcnow()
        context1 = GitContext()
        commit_message1 = GitCommitMessage(context1, "tëst\n\nfoo", "tëst\n\nfoo", "tēst", ["", "föo"])
        commit1 = GitCommit(context1, commit_message1, "shä", now, "Jöhn Smith", "jö[email protected]", None,
                            ["föo/bar"], ["brånch1", "brånch2"])
        context1.commits = [commit1]

        context2 = GitContext()
        commit_message2 = GitCommitMessage(context2, "tëst\n\nfoo", "tëst\n\nfoo", "tēst", ["", "föo"])
        commit2 = GitCommit(context2, commit_message1, "shä", now, "Jöhn Smith", "jö[email protected]", None,
                            ["föo/bar"], ["brånch1", "brånch2"])
        context2.commits = [commit2]

        self.assertEqual(context1, context2)
        self.assertEqual(commit_message1, commit_message2)
        self.assertEqual(commit1, commit2)

        # Check that objects are unequal when changing a single attribute
        kwargs = {'message': commit1.message, 'sha': commit1.sha, 'date': commit1.date,
                  'author_name': commit1.author_name, 'author_email': commit1.author_email, 'parents': commit1.parents,
                  'changed_files': commit1.changed_files, 'branches': commit1.branches}

        self.object_equality_test(commit1, kwargs.keys(), {"context": commit1.context})

        # Check that the is_* attributes that are affected by the commit message affect equality
        special_messages = {'is_merge_commit': "Merge: foöbar", 'is_fixup_commit': "fixup! foöbar",
                            'is_squash_commit': "squash! foöbar", 'is_revert_commit': "Revert: foöbar"}
        for key in special_messages:
            kwargs_copy = copy.deepcopy(kwargs)
            clone1 = GitCommit(context=commit1.context, **kwargs_copy)
            clone1.message = GitCommitMessage.from_full_message(context1, special_messages[key])
            self.assertTrue(getattr(clone1, key))

            clone2 = GitCommit(context=commit1.context, **kwargs_copy)
            clone2.message = GitCommitMessage.from_full_message(context1, "foöbar")
            self.assertNotEqual(clone1, clone2)
Beispiel #44
0
    def test_gitcontext_equality(self, sh):

        sh.git.side_effect = [
            u"û\n",  # context1: git config --get core.commentchar
            u"û\n",  # context2: git config --get core.commentchar
            u"my-brånch\n",  # context1: git rev-parse --abbrev-ref HEAD
            u"my-brånch\n",  # context2: git rev-parse --abbrev-ref HEAD
        ]

        context1 = GitContext(u"fåke/path")
        context1.commits = [
            u"fōo", u"bår"
        ]  # we don't need real commits to check for equality

        context2 = GitContext(u"fåke/path")
        context2.commits = [u"fōo", u"bår"]
        self.assertEqual(context1, context2)

        # INEQUALITY
        # Different commits
        context2.commits = [u"hür", u"dür"]
        self.assertNotEqual(context1, context2)

        # Different repository_path
        context2.commits = context1.commits
        context2.repository_path = u"ōther/path"
        self.assertNotEqual(context1, context2)

        # Different comment_char
        context3 = GitContext(u"fåke/path")
        context3.commits = [u"fōo", u"bår"]
        sh.git.side_effect = ([
            u"ç\n",  # context3: git config --get core.commentchar
            u"my-brånch\n"  # context3: git rev-parse --abbrev-ref HEAD
        ])
        self.assertNotEqual(context1, context3)

        # Different current_branch
        context4 = GitContext(u"fåke/path")
        context4.commits = [u"fōo", u"bår"]
        sh.git.side_effect = ([
            u"û\n",  # context4: git config --get core.commentchar
            u"different-brånch\n"  # context4: git rev-parse --abbrev-ref HEAD
        ])
        self.assertNotEqual(context1, context4)
Beispiel #45
0
def lint(ctx):
    """ Lints a git repository [default command] """
    lint_config = ctx.obj[0]
    msg_filename = ctx.obj[3]

    # Let's determine where our input data is coming from:
    # Order of precedence:
    # 1. Any data specified via --msg-filename
    # 2. Any data sent to stdin
    # 3. Fallback to reading from local repository
    stdin_input = get_stdin_data()
    if msg_filename:
        LOG.debug("Attempting to read from --msg-filename.")
        gitcontext = GitContext.from_commit_msg(ustr(msg_filename.read()))
    elif stdin_input:
        LOG.debug("No --msg-filename flag. Attempting to read from stdin.")
        gitcontext = GitContext.from_commit_msg(stdin_input)
    else:
        LOG.debug(
            "No --msg-filename flag, no or empty data passed to stdin. Attempting to read from the local repo."
        )
        gitcontext = GitContext.from_local_repository(lint_config.target,
                                                      ctx.obj[2])

    number_of_commits = len(gitcontext.commits)
    # Exit if we don't have commits in the specified range. Use a 0 exit code, since a popular use-case is one
    # where users are using --commits in a check job to check the commit messages inside a CI job. By returning 0, we
    # ensure that these jobs don't fail if for whatever reason the specified commit range is empty.
    if number_of_commits == 0:
        LOG.debug(u'No commits in range "%s"', ctx.obj[2])
        ctx.exit(0)

    general_config_builder = ctx.obj[1]
    last_commit = gitcontext.commits[-1]

    # Let's get linting!
    first_violation = True
    exit_code = 0
    for commit in gitcontext.commits:
        # Build a config_builder taking into account the commit specific config (if any)
        config_builder = general_config_builder.clone()
        config_builder.set_config_from_commit(commit)

        # Create a deepcopy from the original config, so we have a unique config object per commit
        # This is important for configuration rules to be able to modifying the config on a per commit basis
        commit_config = config_builder.build(copy.deepcopy(lint_config))

        # Actually do the linting
        linter = GitLinter(commit_config)
        violations = linter.lint(commit)
        # exit code equals the total number of violations in all commits
        exit_code += len(violations)
        if violations:
            # Display the commit hash & new lines intelligently
            if number_of_commits > 1 and commit.sha:
                linter.display.e(u"{0}Commit {1}:".format(
                    "\n" if not first_violation or commit is last_commit else
                    "", commit.sha[:10]))
            linter.print_violations(violations)
            first_violation = False

    # cap actual max exit code because bash doesn't like exit codes larger than 255:
    # http://tldp.org/LDP/abs/html/exitcodes.html
    exit_code = min(MAX_VIOLATION_ERROR_CODE, exit_code)
    LOG.debug("Exit Code = %s", exit_code)
    ctx.exit(exit_code)
Beispiel #46
0
 def test_gitcommitmessage_equality(self):
     commit_message1 = GitCommitMessage(GitContext(), "tëst\n\nfoo", "tëst\n\nfoo", "tēst", ["", "föo"])
     attrs = ['original', 'full', 'title', 'body']
     self.object_equality_test(commit_message1, attrs, {"context": commit_message1.context})
Beispiel #47
0
    def test_get_latest_commit_fixup_squash_commit(self, sh):
        commit_types = ["fixup", "squash"]
        for commit_type in commit_types:
            sample_sha = "d8ac47e9f2923c7f22d8668e3a1ed04eb4cdbca9"

            sh.git.side_effect = [
                sample_sha,
                u"test åuthor\x00test-emå[email protected]\x002016-12-03 15:28:15 +0100\x00åbc\n"
                u"{0}! \"foo bår commit\"".format(commit_type),
                u"#",  # git config --get core.commentchar
                u"file1.txt\npåth/to/file2.txt\n",
                u"foöbar\n* hürdur\n"
            ]

            context = GitContext.from_local_repository(u"fåke/path")
            # assert that commit info was read using git command
            expected_calls = [
                call("log", "-1", "--pretty=%H",
                     **self.expected_sh_special_args),
                call("log", sample_sha, "-1",
                     "--pretty=%aN%x00%aE%x00%ai%x00%P%n%B",
                     **self.expected_sh_special_args),
                call('config',
                     '--get',
                     'core.commentchar',
                     _ok_code=[0, 1],
                     **self.expected_sh_special_args),
                call('diff-tree', '--no-commit-id', '--name-only', '-r',
                     '--root', sample_sha, **self.expected_sh_special_args),
                call('branch', '--contains', sample_sha,
                     **self.expected_sh_special_args)
            ]

            # Only first 'git log' call should've happened at this point
            self.assertEqual(sh.git.mock_calls, expected_calls[:-4])

            last_commit = context.commits[-1]
            self.assertIsInstance(last_commit, LocalGitCommit)
            self.assertEqual(last_commit.sha, sample_sha)
            self.assertEqual(last_commit.message.title,
                             u"{0}! \"foo bår commit\"".format(commit_type))
            self.assertEqual(last_commit.message.body, [])
            self.assertEqual(last_commit.author_name, u"test åuthor")
            self.assertEqual(last_commit.author_email, u"test-emå[email protected]")
            self.assertEqual(
                last_commit.date,
                datetime.datetime(2016,
                                  12,
                                  3,
                                  15,
                                  28,
                                  15,
                                  tzinfo=dateutil.tz.tzoffset("+0100", 3600)))
            self.assertListEqual(last_commit.parents, [u"åbc"])

            # First 2 'git log' calls should've happened at this point
            self.assertEqual(sh.git.mock_calls, expected_calls[:3])

            # Asserting that squash and fixup are correct
            for type in commit_types:
                attr = "is_" + type + "_commit"
                self.assertEqual(getattr(last_commit, attr),
                                 commit_type == type)

            self.assertFalse(last_commit.is_merge_commit)
            self.assertFalse(last_commit.is_revert_commit)
            self.assertListEqual(last_commit.changed_files,
                                 ["file1.txt", u"påth/to/file2.txt"])

            self.assertListEqual(last_commit.changed_files,
                                 ["file1.txt", u"påth/to/file2.txt"])
            # 'git diff-tree' should have happened at this point
            self.assertListEqual(sh.git.mock_calls, expected_calls[:4])

            self.assertListEqual(last_commit.branches, [u"foöbar", u"hürdur"])
            # All expected calls should've happened at this point
            self.assertListEqual(sh.git.mock_calls, expected_calls)

            sh.git.reset_mock()
Beispiel #48
0
    def test_staged_commit(self, now, sh):
        # StagedLocalGitCommit()

        sh.git.side_effect = [
            u"#",  # git config --get core.commentchar
            u"test åuthor\n",  # git config --get user.name
            u"test-emå[email protected]\n",  # git config --get user.email
            u"my-brånch\n",  # git rev-parse --abbrev-ref HEAD
            u"file1.txt\npåth/to/file2.txt\n",
        ]
        now.side_effect = [arrow.get("2020-02-19T12:18:46.675182+01:00")]

        # We use a fixup commit, just to test a non-default path
        context = GitContext.from_staged_commit(
            u"fixup! Foōbar 123\n\ncömmit-body\n", u"fåke/path")

        # git calls we're expexting
        expected_calls = [
            call('config',
                 '--get',
                 'core.commentchar',
                 _ok_code=[0, 1],
                 **self.expected_sh_special_args),
            call('config', '--get', 'user.name',
                 **self.expected_sh_special_args),
            call('config', '--get', 'user.email',
                 **self.expected_sh_special_args),
            call("rev-parse", "--abbrev-ref", "HEAD",
                 **self.expected_sh_special_args),
            call("diff", "--staged", "--name-only", "-r",
                 **self.expected_sh_special_args)
        ]

        last_commit = context.commits[-1]
        self.assertIsInstance(last_commit, StagedLocalGitCommit)
        self.assertIsNone(last_commit.sha, None)
        self.assertEqual(last_commit.message.title, u"fixup! Foōbar 123")
        self.assertEqual(last_commit.message.body, ["", u"cömmit-body"])
        # Only `git config --get core.commentchar` should've happened up until this point
        self.assertListEqual(sh.git.mock_calls, expected_calls[0:1])

        self.assertEqual(last_commit.author_name, u"test åuthor")
        self.assertListEqual(sh.git.mock_calls, expected_calls[0:2])

        self.assertEqual(last_commit.author_email, u"test-emå[email protected]")
        self.assertListEqual(sh.git.mock_calls, expected_calls[0:3])

        self.assertEqual(
            last_commit.date,
            datetime.datetime(2020,
                              2,
                              19,
                              12,
                              18,
                              46,
                              tzinfo=dateutil.tz.tzoffset("+0100", 3600)))
        now.assert_called_once()

        self.assertListEqual(last_commit.parents, [])
        self.assertFalse(last_commit.is_merge_commit)
        self.assertTrue(last_commit.is_fixup_commit)
        self.assertFalse(last_commit.is_squash_commit)
        self.assertFalse(last_commit.is_revert_commit)

        self.assertListEqual(last_commit.branches, [u"my-brånch"])
        self.assertListEqual(sh.git.mock_calls, expected_calls[0:4])

        self.assertListEqual(last_commit.changed_files,
                             ["file1.txt", u"påth/to/file2.txt"])
        self.assertListEqual(sh.git.mock_calls, expected_calls[0:5])
Beispiel #49
0
    def test_from_local_repository_specific_ref(self, sh):
        sample_sha = "myspecialref"

        sh.git.side_effect = [
            sample_sha,
            u"test åuthor\x00test-emå[email protected]\x002016-12-03 15:28:15 +0100\x00åbc\n"
            u"cömmit-title\n\ncömmit-body",
            u"#",  # git config --get core.commentchar
            u"file1.txt\npåth/to/file2.txt\n",
            u"foöbar\n* hürdur\n"
        ]

        context = GitContext.from_local_repository(u"fåke/path", sample_sha)
        # assert that commit info was read using git command
        expected_calls = [
            call("rev-list", sample_sha, **self.expected_sh_special_args),
            call("log", sample_sha, "-1",
                 "--pretty=%aN%x00%aE%x00%ai%x00%P%n%B",
                 **self.expected_sh_special_args),
            call('config',
                 '--get',
                 'core.commentchar',
                 _ok_code=[0, 1],
                 **self.expected_sh_special_args),
            call('diff-tree', '--no-commit-id', '--name-only', '-r', '--root',
                 sample_sha, **self.expected_sh_special_args),
            call('branch', '--contains', sample_sha,
                 **self.expected_sh_special_args)
        ]

        # Only first 'git log' call should've happened at this point
        self.assertEqual(sh.git.mock_calls, expected_calls[:1])

        last_commit = context.commits[-1]
        self.assertIsInstance(last_commit, LocalGitCommit)
        self.assertEqual(last_commit.sha, sample_sha)
        self.assertEqual(last_commit.message.title, u"cömmit-title")
        self.assertEqual(last_commit.message.body, ["", u"cömmit-body"])
        self.assertEqual(last_commit.author_name, u"test åuthor")
        self.assertEqual(last_commit.author_email, u"test-emå[email protected]")
        self.assertEqual(
            last_commit.date,
            datetime.datetime(2016,
                              12,
                              3,
                              15,
                              28,
                              15,
                              tzinfo=dateutil.tz.tzoffset("+0100", 3600)))
        self.assertListEqual(last_commit.parents, [u"åbc"])
        self.assertFalse(last_commit.is_merge_commit)
        self.assertFalse(last_commit.is_fixup_commit)
        self.assertFalse(last_commit.is_squash_commit)
        self.assertFalse(last_commit.is_revert_commit)

        # First 2 'git log' calls should've happened at this point
        self.assertListEqual(sh.git.mock_calls, expected_calls[:3])

        self.assertListEqual(last_commit.changed_files,
                             ["file1.txt", u"påth/to/file2.txt"])
        # 'git diff-tree' should have happened at this point
        self.assertListEqual(sh.git.mock_calls, expected_calls[:4])

        self.assertListEqual(last_commit.branches, [u"foöbar", u"hürdur"])
        # All expected calls should've happened at this point
        self.assertListEqual(sh.git.mock_calls, expected_calls)