class IgnoreByBody(ConfigurationRule): name = "ignore-by-body" id = "I2" options_spec = [ StrOption( 'regex', None, "Regex matching lines of the body of commits this rule should apply to" ), StrOption('ignore', "all", "Comman-seperate list of rules to ignore") ] def apply(self, config, commit): body_line_regex = re.compile(self.options['regex'].value, re.UNICODE) for line in commit.message.body: if body_line_regex.match(line): config.ignore = self.options['ignore'].value message = u"Commit message line '{0}' matches the regex '{1}', ignoring rules: {2}" message = message.format(line, self.options['regex'].value, self.options['ignore'].value) LOG.debug("Ignoring commit because of rule '%s': %s", self.id, message) # No need to check other lines if we found a match return
class IgnoreByBody(ConfigurationRule): name = "ignore-by-body" id = "I2" options_spec = [ RegexOption( 'regex', None, "Regex matching lines of the body of commits this rule should apply to" ), StrOption('ignore', "all", "Comma-separated list of rules to ignore") ] def apply(self, config, commit): # If no regex is specified, immediately return if not self.options['regex'].value: return for line in commit.message.body: if self.options['regex'].value.match(line): config.ignore = self.options['ignore'].value message = f"Commit message line '{line}' matches the regex '{self.options['regex'].value.pattern}'," + \ f" ignoring rules: {self.options['ignore'].value}" self.log.debug("Ignoring commit because of rule '%s': %s", self.id, message) # No need to check other lines if we found a match return
class IgnoreByTitle(ConfigurationRule): name = "ignore-by-title" id = "I1" options_spec = [ RegexOption( 'regex', None, "Regex matching the titles of commits this rule should apply to"), StrOption('ignore', "all", "Comma-separated list of rules to ignore") ] def apply(self, config, commit): # If no regex is specified, immediately return if not self.options['regex'].value: return if self.options['regex'].value.match(commit.message.title): config.ignore = self.options['ignore'].value message = u"Commit title '{0}' matches the regex '{1}', ignoring rules: {2}" message = message.format(commit.message.title, self.options['regex'].value.pattern, self.options['ignore'].value) self.log.debug("Ignoring commit because of rule '%s': %s", self.id, message)
class IgnoreByTitle(ConfigurationRule): name = "ignore-by-title" id = "I1" options_spec = [StrOption('regex', None, "Regex matching the titles of commits this rule should apply to"), StrOption('ignore', "all", "Comman-seperate list of rules to ignore")] def apply(self, config, commit): title_regex = re.compile(self.options['regex'].value, re.UNICODE) if title_regex.match(commit.message.title): config.ignore = self.options['ignore'].value message = u"Commit title '{0}' matches the regex '{1}', ignoring rules: {2}" message = message.format(commit.message.title, self.options['regex'].value, self.options['ignore'].value) LOG.debug("Ignoring commit because of rule '%s': %s", self.id, message)
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
class TitleRegexMatches(CommitMessageTitleRule): name = "title-match-regex" id = "T7" options_spec = [StrOption('regex', ".*", "Regex the title should match")] def validate(self, title, _gitcontext): regex = self.options['regex'].value pattern = re.compile(regex) if not pattern.search(title): violation_msg = "Title does not match regex ({0})".format(regex) return [RuleViolation(self.id, violation_msg, title)]
def test_str_option(self): # normal behavior option = StrOption("test-name", "bar", "Test Description") option.set("foo") self.assertEqual(option.value, "foo") # conversion to str option.set(123) self.assertEqual(option.value, "123") # conversion to str option.set(-123) self.assertEqual(option.value, "-123")
class TitleStartsWithSubsystem(LineRule): name = "title-starts-with-subsystem" id = "UC3" target = CommitMessageTitle options_spec = [StrOption('regex', ".*", "Regex the title should match")] def validate(self, title, _commit): regex = self.options['regex'].value pattern = re.compile(regex, re.UNICODE) violation_message = "Title does not follow [subsystem]: [subject] (and should not start with literal subsys:)" if not pattern.search(title): return [RuleViolation(self.id, violation_message, title)]
def test_str_option(self): # normal behavior option = StrOption(u"tëst-name", u"föo", u"Tëst Description") self.assertEqual(option.name, u"tëst-name") self.assertEqual(option.description, u"Tëst Description") self.assertEqual(option.value, u"föo") # re-set value option.set(u"bår") self.assertEqual(option.value, u"bår") # conversion to str option.set(123) self.assertEqual(option.value, "123") # conversion to str option.set(-123) self.assertEqual(option.value, "-123") # None value option.set(None) self.assertEqual(option.value, None)
class AuthorValidEmail(CommitRule): name = "author-valid-email" id = "M1" options_spec = [StrOption('regex', "[^@ ]+@[^@ ]+\.[^@ ]+", "Regex that author email address should match")] def validate(self, commit): # Note that unicode is allowed in email addresses # See http://stackoverflow.com/questions/3844431 # /are-email-addresses-allowed-to-contain-non-alphanumeric-characters email_regex = re.compile(self.options['regex'].value, re.UNICODE) if commit.author_email and not email_regex.match(commit.author_email): return [RuleViolation(self.id, "Author email for commit is invalid", commit.author_email)]
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"))
class TitleMatchRegexAllowException(LineRule): """Allows revert commits contrary to the built-in title-match-regex rule""" name = "title-match-regex-allow-exception" id = "Z2" target = CommitMessageTitle options_spec = [StrOption("regex", ".*", "Regex the title should match")] def validate(self, title: str, commit: GitCommit) -> List[RuleViolation]: regex = self.options["regex"].value pattern = re.compile(regex, re.UNICODE) if not pattern.search(title) and not title.startswith('Revert "'): violation_msg = f"Title does not match regex ({regex})" return [RuleViolation(self.id, violation_msg, title)] return []
class TitleMatchRegexAllowException(LineRule): """Allows revert commits contrary to the built-in title-match-regex rule""" name = 'title-match-regex-allow-exception' id = 'Z2' target = CommitMessageTitle options_spec = [StrOption('regex', ".*", "Regex the title should match")] def validate(self, title: Text, commit: GitCommit) -> List[RuleViolation]: regex = self.options['regex'].value pattern = re.compile(regex, re.UNICODE) if not pattern.search(title) and not title.startswith("Revert \""): violation_msg = "Title does not match regex ({})".format(regex) return [RuleViolation(self.id, violation_msg, title)] return []
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