Пример #1
0
class TitleMaxLengthCustom(MaxLineLengthCustom):
    name = "title-max-length-custom"
    id = "UT1"
    target = CommitMessageTitle
    options_spec = [IntOption('line-length', 65, "Max line length"),
                IntOption('warn-line-length', 50, "Warning about line length")]
    violation_message = "Title exceeds max length ({0}>{1})"
    warning_message = "{2} WARNING: Title exceeds max length ({0}>{1}): \"{3}\""
Пример #2
0
    def test_option_equals(self):
        # 2 options are equal if their name, value and description match
        option1 = IntOption("test-option", 123, u"Test Dëscription")
        option2 = IntOption("test-option", 123, u"Test Dëscription")
        self.assertEqual(option1, option2)

        # Not equal: name, description, value are different
        self.assertNotEqual(option1, IntOption("test-option1", 123, u"Test Dëscription"))
        self.assertNotEqual(option1, IntOption("test-option", 1234, u"Test Dëscription"))
        self.assertNotEqual(option1, IntOption("test-option", 123, u"Test Dëscription2"))
Пример #3
0
class ConfigurableCommitRule(CommitRule):
    """ Rule that tests that we can add configuration to user-defined rules """
    name = "configürable"
    id = "UC4"

    options_spec = [
        IntOption("int-öption", 2, "int-öption description"),
        StrOption("str-öption", "föo", "int-öption description"),
        ListOption("list-öption", ["foo", "bar"], "list-öption description")
    ]

    def validate(self, _):
        violations = [
            RuleViolation(self.id,
                          f"int-öption: {self.options[u'int-öption'].value}",
                          line_nr=1),
            RuleViolation(self.id,
                          f"str-öption: {self.options[u'str-öption'].value}",
                          line_nr=1),
            RuleViolation(self.id,
                          f"list-öption: {self.options[u'list-öption'].value}",
                          line_nr=1),
        ]

        return violations
Пример #4
0
class ReleaseConfigurationRule(ConfigurationRule):
    """
    This rule will modify gitlint's behavior for Release Commits.

    This example might not be the most realistic for a real-world scenario,
    but is meant to give an overview of what's possible.
    """

    # A rule MUST have a human friendly name
    name = "release-configuration-rule"

    # A rule MUST have a *unique* id, we recommend starting with UCR
    # (for User-defined Configuration-Rule), but this can really be anything.
    id = "UCR1"

    # A rule MAY have an option_spec if its behavior should be configurable.
    options_spec = [
        IntOption('custom-verbosity', 2,
                  "Gitlint verbosity for release commits")
    ]

    def apply(self, config, commit):
        self.log.debug(
            "ReleaseConfigurationRule: This will be visible when running `gitlint --debug`"
        )

        # If the commit title starts with 'Release', we want to modify
        # how all subsequent rules interpret that commit
        if commit.message.title.startswith("Release"):

            # If your Release commit messages are auto-generated, the
            # body might contain trailing whitespace. Let's ignore that
            config.ignore.append("body-trailing-whitespace")

            # Similarly, the body lines might exceed 80 chars,
            # let's set gitlint's limit to 200
            # To set rule options use:
            # config.set_rule_option(<rule-name>, <rule-option>, <value>)
            config.set_rule_option("body-max-line-length", "line-length", 200)

            # For kicks, let's set gitlint's verbosity to 2
            # To set general options use
            # config.set_general_option(<general-option>, <value>)
            config.set_general_option("verbosity", 2)
            # Wwe can also use custom options to make this configurable
            config.set_general_option("verbosity",
                                      self.options['custom-verbosity'].value)

            # Strip any lines starting with $ from the commit message
            # (this only affects how gitlint sees your commit message, it does
            # NOT modify your actual commit in git)
            commit.message.body = [
                line for line in commit.message.body
                if not line.startswith("$")
            ]

            # You can add any extra properties you want to the commit object, these will be available later on
            # in all rules.
            commit.my_property = "This is my property"
Пример #5
0
class MaxLineLengthCustom(LineRule):
    name = "max-line-length-custom"
    id = "UR1"
    target = CommitMessageBody
    options_spec = [IntOption('line-length', 80, "Max line length"),
                    IntOption('warn-line-length', 78, "Warning about line length")]
    warning_message = "{2} WARNING: Line exceeds max length ({0}>{1}): \"{3}\""
    violation_message = "Line exceeds max length ({0}>{1})"

    def validate(self, line, _commit):
        max_length = self.options['line-length'].value
        warn_length = self.options['warn-line-length'].value
        if len(line) > max_length:
            return [RuleViolation(self.id, self.violation_message.format(len(line), max_length), line)]
        elif len(line) > warn_length:
            print self.warning_message.format(len(line), warn_length,
                                              self.id, line)
