1ea7999e0SRuslan Mstoifrom gitlint.rules import LineRule, RuleViolation, CommitMessageTitle 2ea7999e0SRuslan Mstoiimport re 3ea7999e0SRuslan Mstoi 4ea7999e0SRuslan Mstoi 5ea7999e0SRuslan Mstoiclass TitleStartsWithComponent(LineRule): 6851ab0adSRuslan Mstoi """A rule to enforce valid commit message title 7851ab0adSRuslan Mstoi 8851ab0adSRuslan Mstoi Valid title format: 9851ab0adSRuslan Mstoi component1[, component2, componentN]: submodule: summary 10851ab0adSRuslan Mstoi 11851ab0adSRuslan Mstoi Title should have at least one component 12851ab0adSRuslan Mstoi Components are separated by comma+space: ", " 13851ab0adSRuslan Mstoi Components are validated to be in valid_components 14851ab0adSRuslan Mstoi Components list is ended by a colon 15851ab0adSRuslan Mstoi Submodules are not validated 16851ab0adSRuslan 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): 30851ab0adSRuslan 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', 4566f8841bSMuminul Islam 'main', 46ea7999e0SRuslan Mstoi 'misc', 47ea7999e0SRuslan Mstoi 'net_gen', 48ea7999e0SRuslan Mstoi 'net_util', 49*8a80bea4SRuslan Mstoi 'openapi', 50ea7999e0SRuslan Mstoi 'option_parser', 51ea7999e0SRuslan Mstoi 'pci', 52ea7999e0SRuslan Mstoi 'performance-metrics', 53ea7999e0SRuslan Mstoi 'rate_limiter', 54ea7999e0SRuslan Mstoi 'README', 55ea7999e0SRuslan Mstoi 'resources', 56ea7999e0SRuslan Mstoi 'scripts', 57ea7999e0SRuslan Mstoi 'serial_buffer', 58ea7999e0SRuslan Mstoi 'test_data', 59ea7999e0SRuslan Mstoi 'test_infra', 60ea7999e0SRuslan Mstoi 'tests', 61ea7999e0SRuslan Mstoi 'tpm', 62ea7999e0SRuslan Mstoi 'tracer', 63ea7999e0SRuslan Mstoi 'vhost_user_block', 64ea7999e0SRuslan Mstoi 'vhost_user_net', 65ea7999e0SRuslan Mstoi 'virtio-devices', 66ea7999e0SRuslan Mstoi 'vm-allocator', 67ea7999e0SRuslan Mstoi 'vm-device', 68ea7999e0SRuslan Mstoi 'vmm', 69ea7999e0SRuslan Mstoi 'vm-migration', 70851ab0adSRuslan Mstoi 'vm-virtio') 71ea7999e0SRuslan Mstoi 72851ab0adSRuslan Mstoi ptrn_title = re.compile(r'^(.+?):\s(.+)$') 73851ab0adSRuslan Mstoi match = ptrn_title.match(line) 74ea7999e0SRuslan Mstoi 75ea7999e0SRuslan Mstoi if not match: 76ea7999e0SRuslan Mstoi self.log.debug("Invalid commit title {}", line) 77ea7999e0SRuslan Mstoi return [RuleViolation(self.id, "Commit title does not comply with " 78ea7999e0SRuslan Mstoi "rule: 'component: change summary'")] 79851ab0adSRuslan Mstoi components = match.group(1) 80ea7999e0SRuslan Mstoi summary = match.group(2) 81851ab0adSRuslan Mstoi self.log.debug(f"\nComponents: {components}\nSummary: {summary}") 82ea7999e0SRuslan Mstoi 83851ab0adSRuslan Mstoi ptrn_components = re.compile(r',\s') 84851ab0adSRuslan Mstoi components_list = re.split(ptrn_components, components) 85851ab0adSRuslan Mstoi self.log.debug("components list: %s" % components_list) 86851ab0adSRuslan Mstoi 87851ab0adSRuslan Mstoi for component in components_list: 88ea7999e0SRuslan Mstoi if component not in valid_components: 89ea7999e0SRuslan Mstoi return [RuleViolation(self.id, 90ea7999e0SRuslan Mstoi f"Invalid component: {component}, " 91851ab0adSRuslan Mstoi "\nValid components are: {}".format( 92851ab0adSRuslan Mstoi " ".join(valid_components)))] 93