From add2d87ac6dec73b74c5611d9d2de041364ddd24 Mon Sep 17 00:00:00 2001 From: Silvia Donati Date: Tue, 12 May 2026 11:09:27 +0100 Subject: [PATCH 1/6] add support conventional commit (NO_JIRA) --- main/githooks.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/main/githooks.py b/main/githooks.py index d795068..66a9aa8 100755 --- a/main/githooks.py +++ b/main/githooks.py @@ -854,6 +854,11 @@ def check_commit_msg(message, files, repo): # Do not check for JIRA in opensource repo as we don't want to require external contributors to do this return 0 + + # Check for Conventional Commits compliance + if check_conventional_commit(message): + return 1 + if NO_JIRA_MARKER not in message: if jira_id_pattern.search(message) is None: _fail('Every commit should contain a Jira issue ID or the text ' @@ -874,6 +879,25 @@ def check_commit_msg(message, files, repo): jira_id_pattern = re.compile(r'\b[A-Z]{2,8}-[0-9]{1,5}\b') + +def check_conventional_commit(message): + '''Check if the commit message follows the Conventional Commits standard.''' + # Conventional Commits: type(scope?): subject\n\nbody\n\nfooter + # type: feat, fix, chore, docs, style, refactor, perf, test, build, ci, revert, etc. + pattern = re.compile( + r'^(feat|fix|chore|docs|style|refactor|perf|test|build|ci|revert)' # type + r'(\([\w\-]+\))?' # optional scope + r'!?: ' # optional breaking change indicator and colon + r'.+' # subject + ) + first_line = message.split('\n', 1)[0] + if not pattern.match(first_line): + _fail('Commit message does not follow Conventional Commits standard.\n' + 'See https://www.conventionalcommits.org/en/v1.0.0/') + return 1 + return 0 + + class TestJiraIDPattern(unittest.TestCase): def test_various_strings(self): def _test(input, is_jira=True): From fb4f7915758708c77173aaaf62192cbc082ba9a0 Mon Sep 17 00:00:00 2001 From: Silvia Donati Date: Fri, 29 May 2026 15:04:28 +0100 Subject: [PATCH 2/6] change conventional commit check to reflect angular conventions (NO_JIRA) --- main/githooks.py | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/main/githooks.py b/main/githooks.py index 66a9aa8..4f4fdc9 100755 --- a/main/githooks.py +++ b/main/githooks.py @@ -855,9 +855,12 @@ def check_commit_msg(message, files, repo): return 0 - # Check for Conventional Commits compliance - if check_conventional_commit(message): - return 1 + # Check for Conventional Commits compliance. + # Opt-in per repo: commit an empty marker file named + # `.conventional-commits` at the repo root. + if _conventional_commits_enabled(): + if check_conventional_commit(message): + return 1 if NO_JIRA_MARKER not in message: if jira_id_pattern.search(message) is None: @@ -880,20 +883,35 @@ def check_commit_msg(message, files, repo): +def _conventional_commits_enabled(): + '''Return True if the repo opts in to Conventional Commits enforcement. + + Opt-in is signalled by a `.conventional-commits` file at the repo root. + ''' + try: + repo_root = _get_output(['git', 'rev-parse', '--show-toplevel']).strip() + except subprocess.CalledProcessError: + return False + return (Path(repo_root) / '.conventional-commits').is_file() + + def check_conventional_commit(message): - '''Check if the commit message follows the Conventional Commits standard.''' - # Conventional Commits: type(scope?): subject\n\nbody\n\nfooter - # type: feat, fix, chore, docs, style, refactor, perf, test, build, ci, revert, etc. + '''Check if the commit message follows the Angular Conventional Commits standard.''' + # Angular Conventional Commits header: type(scope?)!?: subject + # Allowed types from @commitlint/config-angular: + # build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test pattern = re.compile( - r'^(feat|fix|chore|docs|style|refactor|perf|test|build|ci|revert)' # type - r'(\([\w\-]+\))?' # optional scope - r'!?: ' # optional breaking change indicator and colon + r'^(BREAKING CHANGE|feat|fix|refactor|build|chore|ci|docs|perf|revert|style|test)' # type + r'(\([\w\-\.\/]+\))?' # optional scope + r'!?: ' # optional breaking change indicator and required ": " r'.+' # subject ) first_line = message.split('\n', 1)[0] if not pattern.match(first_line): - _fail('Commit message does not follow Conventional Commits standard.\n' - 'See https://www.conventionalcommits.org/en/v1.0.0/') + _fail('Commit message does not follow the Angular Conventional ' + 'Commits standard.\n' + 'Expected: ()?!?: \n' + 'See https://github.com/angular/angular/blob/main/contributing-docs/commit-message-guidelines.md') return 1 return 0 From cbbc1e400d758969016831b1b6472c4b44fcdf15 Mon Sep 17 00:00:00 2001 From: Silvia Donati Date: Tue, 2 Jun 2026 14:44:34 +0100 Subject: [PATCH 3/6] remove ! as not in angular commit convention (NO_JIRA) --- main/githooks.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/main/githooks.py b/main/githooks.py index 4f4fdc9..075be02 100755 --- a/main/githooks.py +++ b/main/githooks.py @@ -897,20 +897,21 @@ def _conventional_commits_enabled(): def check_conventional_commit(message): '''Check if the commit message follows the Angular Conventional Commits standard.''' - # Angular Conventional Commits header: type(scope?)!?: subject + # Angular Conventional Commits header: type(scope?): subject # Allowed types from @commitlint/config-angular: # build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test + # Note: Angular does not use the `!` breaking-change marker in the header; pattern = re.compile( r'^(BREAKING CHANGE|feat|fix|refactor|build|chore|ci|docs|perf|revert|style|test)' # type r'(\([\w\-\.\/]+\))?' # optional scope - r'!?: ' # optional breaking change indicator and required ": " + r': ' # required ": " r'.+' # subject ) first_line = message.split('\n', 1)[0] if not pattern.match(first_line): _fail('Commit message does not follow the Angular Conventional ' 'Commits standard.\n' - 'Expected: ()?!?: \n' + 'Expected: ()?: \n' 'See https://github.com/angular/angular/blob/main/contributing-docs/commit-message-guidelines.md') return 1 return 0 From 0b0647dfe43c8641b359857982da0caa9dc2d1b1 Mon Sep 17 00:00:00 2001 From: Silvia Donati Date: Tue, 2 Jun 2026 15:03:28 +0100 Subject: [PATCH 4/6] fix commit merge (PLA-3204) --- main/githooks.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/main/githooks.py b/main/githooks.py index 820a419..a17e8da 100644 --- a/main/githooks.py +++ b/main/githooks.py @@ -867,7 +867,6 @@ def check_commit_msg(message, files, repo): if check_conventional_commit(message): return 1 - if ( NO_JIRA_MARKER not in message and copilot_autofix_coauthor_pattern.search(message) is None @@ -877,14 +876,6 @@ def check_commit_msg(message, files, repo): 'Every commit should contain a Jira issue ID, ' f'{NO_JIRA_MARKER}, or be a Copilot Autofix commit' ) - if ( - NO_JIRA_MARKER not in message - and copilot_autofix_coauthor_pattern.search(message) is None - and jira_id_pattern.search(message) is None - ): - _fail( - 'Every commit should contain a Jira issue ID, ' - f'{NO_JIRA_MARKER}, or be a Copilot Autofix commit' return 1 for filename in files: From 603138cca5050ebd1b5c51384b5ea8a4a3e91ef8 Mon Sep 17 00:00:00 2001 From: Silvia Donati Date: Wed, 3 Jun 2026 14:12:54 +0100 Subject: [PATCH 5/6] fix(PLA-3204): PR feedback, change check conventional commit present --- main/githooks.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/main/githooks.py b/main/githooks.py index a17e8da..82ef6a7 100644 --- a/main/githooks.py +++ b/main/githooks.py @@ -864,7 +864,11 @@ def check_commit_msg(message, files, repo): # Opt-in per repo: commit an empty marker file named # `.conventional-commits` at the repo root. if _conventional_commits_enabled(): - if check_conventional_commit(message): + if not conventional_commit_present(message): + _fail('Commit message does not follow the Angular Conventional ' + 'Commits standard.\n' + 'Expected: ()?: \n' + 'See https://github.com/angular/angular/blob/main/contributing-docs/commit-message-guidelines.md') return 1 if ( @@ -905,8 +909,8 @@ def _conventional_commits_enabled(): return (Path(repo_root) / '.conventional-commits').is_file() -def check_conventional_commit(message): - '''Check if the commit message follows the Angular Conventional Commits standard.''' +def conventional_commit_present(message): + '''Return True if the commit message follows the Angular Conventional Commits standard.''' # Angular Conventional Commits header: type(scope?): subject # Allowed types from @commitlint/config-angular: # build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test @@ -918,13 +922,7 @@ def check_conventional_commit(message): r'.+' # subject ) first_line = message.split('\n', 1)[0] - if not pattern.match(first_line): - _fail('Commit message does not follow the Angular Conventional ' - 'Commits standard.\n' - 'Expected: ()?: \n' - 'See https://github.com/angular/angular/blob/main/contributing-docs/commit-message-guidelines.md') - return 1 - return 0 + return pattern.match(first_line) is not None class TestJiraIDPattern(unittest.TestCase): From ec9815d727254718d3c530bc1eeca38b39c30d95 Mon Sep 17 00:00:00 2001 From: Silvia Donati Date: Wed, 3 Jun 2026 14:17:56 +0100 Subject: [PATCH 6/6] fix(PLA-3204): PR feedback, remove try catch so if it's failing for different reason that the check itself will stop processing --- main/githooks.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/main/githooks.py b/main/githooks.py index 82ef6a7..c10ff2e 100644 --- a/main/githooks.py +++ b/main/githooks.py @@ -902,10 +902,7 @@ def _conventional_commits_enabled(): Opt-in is signalled by a `.conventional-commits` file at the repo root. ''' - try: - repo_root = _get_output(['git', 'rev-parse', '--show-toplevel']).strip() - except subprocess.CalledProcessError: - return False + repo_root = _get_output(['git', 'rev-parse', '--show-toplevel']).strip() return (Path(repo_root) / '.conventional-commits').is_file()