Пример #6
0
class BodyMaxLineCount(CommitRule):
    name = "body-max-line-count"
    id = "UC1"
    options_spec = [
        IntOption('body-max-line-count', 3, "Maximum body line count")
    ]

    def validate(self, commit):
        if len(commit.message.body) > self.options['body-max-line-count']:
            return [RuleViolation(self.id, "Body contains too many lines")]
Пример #7
0
class MaxLineLength(LineRule):
    name = "max-line-length"
    id = "R1"
    options_spec = [IntOption('line-length', 80, "Max line length")]
    violation_message = "Line exceeds max length ({0}>{1})"

    def validate(self, line, _commit):
        max_length = self.options['line-length'].value
        if len(line) > max_length:
            return [RuleViolation(self.id, self.violation_message.format(len(line), max_length), line)]
Пример #8
0
class MyUserCommitRule(CommitRule):
    name = "my-üser-commit-rule"
    id = "UC1"
    options_spec = [IntOption('violation-count', 1, "Number of violåtions to return")]

    def validate(self, _commit):
        violations = []
        for i in range(1, self.options['violation-count'].value + 1):
            violations.append(RuleViolation(self.id, "Commit violåtion %d" % i, "Contënt %d" % i, i))

        return violations
Пример #9
0
class MaxLineLengthExceptions(LineRule):
    name = "max-line-length-with-exceptions"
    id = "UC4"
    target = CommitMessageBody
    options_spec = [IntOption('line-length', 80, "Max line length")]
    violation_message = "Line exceeds max length ({0}>{1})"

    def validate(self, line, _commit):
        max_length = self.options['line-length'].value
        if len(line) > max_length and not line.startswith('Signed-off-by'):
            return [RuleViolation(self.id, self.violation_message.format(len(line), max_length), line)]
Пример #10
0
class TitleMaxLengthRevert(LineRule):
    name = "title-max-length-no-revert"
    id = "UC5"
    target = CommitMessageTitle
    options_spec = [IntOption('line-length', 72, "Max line length")]
    violation_message = "Title exceeds max length ({0}>{1})"

    def validate(self, line, _commit):
        max_length = self.options['line-length'].value
        if len(line) > max_length and not line.startswith("Revert"):
            return [RuleViolation(self.id, self.violation_message.format(len(line), max_length), line)]
Пример #11
0
class BodyMinLength(CommitRule):
    name = "body-min-length"
    id = "B5"
    options_spec = [IntOption('min-length', 20, "Minimum body length")]

    def validate(self, commit):
        min_length = self.options['min-length'].value
        body_message_no_newline = "".join([line for line in commit.message.body if line is not None])
        actual_length = len(body_message_no_newline)
        if actual_length > 0 and actual_length < min_length:
            violation_message = "Body message is too short ({0}<{1})".format(actual_length, min_length)
            return [RuleViolation(self.id, violation_message, body_message_no_newline, 3)]
Пример #12
0
class TitleMinLength(LineRule):
    name = "title-min-length"
    id = "T8"
    target = CommitMessageTitle
    options_spec = [IntOption('min-length', 5, "Minimum required title length")]

    def validate(self, title, _commit):
        min_length = self.options['min-length'].value
        actual_length = len(title)
        if actual_length < min_length:
            violation_message = f"Title is too short ({actual_length}<{min_length})"
            return [RuleViolation(self.id, violation_message, title, 1)]
Пример #13
0
class BodyMinLength(CommitRule):
    name = "body-min-length"
    id = "B5"
    options_spec = [IntOption('min-length', 20, "Minimum body length")]

    def validate(self, commit):
        min_length = self.options['min-length'].value
        lines = commit.message.body
        if len(lines) == 2:
            actual_length = len(lines[1])
            if lines[0] == "" and actual_length <= min_length:
                violation_message = "Body message is too short ({0}<{1})".format(
                    actual_length, min_length)
                return [RuleViolation(self.id, violation_message, lines[1], 3)]
Пример #14
0
class BodyMinLength(MultiLineRule, CommitMessageBodyRule):
    name = "body-min-length"
    id = "B5"
    options_spec = [IntOption('min-length', 20, "Minimum body length")]

    def validate(self, gitcontext):
        min_length = self.options['min-length'].value
        lines = gitcontext.commit_msg.body
        if len(lines) == 3:
            actual_length = len(lines[1])
            if lines[0] == "" and actual_length <= min_length:
                violation_message = "Body message is too short ({}<{})".format(
                    actual_length, min_length)
                return [RuleViolation(self.id, violation_message, lines[1], 3)]
