Пример #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)
Пример #2
0
    def test_lint_regex_rules(self):
        """ Additional test for title-match-regex, body-match-regex """
        commit = self.gitcommit(
            self.get_sample("commit_message/no-violations"))
        lintconfig = LintConfig()
        linter = GitLinter(lintconfig)
        violations = linter.lint(commit)
        # No violations by default
        self.assertListEqual(violations, [])

        # Matching regexes shouldn't be a problem
        rule_regexes = [("title-match-regex", u"Tïtle$"),
                        ("body-match-regex", u"Sïgned-Off-By: (.*)$")]
        for rule_regex in rule_regexes:
            lintconfig.set_rule_option(rule_regex[0], "regex", rule_regex[1])
            violations = linter.lint(commit)
            self.assertListEqual(violations, [])

        # Non-matching regexes should return violations
        rule_regexes = [("title-match-regex", ), ("body-match-regex", )]
        lintconfig.set_rule_option("title-match-regex", "regex", u"^Tïtle")
        lintconfig.set_rule_option("body-match-regex", "regex",
                                   u"Sügned-Off-By: (.*)$")
        expected_violations = [
            RuleViolation("T7", u"Title does not match regex (^Tïtle)",
                          u"Normal Commit Tïtle", 1),
            RuleViolation("B8",
                          u"Body does not match regex (Sügned-Off-By: (.*)$)",
                          None, 6)
        ]
        violations = linter.lint(commit)
        self.assertListEqual(violations, expected_violations)
Пример #3
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)
Пример #4
0
 def test_lint_sample5(self):
     gitcontext = self.gitcontext(self.get_sample("commit_message/sample5"))
     lintconfig = LintConfig()
     lintconfig.apply_config_from_commit(gitcontext.commits[-1])
     linter = GitLinter(lintconfig)
     violations = linter.lint(gitcontext.commits[-1], 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)
Пример #5
0
    def test_lint_sample1(self):
        linter = GitLinter(LintConfig())
        gitcontext = self.gitcontext(self.get_sample("commit_message/sample1"))
        violations = linter.lint(gitcontext.commits[-1])
        expected_errors = [
            RuleViolation(
                "T3", "Title has trailing punctuation (.)",
                u"Commit title contåining 'WIP', as well as trailing punctuation.",
                1),
            RuleViolation(
                "T5", "Title contains the word 'WIP' (case-insensitive)",
                u"Commit title contåining '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",
                          u"This line has a tråiling 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)
Пример #6
0
    def test_named_rules(self):
        """ Test that when named rules are present, both them and the original (non-named) rules executed """

        lint_config = LintConfig()
        for rule_name in [u"my-ïd", u"another-rule-ïd"]:
            rule_id = TitleMustNotContainWord.id + ":" + rule_name
            lint_config.rules.add_rule(TitleMustNotContainWord, rule_id)
            lint_config.set_rule_option(rule_id, "words", [u"Föo"])
            linter = GitLinter(lint_config)

        violations = [
            RuleViolation("T5",
                          u"Title contains the word 'WIP' (case-insensitive)",
                          u"WIP: Föo bar", 1),
            RuleViolation(u"T5:another-rule-ïd",
                          u"Title contains the word 'Föo' (case-insensitive)",
                          u"WIP: Föo bar", 1),
            RuleViolation(u"T5:my-ïd",
                          u"Title contains the word 'Föo' (case-insensitive)",
                          u"WIP: Föo bar", 1)
        ]
        self.assertListEqual(
            violations,
            linter.lint(
                self.gitcommit(u"WIP: Föo bar\n\nFoo bår hur dur bla bla")))
Пример #7
0
    def test_lint_sample5(self):
        commit = self.gitcommit(self.get_sample("commit_message/sample5"))
        config_builder = LintConfigBuilder()
        config_builder.set_config_from_commit(commit)
        linter = GitLinter(config_builder.build())
        violations = linter.lint(commit)

        title = u" Commit title containing 'WIP', \tleading and tråiling whitespace and longer than 72 characters."
        # expect only certain violations because sample5 has a 'gitlint-ignore: T3, T6, body-max-line-length'
        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",
                          u"This line should be ëmpty", 2),
            RuleViolation("B2", "Line has trailing whitespace",
                          u"This line has a tråiling 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)
Пример #8
0
    def test_lint_sample3(self):
        linter = GitLinter(LintConfig())
        gitcontext = self.gitcontext(self.get_sample("commit_message/sample3"))
        violations = linter.lint(gitcontext.commits[-1])

        title = u" Commit title containing 'WIP', \tleading and tråiling 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)",
                u"This is the first line is meånt 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",
                          u"This line has a tråiling tab.\t", 5),
            RuleViolation("B3", "Line contains hard tab characters (\\t)",
                          u"This line has a tråiling tab.\t", 5)
        ]

        self.assertListEqual(violations, expected)
