From 59e77759e6ae5019e55563d4713d9392ab5b6893 Mon Sep 17 00:00:00 2001 From: Carlos Vigo Date: Fri, 30 Jan 2026 11:38:16 +0100 Subject: [PATCH 1/6] test: add integration tests for valid and invalid branch names in commit process --- tests/test_integration.py | 112 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/tests/test_integration.py b/tests/test_integration.py index b21bf867..adc2d644 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -1473,6 +1473,118 @@ def test_github_cli_authentication(self, devcontainer_up): f"Expected 'Logged in to github.com' or similar in output" ) + def test_valid_branch_names_commit_succeeds(self, devcontainer_up): + """Valid branch names (convention) allow commits; passes with or without branch-name hook.""" + # Create dummy file to commit + workspace_path = devcontainer_up.resolve() + dummy_file = workspace_path / "dummy.txt" + dummy_file.write_text("dummy\n") + + # Define valid branch names + valid_branch_names = [ + "feature/123-test-branch", + "bugfix/123-test-branch", + "hotfix/123-test-branch", + "release/123-test-branch", + "docs/123-test-branch", + "test/123-test-branch", + "refactor/123-test-branch", + ] + + # Test valid branch names + for branch_name in valid_branch_names: + # Create branch and run pre-commit hook + exec_cmd = [ + "devcontainer", + "exec", + "--workspace-folder", + str(workspace_path), + "--config", + f"{workspace_path}/.devcontainer/devcontainer.json", + "--docker-path", + "podman", + "bash", + "-c", + ( + "cd /workspace/test_project" + " && printf 'dummy\\n' > dummy.txt" + f" && git checkout -b '{branch_name}'" + " && git add dummy.txt" + " && pre-commit run -a" + ), + ] + result = subprocess.run( + exec_cmd, + capture_output=True, + text=True, + cwd=str(workspace_path), + env=os.environ.copy(), + timeout=120, + ) + + assert result.returncode == 0, ( + f"pre-commit on valid branch '{branch_name}' should succeed\n" + f"stdout: {result.stdout}\n" + f"stderr: {result.stderr}\n" + f"command: {' '.join(exec_cmd)}" + ) + + def test_invalid_branch_names_commit_fails(self, devcontainer_up): + """Invalid branch names (convention) fail commits (branch-name pre-commit hook).""" + # Create dummy file to commit + workspace_path = devcontainer_up.resolve() + dummy_file = workspace_path / "dummy.txt" + dummy_file.write_text("dummy\n") + + invalid_branch_names = [ + "featur/123-typo", + "bugfix/missing-issue-number", + "hotfix/123", + "release123-missing-/", + "random-string", + ] + + for branch_name in invalid_branch_names: + exec_cmd = [ + "devcontainer", + "exec", + "--workspace-folder", + str(workspace_path), + "--config", + f"{workspace_path}/.devcontainer/devcontainer.json", + "--docker-path", + "podman", + "bash", + "-c", + ( + "cd /workspace/test_project" + " && printf 'dummy\\n' > dummy.txt" + f" && git checkout -b '{branch_name}'" + " && git add dummy.txt" + " && pre-commit run -a" + ), + ] + result = subprocess.run( + exec_cmd, + capture_output=True, + text=True, + cwd=str(workspace_path), + env=os.environ.copy(), + timeout=120, + ) + + assert result.returncode != 0, ( + f"pre-commit on invalid branch '{branch_name}' should fail\n" + f"stdout: {result.stdout}\n" + f"stderr: {result.stderr}\n" + f"command: {' '.join(exec_cmd)}" + ) + output = (result.stdout + result.stderr).lower() + assert "branch" in output or "no-commit-to-branch" in output, ( + f"Expected branch-name hook failure in output\n" + f"stdout: {result.stdout}\nstderr: {result.stderr}" + ) + class TestJustRecipes: """Test the just recipes.""" From 2436542e1a89be153856b1e61195db1e3bcb35be Mon Sep 17 00:00:00 2001 From: Carlos Vigo Date: Fri, 30 Jan 2026 11:39:22 +0100 Subject: [PATCH 2/6] feature: update pre-commit configuration with new hook for branch name enforcement --- assets/workspace/.pre-commit-config.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/assets/workspace/.pre-commit-config.yaml b/assets/workspace/.pre-commit-config.yaml index 98eba66b..1e8b056e 100644 --- a/assets/workspace/.pre-commit-config.yaml +++ b/assets/workspace/.pre-commit-config.yaml @@ -6,6 +6,15 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 hooks: + # Enforce topic branch naming: /- + # Allows main, dev, and branches matching the convention. + - id: no-commit-to-branch + name: branch-name (enforce /-) + args: + - --branch + - __none__ # override default so main/dev are not protected + - --pattern + - "^(?!main$)(?!dev$)(?!^(feature|bugfix|hotfix|release|docs|test|refactor)/[0-9]+-[a-z0-9]+(-[a-z0-9]+)*$).+$" - id: check-added-large-files - id: check-case-conflict - id: check-json From cbdeba95141a30b4438219cc99aac5a5b63f82b0 Mon Sep 17 00:00:00 2001 From: Carlos Vigo Date: Fri, 30 Jan 2026 11:42:52 +0100 Subject: [PATCH 3/6] feature: add Cursor rules for branch naming and issue development workflow guidelines --- .../workspace/.cursor/rules/branch-naming.mdc | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 assets/workspace/.cursor/rules/branch-naming.mdc diff --git a/assets/workspace/.cursor/rules/branch-naming.mdc b/assets/workspace/.cursor/rules/branch-naming.mdc new file mode 100644 index 00000000..506277be --- /dev/null +++ b/assets/workspace/.cursor/rules/branch-naming.mdc @@ -0,0 +1,55 @@ +--- +description: Topic branch naming and workflow for starting work on an issue +alwaysApply: true +--- + +# Topic Branch Naming and Workflow + +When the user asks to create or start work on an issue (e.g. "create branch for issue 36", "start working on issue 36", or references `.github_data/issues/issue-36.md`), follow this workflow. + +## Workflow: Create and link a development branch + +1. **Verify no developer branch is linked yet** + - Run: `gh issue develop --list ` + - If the issue already has a linked branch, tell the user and offer to checkout that branch locally (`git fetch origin && git checkout `) or stop. Do not create a second linked branch. + +2. **Infer branch type** + - From issue labels or intent, pick one: `feature` | `bugfix` | `hotfix` | `release` | `docs` | `test` | `refactor`. + - Ask the user if labels and title are ambiguous. + +3. **Set short summary** + - From the issue title or description, derive a kebab-case `short_summary` (a few words). + - Omit prefixes like "FEATURE", "BUG", "Add". Example: "Standardize and Enforce Commit Message Format" → `standardize-commit-messages`. + +4. **Propose branch name and ask for validation** + - Propose: `/-` (e.g. `feature/36-standardize-commit-messages`). + - Explicitly ask the user to confirm or give a different name before proceeding. + +5. **Create and link the branch via GitHub** + - After user confirms: `gh issue develop --base dev --name --checkout` + - This creates the branch on the remote from `dev`, links it to the issue, and checks it out locally. If `gh` reports that the branch already exists on the remote, run `git fetch origin` and `git checkout ` instead. + +6. **Ensure local branch is up to date** + - After checkout: `git pull origin ` (if the branch already had commits and you created it via another path, or to sync with remote). + +## Branch name format (reference) + +``` +/- +``` + +## Branch types (reference) + +| Type | Use for | +|----------|-------------------------------------------------------------------------| +| feature | New functionality, enhancements | +| bugfix | Bug fixes (non-urgent) | +| hotfix | Urgent production fixes, often merged outside normal release | +| release | Release preparation, version bumps, release notes | +| docs | Documentation only | +| test | Tests, CI, or test infrastructure | +| refactor | Code refactoring, no new behavior | + +## One-off branch name only + +When the user only wants a branch name suggestion (no "create" or "start work"), propose the name in the format above and do not run the full workflow. From dde1857c5cae2a1ec87ad740ea9d213e0211edd0 Mon Sep 17 00:00:00 2001 From: Carlos Vigo Date: Fri, 30 Jan 2026 11:43:32 +0100 Subject: [PATCH 4/6] feature: implement branch enforcement and Curosr rules in this repository --- .cursor/rules/branch-naming.mdc | 55 +++++++++++++++++++++++++++++++++ .pre-commit-config.yaml | 9 ++++++ 2 files changed, 64 insertions(+) create mode 100644 .cursor/rules/branch-naming.mdc diff --git a/.cursor/rules/branch-naming.mdc b/.cursor/rules/branch-naming.mdc new file mode 100644 index 00000000..506277be --- /dev/null +++ b/.cursor/rules/branch-naming.mdc @@ -0,0 +1,55 @@ +--- +description: Topic branch naming and workflow for starting work on an issue +alwaysApply: true +--- + +# Topic Branch Naming and Workflow + +When the user asks to create or start work on an issue (e.g. "create branch for issue 36", "start working on issue 36", or references `.github_data/issues/issue-36.md`), follow this workflow. + +## Workflow: Create and link a development branch + +1. **Verify no developer branch is linked yet** + - Run: `gh issue develop --list ` + - If the issue already has a linked branch, tell the user and offer to checkout that branch locally (`git fetch origin && git checkout `) or stop. Do not create a second linked branch. + +2. **Infer branch type** + - From issue labels or intent, pick one: `feature` | `bugfix` | `hotfix` | `release` | `docs` | `test` | `refactor`. + - Ask the user if labels and title are ambiguous. + +3. **Set short summary** + - From the issue title or description, derive a kebab-case `short_summary` (a few words). + - Omit prefixes like "FEATURE", "BUG", "Add". Example: "Standardize and Enforce Commit Message Format" → `standardize-commit-messages`. + +4. **Propose branch name and ask for validation** + - Propose: `/-` (e.g. `feature/36-standardize-commit-messages`). + - Explicitly ask the user to confirm or give a different name before proceeding. + +5. **Create and link the branch via GitHub** + - After user confirms: `gh issue develop --base dev --name --checkout` + - This creates the branch on the remote from `dev`, links it to the issue, and checks it out locally. If `gh` reports that the branch already exists on the remote, run `git fetch origin` and `git checkout ` instead. + +6. **Ensure local branch is up to date** + - After checkout: `git pull origin ` (if the branch already had commits and you created it via another path, or to sync with remote). + +## Branch name format (reference) + +``` +/- +``` + +## Branch types (reference) + +| Type | Use for | +|----------|-------------------------------------------------------------------------| +| feature | New functionality, enhancements | +| bugfix | Bug fixes (non-urgent) | +| hotfix | Urgent production fixes, often merged outside normal release | +| release | Release preparation, version bumps, release notes | +| docs | Documentation only | +| test | Tests, CI, or test infrastructure | +| refactor | Code refactoring, no new behavior | + +## One-off branch name only + +When the user only wants a branch name suggestion (no "create" or "start work"), propose the name in the format above and do not run the full workflow. diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d87c4887..f100967c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,6 +8,15 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 hooks: + # Enforce topic branch naming: /- + # Allows main, dev, and branches matching the convention. + - id: no-commit-to-branch + name: branch-name (enforce /-) + args: + - --branch + - __none__ # override default so main/dev are not protected + - --pattern + - "^(?!main$)(?!dev$)(?!^(feature|bugfix|hotfix|release|docs|test|refactor)/[0-9]+-[a-z0-9]+(-[a-z0-9]+)*$).+$" - id: check-added-large-files - id: check-case-conflict - id: check-json From 169f5818c8a9f3924336763f072edbf4c4d78f0d Mon Sep 17 00:00:00 2001 From: Carlos Vigo Date: Fri, 30 Jan 2026 11:47:35 +0100 Subject: [PATCH 5/6] chore: update devcontainer pre-commit configuration - Exclude issue and template docs from .github_data - Autofix shellcheck - Autofix pymarkdown - Add license compliance check --- assets/workspace/.pre-commit-config.yaml | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/assets/workspace/.pre-commit-config.yaml b/assets/workspace/.pre-commit-config.yaml index 1e8b056e..d567625b 100644 --- a/assets/workspace/.pre-commit-config.yaml +++ b/assets/workspace/.pre-commit-config.yaml @@ -1,6 +1,8 @@ --- # .pre-commit-config.yaml +exclude: ^\.github_data/ + repos: # General Pre-commit Hooks (Fixes formatting issues) - repo: https://github.com/pre-commit/pre-commit-hooks @@ -50,14 +52,15 @@ repos: hooks: - id: shellcheck name: shellcheck + args: ["-x"] - # Markdown Linting + # Markdown Linting (excludes auto-generated docs) - repo: https://github.com/jackdewinter/pymarkdown rev: v0.9.23 hooks: - id: pymarkdown name: pymarkdown - args: ["scan"] + args: ["-c", ".pymarkdown", "fix"] # Justfile formatting - repo: local @@ -75,13 +78,12 @@ repos: hooks: - id: typos - # Typstyle Linting + # License Compliance Check (runs only when dependencies change) - repo: local hooks: - - id: typstyle - name: typstyle - entry: typstyle + - id: pip-licenses + name: pip-licenses (check dependency licenses) + entry: uv run pip-licenses --fail-on="GPL-3.0-only;GPL-3.0-or-later;AGPL-3.0-only;AGPL-3.0-or-later" language: system - files: ^.*\.typ$ - pass_filenames: true - args: [--inplace] + files: ^(pyproject\.toml|uv\.lock|requirements.*\.txt)$ + pass_filenames: false From decfc07a3ad740de72e8b34396f7f3d3c787bcf7 Mon Sep 17 00:00:00 2001 From: Carlos Vigo Date: Fri, 30 Jan 2026 14:20:36 +0100 Subject: [PATCH 6/6] docs: update CHANGELOG - Added pre-commit hook for enforcing branch naming convention - Updated pre-commit configuration in the repository and workspace - Included integration tests for branch name validation - Documented cursor rules for branch naming and issue workflow --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97ab50a7..f1ded353 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,8 +9,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- **Branch name enforcement as a pre-commit hook** + - New `branch-name` hook enforcing `/-` convention (e.g. `feature/38-standardize-branching-strategy-enforcement`) + - Pre-commit configuration updated in repo and in workspace assets (`.pre-commit-config.yaml`, `assets/workspace/.pre-commit-config.yaml`) + - Integration tests added for valid and invalid branch names +- **Cursor rules for branch naming and issue workflow** + - `.cursor/rules/branch-naming.mdc`: topic branch naming format, branch types, workflow for creating/linking branches via `gh issue develop` + - Guidelines for inferring branch type from issue labels and deriving short summary from issue title + ### Changed +- **Updated pre-commit hook configuration in the devcontainer** + - Exclude issue and template docs from .github_data + - Autofix shellcheck + - Autofix pymarkdown + - Add license compliance check + ### Deprecated ### Removed