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