Пример #9
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)
Пример #10
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))
Пример #11
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))
Пример #12
0
    def test_print_violations(self):
        violations = [
            RuleViolation("RULE_ID_1", u"Error Messåge 1",
                          "Violating Content 1", None),
            RuleViolation("RULE_ID_2", "Error Message 2",
                          u"Violåting Content 2", 2)
        ]
        linter = GitLinter(LintConfig())

        # test output with increasing verbosity
        with patch('gitlint.display.stderr', new=StringIO()) as stderr:
            linter.config.verbosity = 0
            linter.print_violations(violations)
            self.assertEqual("", stderr.getvalue())

        with patch('gitlint.display.stderr', new=StringIO()) as stderr:
            linter.config.verbosity = 1
            linter.print_violations(violations)
            expected = u"-: RULE_ID_1\n2: RULE_ID_2\n"
            self.assertEqual(expected, stderr.getvalue())

        with patch('gitlint.display.stderr', new=StringIO()) as stderr:
            linter.config.verbosity = 2
            linter.print_violations(violations)
            expected = u"-: RULE_ID_1 Error Messåge 1\n2: RULE_ID_2 Error Message 2\n"
            self.assertEqual(expected, stderr.getvalue())

        with patch('gitlint.display.stderr', new=StringIO()) as stderr:
            linter.config.verbosity = 3
            linter.print_violations(violations)
            expected = u"-: RULE_ID_1 Error Messåge 1: \"Violating Content 1\"\n" + \
                       u"2: RULE_ID_2 Error Message 2: \"Violåting Content 2\"\n"
            self.assertEqual(expected, stderr.getvalue())
Пример #13
0
    def test_lint_sample2(self):
        linter = GitLinter(LintConfig())
        gitcontext = self.gitcontext(self.get_sample("commit_message/sample2"))
        violations = linter.lint(gitcontext.commits[-1])
        expected = [RuleViolation("T5", "Title contains the word 'WIP' (case-insensitive)",
                                  u"Just a title contåining WIP", 1),
                    RuleViolation("B6", "Body message is missing", None, 3)]

        self.assertListEqual(violations, expected)
Пример #14
0
    def test_lint_sample2(self):
        linter = GitLinter(LintConfig())
        gitcontext = self.gitcontext(self.get_sample("commit_message/sample2"))
        violations = linter.lint(gitcontext.commits[-1])
        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)
Пример #15
0
 def test_lint_sample4(self):
     gitcontext = self.gitcontext(self.get_sample("commit_message/sample4"))
     lintconfig = LintConfig()
     lintconfig.apply_config_from_commit(gitcontext.commits[-1])
     linter = GitLinter(lintconfig)
     violations = linter.lint(gitcontext.commits[-1], gitcontext)
     # expect no violations because sample4 has a 'gitlint: disable line'
     expected = []
     self.assertListEqual(violations, expected)
Пример #16
0
 def test_lint_sample4(self):
     commit = self.gitcommit(self.get_sample("commit_message/sample4"))
     config_builder = LintConfigBuilder()
     config_builder.set_config_from_commit(commit)
     linter = GitLinter(config_builder.build())
     violations = linter.lint(commit)
     # expect no violations because sample4 has a 'gitlint: disable line'
     expected = []
     self.assertListEqual(violations, expected)