Пример #15
0
class BodyMaxLineCount(CommitRule):
    # A rule MUST have a human friendly name
    name = "body-max-line-count"

    # A rule MUST have an *unique* id, we recommend starting with UC (for User-defined Commit-rule).
    id = "UC1"

    # A rule MAY have an option_spec if its behavior should be configurable.
    options_spec = [IntOption('max-line-count', 3, "Maximum body line count")]

    def validate(self, commit):
        line_count = len(commit.message.body)
        max_line_count = self.options['max-line-count'].value
        if line_count > max_line_count:
            message = "Body contains too many lines ({0} > {1})".format(line_count, max_line_count)
            return [RuleViolation(self.id, message, line_nr=1)]
Пример #16
0
class BodyMinLineCount(CommitRule):
    # A rule MUST have a human friendly name
    name = "body-min-line-count"

    # A rule MUST have an *unique* id, we recommend starting with UC (for User-defined Commit-rule).
    id = "UC6"

    # A rule MAY have an option_spec if its behavior should be configurable.
    options_spec = [IntOption('min-line-count', 2, "Minimum body line count excluding Signed-off-by")]

    def validate(self, commit):
        filtered = [x for x in commit.message.body if not x.lower().startswith("signed-off-by") and x != '']
        line_count = len(filtered)
        min_line_count = self.options['min-line-count'].value
        if line_count < min_line_count:
            message = "Body has no content, should at least have {} line.".format(min_line_count)
            return [RuleViolation(self.id, message, line_nr=1)]
Пример #17
0
class ConfigurableCommitRule(CommitRule):
    """ Rule that tests that we can add configuration to user-defined rules """
    name = u"configürable"
    id = "UC4"

    options_spec = [IntOption(u"int-öption", 2, u"int-öption description"),
                    StrOption(u"str-öption", u"föo", u"int-öption description"),
                    ListOption(u"list-öption", [u"foo", u"bar"], u"list-öption description")]

    def validate(self, _):
        violations = [
            RuleViolation(self.id, u"int-öption: {0}".format(self.options[u'int-öption'].value), line_nr=1),
            RuleViolation(self.id, u"str-öption: {0}".format(self.options[u'str-öption'].value), line_nr=1),
            RuleViolation(self.id, u"list-öption: {0}".format(sstr(self.options[u'list-öption'].value)), line_nr=1),
        ]

        return violations
