Exemplo n.º 1
0
    def test_git_no_commits_error(self, sh):
        # No commits: returned by 'git log'
        err = b"fatal: your current branch 'master' does not have any commits yet"

        sh.git.side_effect = ErrorReturnCode("git log -1 --pretty=%H", b"", err)

        expected_msg = "Current branch has no commits. Gitlint requires at least one commit to function."
        with self.assertRaisesMessage(GitContextError, expected_msg):
            GitContext.from_local_repository("fåke/path")

        # assert that commit message was read using git command
        sh.git.assert_called_once_with("log", "-1", "--pretty=%H", **self.expected_sh_special_args)
        sh.git.reset_mock()

        # Unknown reference 'HEAD' commits: returned by 'git rev-parse'
        err = (b"HEAD"
               b"fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree."
               b"Use '--' to separate paths from revisions, like this:"
               b"'git <command> [<revision>...] -- [<file>...]'")

        sh.git.side_effect = [
            "#\n",  # git config --get core.commentchar
            ErrorReturnCode("rev-parse --abbrev-ref HEAD", b"", err)
        ]

        with self.assertRaisesMessage(GitContextError, expected_msg):
            context = GitContext.from_commit_msg("test")
            context.current_branch

        # assert that commit message was read using git command
        sh.git.assert_called_with("rev-parse", "--abbrev-ref", "HEAD", _tty_out=False, _cwd=None)
Exemplo n.º 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)
Exemplo n.º 3
0
    def test_from_commit_msg_fixup_squash_commit(self):
        commit_types = ["fixup", "squash"]
        for commit_type in commit_types:
            commit_msg = f"{commit_type}! Test message"
            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, 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.assertListEqual(commit.branches, [])
            self.assertEqual(len(gitcontext.commits), 1)
            self.assertFalse(commit.is_merge_commit)
            self.assertFalse(commit.is_revert_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)
Exemplo n.º 4
0
    def test_from_commit_msg_full(self):
        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"

        commit = gitcontext.commits[-1]
        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.assertFalse(commit.is_merge_commit)
        self.assertEqual(len(gitcontext.commits), 1)
Exemplo n.º 5
0
 def gitcontext(commit_msg_str, changed_files=None):
     """ Utility method to easily create gitcontext objects based on a given commit msg string and an optional 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
Exemplo n.º 6
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
Exemplo n.º 7
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)
Exemplo n.º 8
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)
Exemplo n.º 9
0
 def gitcontext(commit_msg_str, changed_files=None, ):
     """ Utility method to easily create gitcontext objects based on a given commit msg string and an optional set of
     changed files"""
     with patch("gitlint.git.git_commentchar") as comment_char:
         comment_char.return_value = u"#"
         gitcontext = GitContext.from_commit_msg(commit_msg_str)
         commit = gitcontext.commits[-1]
         if changed_files:
             commit.changed_files = changed_files
         return gitcontext
Exemplo n.º 10
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)
Exemplo n.º 11
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, ctx.obj[2])
        else:
            stdin_str = ustr(sys.stdin.read())
            gitcontext = GitContext.from_commit_msg(stdin_str)
    except GitContextError as e:
        click.echo(ustr(e))
        ctx.exit(GIT_CONTEXT_ERROR_CODE)

    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:
        click.echo(u'No commits in range "{0}".'.format(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 and linter taking into account the commit specific config (if any)
        config_builder = general_config_builder.clone()
        config_builder.set_config_from_commit(commit)
        lint_config = config_builder.build(lint_config)
        linter = GitLinter(lint_config)

        # Actually do the linting
        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)
Exemplo n.º 12
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.assertListEqual(gitcontext.commits[-1].parents, [])
        self.assertFalse(gitcontext.commits[-1].is_merge_commit)
        self.assertEqual(len(gitcontext.commits), 1)
Exemplo n.º 13
0
def build_git_context(lint_config, msg_filename, refspec):
    """ Builds a git context based on passed parameters and order of precedence """
    # Order of precedence:
    # 1. Any data specified via --msg-filename
    if msg_filename:
        LOG.debug("Attempting to read from --msg-filename.")
        return GitContext.from_commit_msg(ustr(msg_filename.read()))

    # 2. Any data sent to stdin (unless stdin is being ignored)
    if not lint_config.ignore_stdin:
        stdin_input = get_stdin_data()
        if stdin_input:
            LOG.debug("Stdin data: %r", stdin_input)
            LOG.debug("Stdin detected and not ignored. Will be used as input.")
            return GitContext.from_commit_msg(stdin_input)

    # 3. Fallback to reading from local repository
    LOG.debug(
        "No --msg-filename flag, no or empty data passed to stdin. Attempting to read from the local repo."
    )
    return GitContext.from_local_repository(lint_config.target, refspec)
Exemplo n.º 14
0
    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)
Exemplo n.º 15
0
    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)
Exemplo n.º 16
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.assertEqual(len(gitcontext.commits), 1)
Exemplo n.º 17
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, ctx.obj[2])
        else:
            stdin_str = ustr(sys.stdin.read())
            gitcontext = GitContext.from_commit_msg(stdin_str)
    except GitContextError as e:
        click.echo(ustr(e))
        ctx.exit(GIT_CONTEXT_ERROR_CODE)

    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:
        click.echo(u'No commits in range "{0}".'.format(ctx.obj[2]))
        ctx.exit(0)

    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)
    first_violation = True

    for commit in gitcontext.commits:
        violations = linter.lint(commit)
        if violations:
            # Display the commit hash & new lines intelligently
            if number_of_commits > 1 and commit.sha:
                click.echo(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

    exit_code = min(MAX_VIOLATION_ERROR_CODE, len(violations))
    ctx.exit(exit_code)
Exemplo n.º 18
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)
Exemplo n.º 19
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)
Exemplo n.º 20
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.assertFalse(commit.is_revert_commit)
        self.assertEqual(len(gitcontext.commits), 1)
Exemplo n.º 21
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)
Exemplo n.º 22
0
    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.assertEqual(len(gitcontext.commits), 1)
Exemplo n.º 23
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.assertIsInstance(commit, GitCommit)
        self.assertFalse(isinstance(commit, LocalGitCommit))
        self.assertEqual(commit.message.title, "Just a title contåining WIP")
        self.assertEqual(commit.message.body, [])
        self.assertEqual(commit.message.full, "Just a title contåining WIP")
        self.assertEqual(commit.message.original, "Just a title contåining WIP")
        self.assertEqual(commit.author_name, None)
        self.assertEqual(commit.author_email, 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)
Exemplo n.º 24
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)
Exemplo n.º 25
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.assertIsInstance(commit, GitCommit)
        self.assertFalse(isinstance(commit, LocalGitCommit))
        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.assertListEqual(commit.branches, [])
        self.assertTrue(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)
Exemplo n.º 26
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)
Exemplo n.º 27
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)
    linter.print_violations(violations)
    exit_code = min(MAX_VIOLATION_ERROR_CODE, len(violations))
    ctx.exit(exit_code)
Exemplo n.º 28
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)
Exemplo n.º 29
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)