Пример #17
0
 def test_lint_sample4(self):
     gitcontext = self.gitcontext(self.get_sample("commit_message/sample4"))
     lintconfig = LintConfig()
     lintconfig.apply_config_from_commit(gitcontext.commits[-1])
     linter = GitLinter(lintconfig)
     violations = linter.lint(gitcontext.commits[-1], gitcontext)
     # expect no violations because sample4 has a 'gitlint: disable line'
     expected = []
     self.assertListEqual(violations, expected)
Пример #18
0
 def test_lint_sample4(self):
     commit = self.gitcommit(self.get_sample("commit_message/sample4"))
     config_builder = LintConfigBuilder()
     config_builder.set_config_from_commit(commit)
     linter = GitLinter(config_builder.build())
     violations = linter.lint(commit)
     # expect no violations because sample4 has a 'gitlint: disable line'
     expected = []
     self.assertListEqual(violations, expected)
Пример #19
0
    def test_print_violations(self):
        violations = [RuleViolation("RULE_ID_1", "Error Message 1", "Violating Content 1", 1),
                      RuleViolation("RULE_ID_2", "Error Message 2", "Violating Content 2", 2)]
        linter = GitLinter(LintConfig())

        # test output with increasing verbosity
        with patch('gitlint.display.stderr', new=StringIO()) as stderr:
            linter.config.verbosity = 0
            linter.print_violations(violations)
            self.assertEqual("", stderr.getvalue())

        with patch('gitlint.display.stderr', new=StringIO()) as stderr:
            linter.config.verbosity = 1
            linter.print_violations(violations)
            expected = "1: RULE_ID_1\n2: RULE_ID_2\n"
            self.assertEqual(expected, stderr.getvalue())

        with patch('gitlint.display.stderr', new=StringIO()) as stderr:
            linter.config.verbosity = 2
            linter.print_violations(violations)
            expected = "1: RULE_ID_1 Error Message 1\n2: RULE_ID_2 Error Message 2\n"
            self.assertEqual(expected, stderr.getvalue())

        with patch('gitlint.display.stderr', new=StringIO()) as stderr:
            linter.config.verbosity = 3
            linter.print_violations(violations)
            expected = "1: RULE_ID_1 Error Message 1: \"Violating Content 1\"\n" + \
                       "2: RULE_ID_2 Error Message 2: \"Violating Content 2\"\n"
            self.assertEqual(expected, stderr.getvalue())
Пример #20
0
def lint(ctx):
    """ Lints a git repository [default command] """
    lint_config = ctx.obj.config
    refspec = ctx.obj.refspec
    msg_filename = ctx.obj.msg_filename

    gitcontext = build_git_context(lint_config, msg_filename, refspec)
    # Set gitcontext in the click context, so we can use it in command that are ran after this
    # in particular, this is used by run-hook
    ctx.obj.gitcontext = gitcontext

    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"', refspec)
        ctx.exit(0)

    LOG.debug(u'Linting %d commit(s)', number_of_commits)
    general_config_builder = ctx.obj.config_builder
    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("{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)
Пример #21
0
    def test_lint_ignore(self):
        lint_config = LintConfig()
        lint_config.ignore = ["T1", "T3", "T4", "T5", "T6", "B1", "B2"]
        linter = GitLinter(lint_config)
        violations = linter.lint(self.gitcommit(self.get_sample("commit_message/sample3")))

        expected = [RuleViolation("B4", "Second line is not empty", "This line should be empty", 2),
                    RuleViolation("B3", "Line contains hard tab characters (\\t)",
                                  u"This line has a tråiling tab.\t", 5)]

        self.assertListEqual(violations, expected)
Пример #22
0
    def test_lint_ignore(self):
        lint_config = LintConfig()
        lint_config.ignore = ["T1", "T3", "T4", "T5", "T6", "B1", "B2"]
        linter = GitLinter(lint_config)
        violations = linter.lint(self.gitcommit(self.get_sample("commit_message/sample3")))

        expected = [RuleViolation("B4", "Second line is not empty", "This line should be empty", 2),
                    RuleViolation("B3", "Line contains hard tab characters (\\t)",
                                  "This line has a trailing tab.\t", 5)]

        self.assertListEqual(violations, expected)
Пример #23
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)
Пример #24
0
    def test_lint_meta(self):
        """ Lint sample2 but also add some metadata to the commit so we that get's linted as well """
        linter = GitLinter(LintConfig())
        gitcontext = self.gitcontext(self.get_sample("commit_message/sample2"))
        gitcontext.commits[0].author_email = u"foo bår"
        violations = linter.lint(gitcontext.commits[-1])
        expected = [RuleViolation("M1", "Author email for commit is invalid", u"foo bår", None),
                    RuleViolation("T5", "Title contains the word 'WIP' (case-insensitive)",
                                  u"Just a title contåining WIP", 1),
                    RuleViolation("B6", "Body message is missing", None, 3)]

        self.assertListEqual(violations, expected)