Пример #18
0
class MaxLineLengthExceptions(LineRule):
    name = "max-line-length-with-exceptions"
    id = "UC4"
    target = CommitMessageBody
    options_spec = [IntOption('line-length', 80, "Max line length")]
    violation_message = "Line exceeds max length ({0}>{1})"

    def validate(self, line, _commit):
        max_length = self.options['line-length'].value
        urls = re.findall(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', line)
        if line.startswith('Signed-off-by'):
            return

        if urls:
            return

        if len(line) > max_length:
            return [RuleViolation(self.id, self.violation_message.format(len(line), max_length), line)]
Пример #19
0
    def test_extra_path(self):
        config = LintConfig()

        config.set_general_option("extra-path", self.get_user_rules_path())
        self.assertEqual(config.extra_path, self.get_user_rules_path())
        actual_rule = config.get_rule('UC1')
        self.assertTrue(actual_rule.user_defined)
        self.assertEqual(ustr(type(actual_rule)), "<class 'my_commit_rules.MyUserCommitRule'>")
        self.assertEqual(actual_rule.id, 'UC1')
        self.assertEqual(actual_rule.name, u'my-üser-commit-rule')
        self.assertEqual(actual_rule.target, None)
        expected_rule_option = IntOption('violation-count', 1, u"Number of violåtions to return")
        self.assertListEqual(actual_rule.options_spec, [expected_rule_option])
        self.assertDictEqual(actual_rule.options, {'violation-count': expected_rule_option})

        # reset value (this is a different code path)
        config.set_general_option("extra-path", self.SAMPLES_DIR)
        self.assertEqual(config.extra_path, self.SAMPLES_DIR)
        self.assertIsNone(config.get_rule("UC1"))
Пример #20
0
class BodyMaxLineCount(CommitRule):
    # A rule MUST have a human friendly name
    name = "body-max-line-count"

    # A rule MUST have a *unique* id, we recommend starting with UC (for User-defined Commit-rule).
    id = "UC1"

    # A rule MAY have an option_spec if its behavior should be configurable.
    options_spec = [IntOption('max-line-count', 3, "Maximum body line count")]

    def validate(self, commit):
        self.log.debug(
            "BodyMaxLineCount: This will be visible when running `gitlint --debug`"
        )

        line_count = len(commit.message.body)
        max_line_count = self.options['max-line-count'].value
        if line_count > max_line_count:
            message = f"Body contains too many lines ({line_count} > {max_line_count})"
            return [RuleViolation(self.id, message, line_nr=1)]
Пример #21
0
    def test_option_equality(self):
        options = {
            IntOption: 123,
            StrOption: u"foöbar",
            BoolOption: False,
            ListOption: ["a", "b"],
            PathOption: ".",
            RegexOption: u"^foöbar(.*)"
        }
        for clazz, val in options.items():
            # 2 options are equal if their name, value and description match
            option1 = clazz(u"test-öption", val, u"Test Dëscription")
            option2 = clazz(u"test-öption", val, u"Test Dëscription")
            self.assertEqual(option1, option2)

        # Not equal: class, name, description, value are different
        self.assertNotEqual(
            option1, IntOption(u"tëst-option1", 123, u"Test Dëscription"))
        self.assertNotEqual(
            option1, StrOption(u"tëst-option1", u"åbc", u"Test Dëscription"))
        self.assertNotEqual(
            option1, StrOption(u"tëst-option", u"åbcd", u"Test Dëscription"))
        self.assertNotEqual(
            option1, StrOption(u"tëst-option", u"åbc", u"Test Dëscription2"))
Пример #22
0
class TitleMaxLength(MaxLineLength):
    name = "title-max-length"
    id = "T1"
    target = CommitMessageTitle
    options_spec = [IntOption('line-length', 72, "Max line length")]
    violation_message = "Title exceeds max length ({0}>{1})"
Пример #23
0
    def test_int_option(self):
        # normal behavior
        option = IntOption("test-name", 123, "Test Description")
        option.set(456)
        self.assertEqual(option.value, 456)

        # error on negative int when not allowed
        expected_error = "Option 'test-name' must be a positive integer \(current value: '-123'\)"
        with self.assertRaisesRegexp(RuleOptionError, expected_error):
            option.set(-123)

        # error on non-int value
        expected_error = "Option 'test-name' must be a positive integer \(current value: 'foo'\)"
        with self.assertRaisesRegexp(RuleOptionError, expected_error):
            option.set("foo")

        # no error on negative value when allowed and negative int is passed
        option = IntOption("test-name", 123, "Test Description", allow_negative=True)
        option.set(-456)
        self.assertEqual(option.value, -456)

        # error on non-int value when negative int is allowed
        expected_error = "Option 'test-name' must be an integer \(current value: 'foo'\)"
        with self.assertRaisesRegexp(RuleOptionError, expected_error):
            option.set("foo")
Пример #24
0
    def test_int_option(self):
        # normal behavior
        option = IntOption("test-name", 123, "Test Description")
        self.assertEqual(option.value, 123)
        self.assertEqual(option.name, "test-name")
        self.assertEqual(option.description, "Test Description")

        # re-set value
        option.set(456)
        self.assertEqual(option.value, 456)

        # error on negative int when not allowed
        expected_error = r"Option 'test-name' must be a positive integer \(current value: '-123'\)"
        with self.assertRaisesRegexp(RuleOptionError, expected_error):
            option.set(-123)

        # error on non-int value
        expected_error = r"Option 'test-name' must be a positive integer \(current value: 'foo'\)"
        with self.assertRaisesRegexp(RuleOptionError, expected_error):
            option.set("foo")

        # no error on negative value when allowed and negative int is passed
        option = IntOption("test-name",
                           123,
                           "Test Description",
                           allow_negative=True)
        option.set(-456)
        self.assertEqual(option.value, -456)

        # error on non-int value when negative int is allowed
        expected_error = r"Option 'test-name' must be an integer \(current value: 'foo'\)"
        with self.assertRaisesRegexp(RuleOptionError, expected_error):
            option.set("foo")
Пример #25
0
class BodyMaxLineLengthCustom(MaxLineLengthCustom):
    name = "body-max-line-length-custom"
    id = "UB1"
    target = CommitMessageBody
    options_spec = [IntOption('line-length', 80, "Max line length"),
                IntOption('warn-line-length', 78, "Warning about line length")]