diff --git a/README.md b/README.md index 3f2e6b5..1ed5350 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,30 @@ The commit will also be flagged if the commit message does not include a Jira ID (unless marked with NO_JIRA or a Copilot Autofix co-author line), or if the size of new or modified files exceeds a threshold. +## Conventional Commits + +Conventional Commits validation is optional. Add a `.conventional-commits` file +at the repository root to enable it. The supported header format is: + +```text +: +(): +``` + +Examples: + +```text +fix: handle an empty search response +feat(PLA-0001): add structure filtering +break(NO_JIRA): remove the legacy search endpoint +``` + +Supported types are `break`, `feat`, `fix`, `refactor`, `build`, `chore`, `ci`, +`docs`, `perf`, `revert`, `style`, and `test`. CCDC release configurations use +`break` for a major version. A branch may contain more than one type. +Releases should choose the highest required version bump, +so `break` takes precedence over `feat`, which takes precedence over `fix`. + # GitHub Actions diff --git a/main/githooks.py b/main/githooks.py index 035d75e..7059823 100644 --- a/main/githooks.py +++ b/main/githooks.py @@ -960,11 +960,6 @@ def check_commit_msg(message, files, repo): # Not checking for JIRA or large file in commit message generated by github return 0 - if re.match(r'^ccdc-opensource/', 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. # Opt-in per repo: commit an empty marker file named # `.conventional-commits` at the repo root. @@ -977,6 +972,8 @@ def check_commit_msg(message, files, repo): return 1 if ( + not re.match(r'^ccdc-opensource/', repo) + and NO_JIRA_MARKER not in message and copilot_autofix_coauthor_pattern.search(message) is None and jira_id_pattern.search(message) is None @@ -1071,6 +1068,28 @@ def _test(input, is_good=True): _test('I forgot to add the jira marker!', False) _test('Close but no cigar abc-1234', False) + @patch('githooks._conventional_commits_enabled', return_value=True) + def test_opensource_repo_still_checks_conventional_commit(self, _enabled): + self.assertEqual(0, check_commit_msg('feat: valid change', [], 'ccdc-opensource/example')) + self.assertEqual(1, check_commit_msg('invalid: invalid change', [], 'ccdc-opensource/example')) + + +class TestConventionalCommitPresent(unittest.TestCase): + def test_supported_types(self): + for commit_type in ( + 'break', 'feat', 'fix', 'refactor', 'build', 'chore', 'ci', + 'docs', 'perf', 'revert', 'style', 'test' + ): + with self.subTest(commit_type=commit_type): + self.assertTrue(conventional_commit_present(f'{commit_type}: subject')) + + def test_scope_and_multiline_description(self): + self.assertTrue(conventional_commit_present('feat(api): subject\n\nMore detail')) + + def test_unsupported_type(self): + self.assertFalse(conventional_commit_present('invalid(PLA-3474): test')) + self.assertFalse(conventional_commit_present('breaking-change: test')) + def run_licence_check(files): '''Check or fix complete CCDC licence headers.