Пример #25
0
    def test_lint_configuration_rule(self):
        # Test that all rules are ignored because of matching regex
        lint_config = LintConfig()
        lint_config.set_rule_option("I1", "regex", "^Just a title(.*)")

        linter = GitLinter(lint_config)
        violations = linter.lint(
            self.gitcommit(self.get_sample("commit_message/sample2")))
        self.assertListEqual(violations, [])

        # Test ignoring only certain rules
        lint_config = LintConfig()
        lint_config.set_rule_option("I1", "regex", "^Just a title(.*)")
        lint_config.set_rule_option("I1", "ignore", "B6")

        linter = GitLinter(lint_config)
        violations = linter.lint(
            self.gitcommit(self.get_sample("commit_message/sample2")))

        # Normally we'd expect a B6 violation, but that one is skipped because of the specific ignore set above
        expected = [
            RuleViolation("T5",
                          "Title contains the word 'WIP' (case-insensitive)",
                          u"Just a title contåining WIP", 1)
        ]

        self.assertListEqual(violations, expected)

        # Test ignoring body lines
        lint_config = LintConfig()
        linter = GitLinter(lint_config)
        lint_config.set_rule_option("I3", "regex", u"(.*)tråiling(.*)")
        violations = linter.lint(
            self.gitcommit(self.get_sample("commit_message/sample1")))
        expected_errors = [
            RuleViolation(
                "T3", "Title has trailing punctuation (.)",
                u"Commit title contåining 'WIP', as well as trailing punctuation.",
                1),
            RuleViolation(
                "T5", "Title contains the word 'WIP' (case-insensitive)",
                u"Commit title contåining '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 tab.\t", 4),
            RuleViolation("B3", "Line contains hard tab characters (\\t)",
                          "This line has a trailing tab.\t", 4)
        ]

        self.assertListEqual(violations, expected_errors)
Пример #26
0
    def test_lint_merge_commit(self):
        commit = self.gitcommit(self.get_sample("commit_message/sample6"))  # Sample 6 is a merge commit
        lintconfig = LintConfig()
        linter = GitLinter(lintconfig)
        violations = linter.lint(commit)
        # Even though there are a number of violations in the commit message, they are ignored because
        # we are dealing with a merge commit
        self.assertListEqual(violations, [])

        # Check that we do see violations if we disable 'ignore-merge-commits'
        lintconfig.ignore_merge_commits = False
        linter = GitLinter(lintconfig)
        violations = linter.lint(commit)
        self.assertTrue(len(violations) > 0)
Пример #27
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)
Пример #28
0
 def test_lint_sample5(self):
     gitcontext = self.gitcontext(self.get_sample("commit_message/sample5"))
     lintconfig = LintConfig()
     lintconfig.apply_config_from_commit(gitcontext.commits[-1])
     linter = GitLinter(lintconfig)
     violations = linter.lint(gitcontext.commits[-1], 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)
