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