1from gitlint.rules import LineRule, RuleViolation, CommitMessageTitle 2import re 3 4 5class TitleStartsWithComponent(LineRule): 6 """A rule to enforce valid commit message title 7 8 Valid title format: 9 component1[, component2, componentN]: submodule: summary 10 11 Title should have at least one component 12 Components are separated by comma+space: ", " 13 Components are validated to be in valid_components 14 Components list is ended by a colon 15 Submodules are not validated 16 17 """ 18 19 # A rule MUST have a human friendly name 20 name = "title-has-valid-component" 21 22 # A rule MUST have a *unique* id. 23 # We recommend starting with UL (for User-defined Line-rule) 24 id = "UL1" 25 26 # A line-rule MUST have a target (not required for CommitRules). 27 target = CommitMessageTitle 28 29 def validate(self, line, _commit): 30 valid_components = ( 31 'api_client', 32 'arch', 33 'block', 34 'build', 35 'ch-remote', 36 'ci', 37 'devices', 38 'docs', 39 'event_monitor', 40 'fuzz', 41 'github', 42 'gitignore', 43 'gitlint', 44 'hypervisor', 45 'main', 46 'misc', 47 'net_gen', 48 'net_util', 49 'option_parser', 50 'pci', 51 'performance-metrics', 52 'rate_limiter', 53 'README', 54 'resources', 55 'scripts', 56 'serial_buffer', 57 'test_data', 58 'test_infra', 59 'tests', 60 'tpm', 61 'tracer', 62 'vhost_user_block', 63 'vhost_user_net', 64 'virtio-devices', 65 'vm-allocator', 66 'vm-device', 67 'vmm', 68 'vm-migration', 69 'vm-virtio') 70 71 ptrn_title = re.compile(r'^(.+?):\s(.+)$') 72 match = ptrn_title.match(line) 73 74 if not match: 75 self.log.debug("Invalid commit title {}", line) 76 return [RuleViolation(self.id, "Commit title does not comply with " 77 "rule: 'component: change summary'")] 78 components = match.group(1) 79 summary = match.group(2) 80 self.log.debug(f"\nComponents: {components}\nSummary: {summary}") 81 82 ptrn_components = re.compile(r',\s') 83 components_list = re.split(ptrn_components, components) 84 self.log.debug("components list: %s" % components_list) 85 86 for component in components_list: 87 if component not in valid_components: 88 return [RuleViolation(self.id, 89 f"Invalid component: {component}, " 90 "\nValid components are: {}".format( 91 " ".join(valid_components)))] 92