xref: /cloud-hypervisor/scripts/gitlint/rules/TitleStartsWithComponent.py (revision d580ed55c6b0785aecae9de400f3dab484bb4bd6)
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            'seccomp',
60            'serial_buffer',
61            'test_data',
62            'test_infra',
63            'tests',
64            'tpm',
65            'tracer',
66            'vhost_user_block',
67            'vhost_user_net',
68            'virtio-devices',
69            'vm-allocator',
70            'vm-device',
71            'vmm',
72            'vm-migration',
73            'vm-virtio')
74
75        ptrn_title = re.compile(r'^(.+?):\s(.+)$')
76        match = ptrn_title.match(line)
77
78        if not match:
79            self.log.debug("Invalid commit title {}", line)
80            return [RuleViolation(self.id, "Commit title does not comply with "
81                                  "rule: 'component: change summary'")]
82        components = match.group(1)
83        summary = match.group(2)
84        self.log.debug(f"\nComponents: {components}\nSummary: {summary}")
85
86        ptrn_components = re.compile(r',\s')
87        components_list = re.split(ptrn_components, components)
88        self.log.debug("components list: %s" % components_list)
89
90        for component in components_list:
91            if component not in valid_components:
92                return [RuleViolation(self.id,
93                                      f"Invalid component: {component}, "
94                                      "\nValid components are: {}".format(
95                                          " ".join(valid_components)))]
96