Commit c59fa17b authored by Adrian DC's avatar Adrian DC
Browse files

chore(hooks): implement evaluators and matchers priority parser

Signed-off-by: default avatarAdrian DC <radian.dc@gmail.com>
parent f745f7e8
Loading
Loading
Loading
Loading
+17 −10
Changes for .hooks/configurations.py: 17 added lines, 10 removed lines.
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ ChangesRegex = str
# Changes parsers class
class ChangesParsers(NamedTuple):
    match: str
    group: int
    groups: List[int]
    commit_type: str

# Changes evaluator class
@@ -43,6 +43,12 @@ COMMITS_DEFAULT_TYPE: str = 'type'
# Commits footers constants
COMMITS_FOOTER_SIGNOFF: str = 'Signed-off-by: '

# Regex constants
REGEX_EXT: str = r'[^/.]*'
REGEX_FOLDER: str = r'[^/]+'
REGEX_STEM: str = r'[^/]+'
REGEX_STEM_VISIBLE: str = r'[^/_\.]{1}[^/]+'

# Changes evaluators constants
CHANGES_EVALUATORS: List[ChangesEvaluator] = [
    # Sources
@@ -52,8 +58,9 @@ CHANGES_EVALUATORS: List[ChangesEvaluator] = [
        ],
        parsers=[
            ChangesParsers(
                match=r'.*/([^_]{1}[^/]*)\.[^/]*$',
                group=1,
                match=
                fr'(({REGEX_FOLDER})/)?(({REGEX_FOLDER})/)?({REGEX_STEM_VISIBLE})\.{REGEX_EXT}$',
                groups=[5, 4, 2],
                commit_type='fix',
            ),
        ],
@@ -61,17 +68,17 @@ CHANGES_EVALUATORS: List[ChangesEvaluator] = [
    # Yocto
    ChangesEvaluator(
        changes=[
            r'conf/(distro|machine)|recipes-[^/*]',
            fr'conf/(distro|machine)|recipes-{REGEX_STEM}',
        ],
        parsers=[
            ChangesParsers(
                match=r'conf/(distro|machine)/[^/]*.conf$',
                group=1,
                match=fr'conf/(distro|machine)/{REGEX_STEM}.conf$',
                groups=[1],
                commit_type='fix',
            ),
            ChangesParsers(
                match=r'.*/([^/]*)/[^/]*\.(bb[^/.]*|inc)$',
                group=1,
                match=fr'({REGEX_STEM})/{REGEX_STEM}\.(bb[^/.]*|inc)$',
                groups=[1],
                commit_type='fix',
            ),
        ],
@@ -93,12 +100,12 @@ CHANGES_MATCHERS: List[ChangesMatcher] = [
        ],
    ),
    ChangesMatcher(
        commit_scope='githooks',
        commit_scope='hooks',
        types=[
            ChangesType(
                commit_type='chore',
                changes=[
                    r'\.githooks$',
                    r'^\.hooks',
                ],
            ),
        ],
+58 −8
Changes for .hooks/prepare_commit_msg_template.py: 58 added lines, 8 removed lines.
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@ from pathlib import Path
from re import match, search
import sys
from sys import argv, exit as sys_exit, path
from typing import List, Optional, Tuple
from typing import List, NamedTuple, Optional, Tuple

# Bind sources
sys.dont_write_bytecode = True
@@ -74,29 +74,79 @@ def parse_commit_input(filepath: str) -> Tuple[bool, bool, str, List[str]]:
    # Result
    return empty, signoff, linesep.join(context), changes

# Prepare commit title, pylint: disable=too-many-nested-blocks
# Prepare commit title, pylint: disable=too-many-branches,too-many-locals,too-many-nested-blocks
def prepare_commit_title(changes: List[str]) -> Tuple[str, str]:

    # Types
    Result = NamedTuple('Result', [
        ('priority', int),
        ('level', int),
        ('commit_type', str),
        ('commit_scope', str),
    ])

    # Variables
    commit_scope: str = COMMITS_DEFAULT_SCOPE
    commit_type: str = COMMITS_DEFAULT_TYPE
    level: int
    levels: List[int]
    priority: int = 0
    results: List[Result] = []

    # Evaluate common changes
    for changes_evaluator in CHANGES_EVALUATORS:
        priority += 1
        for type_change in changes_evaluator.changes:
            for change in changes:
                if search(type_change, change):
                if not search(type_change, change):
                    continue
                for parser in changes_evaluator.parsers:
                        matches = match(parser.match, change)
                        if matches and isinstance(matches.lastindex, int) >= parser.group:
                            return parser.commit_type, matches.group(parser.group)
                    matches = search(parser.match, change)
                    if not matches or not isinstance(matches.lastindex, int):
                        continue
                    level = 0
                    for group in parser.groups:
                        level += 1
                        if matches.lastindex >= group:
                            results += [
                                Result(
                                    priority=priority,
                                    level=level,
                                    commit_type=parser.commit_type,
                                    commit_scope=matches.group(group),
                                )
                            ]

    # Match common changes
    for changes_matcher in CHANGES_MATCHERS:
        priority += 1
        for matcher_type in changes_matcher.types:
            for type_change in matcher_type.changes:
                for change in changes:
                    if search(type_change, change):
                        return matcher_type.commit_type, changes_matcher.commit_scope
                        results += [
                            Result(
                                priority=priority,
                                level=0,
                                commit_type=matcher_type.commit_type,
                                commit_scope=changes_matcher.commit_scope,
                            )
                        ]

    # Parse results
    if results:
        priority = min((result.priority for result in results))
        results = [result for result in set(results) if result.priority == priority]
        levels = sorted([result.level for result in results])
        level = min((level for level in set(levels) if levels.count(level) == 1),
                    default=levels[-1])
        for result in [result for result in set(results) if result.level == level]:
            commit_type = result.commit_type
            commit_scope = result.commit_scope
            break

    # Result
    return COMMITS_DEFAULT_TYPE, COMMITS_DEFAULT_SCOPE
    return commit_type, commit_scope

# Prepare commit message
def prepare_commit_template(