Пример #29
0
    def test_lint_configuration_rule(self):
        # Test that all rules are ignored because of matching regex
        lint_config = LintConfig()
        lint_config.set_rule_option("I1", "regex", "^Just a title(.*)")

        linter = GitLinter(lint_config)
        violations = linter.lint(
            self.gitcommit(self.get_sample("commit_message/sample2")))
        self.assertListEqual(violations, [])

        # Test ignoring only certain rules
        lint_config = LintConfig()
        lint_config.set_rule_option("I1", "regex", "^Just a title(.*)")
        lint_config.set_rule_option("I1", "ignore", "B6")

        linter = GitLinter(lint_config)
        violations = linter.lint(
            self.gitcommit(self.get_sample("commit_message/sample2")))

        # Normally we'd expect a B6 violation, but that one is skipped because of the specific ignore set above
        expected = [
            RuleViolation("T5",
                          "Title contains the word 'WIP' (case-insensitive)",
                          u"Just a title contåining WIP", 1)
        ]

        self.assertListEqual(violations, expected)
Пример #30
0
    def test_ignore_named_rules(self):
        """ Test that named rules can be ignored """

        # Add named rule to lint config
        config_builder = LintConfigBuilder()
        rule_id = TitleMustNotContainWord.id + u":my-ïd"
        config_builder.set_option(rule_id, "words", [u"Föo"])
        lint_config = config_builder.build()
        linter = GitLinter(lint_config)
        commit = self.gitcommit(u"WIP: Föo bar\n\nFoo bår hur dur bla bla")

        # By default, we expect both the violations of the regular rule as well as the named rule to show up
        violations = [
            RuleViolation("T5",
                          u"Title contains the word 'WIP' (case-insensitive)",
                          u"WIP: Föo bar", 1),
            RuleViolation(u"T5:my-ïd",
                          u"Title contains the word 'Föo' (case-insensitive)",
                          u"WIP: Föo bar", 1)
        ]
        self.assertListEqual(violations, linter.lint(commit))

        # ignore regular rule: only named rule violations show up
        lint_config.ignore = ["T5"]
        self.assertListEqual(violations[1:], linter.lint(commit))

        # ignore named rule by id: only regular rule violations show up
        lint_config.ignore = [rule_id]
        self.assertListEqual(violations[:-1], linter.lint(commit))

        # ignore named rule by name: only regular rule violations show up
        lint_config.ignore = [TitleMustNotContainWord.name + u":my-ïd"]
        self.assertListEqual(violations[:-1], linter.lint(commit))
Пример #31
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)
Пример #32
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)
Пример #33
0
    def test_lint_special_commit(self):
        for commit_type in ["merge", "squash", "fixup"]:
            commit = self.gitcommit(self.get_sample("commit_message/{0}".format(commit_type)))
            lintconfig = LintConfig()
            linter = GitLinter(lintconfig)
            violations = linter.lint(commit)
            # Even though there are a number of violations in the commit message, they are ignored because
            # we are dealing with a merge commit
            self.assertListEqual(violations, [])

            # Check that we do see violations if we disable 'ignore-merge-commits'
            setattr(lintconfig, "ignore_{0}_commits".format(commit_type), False)
            linter = GitLinter(lintconfig)
            violations = linter.lint(commit)
            self.assertTrue(len(violations) > 0)
Пример #34
0
    def test_lint_merge_commit(self):
        commit = self.gitcommit(self.get_sample(
            "commit_message/sample6"))  # Sample 6 is a merge commit
        lintconfig = LintConfig()
        linter = GitLinter(lintconfig)
        violations = linter.lint(commit)
        # Even though there are a number of violations in the commit message, they are ignored because
        # we are dealing with a merge commit
        self.assertListEqual(violations, [])

        # Check that we do see violations if we disable 'ignore-merge-commits'
        lintconfig.ignore_merge_commits = False
        linter = GitLinter(lintconfig)
        violations = linter.lint(commit)
        self.assertTrue(len(violations) > 0)
Пример #35
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)