8Integration tests for the auto-branching behaviour in ``oct git commit``
9(Phase 4F — G-F2): when committing on a protected branch, the command
10automatically creates a feature branch instead of blocking.
14- Verify auto-branch creates a correctly named feature branch from the
16- Verify the commit lands on the new branch, not on the protected branch.
17- Verify stderr reports the auto-branch action.
18- Verify ``git.auto_branch_on_protected: false`` disables auto-branching.
19- Verify branch name deduplication when the generated name already exists.
26 L3 -- assertion details
31- All tests use subprocess invocation (same pattern as test_git_commit.py).
32- All tests use tmp_path fixtures so they are automatically cleaned up.
39from pathlib
import Path
43from tests.tests_git.conftest
import _git, commit_file
52 return shutil.which(
"git")
is not None
55def _run_commit(root: Path, *extra_args: str) -> subprocess.CompletedProcess:
56 """Run ``oct git commit`` in a subprocess."""
57 return subprocess.run(
58 [sys.executable,
"-m",
"oct.cli",
"git",
"commit", *extra_args],
66 """Overwrite ``.octrc.json`` in *root*."""
67 (root /
".octrc.json").write_text(
68 json.dumps(octrc, indent=2), encoding=
"utf-8",
79 @pytest.mark.skipif(not _git_available(), reason=
"git not on PATH")
81 self, temp_git_project: Path, make_compliant_py,
83 """Commit on main auto-creates feature/... and succeeds."""
84 path = make_compliant_py(
"src/good.py")
85 _git(temp_git_project,
"add",
"src/good.py")
87 temp_git_project,
"-m",
"feat(auth): add JWT tokens",
89 assert result.returncode == 0, f
"stderr: {result.stderr}"
91 proc = _git(temp_git_project,
"rev-parse",
"--abbrev-ref",
"HEAD")
92 branch = proc.stdout.strip()
93 assert branch.startswith(
"feature/"), f
"expected feature/..., got {branch!r}"
94 assert "auth" in branch
96 assert "auto-created branch" in result.stderr.lower()
98 @pytest.mark.skipif(not _git_available(), reason=
"git not on PATH")
100 self, temp_git_project: Path, make_compliant_py,
102 """The commit message appears on the new branch, not main."""
103 path = make_compliant_py(
"src/module.py")
104 _git(temp_git_project,
"add",
"src/module.py")
105 _run_commit(temp_git_project,
"-m",
"fix: resolve null pointer")
107 proc = _git(temp_git_project,
"log",
"--oneline",
"-1")
108 assert "resolve null pointer" in proc.stdout
110 proc_main = _git(temp_git_project,
"log",
"main",
"--oneline",
"-1")
111 assert "resolve null pointer" not in proc_main.stdout
113 @pytest.mark.skipif(not _git_available(), reason=
"git not on PATH")
115 self, temp_git_project: Path, make_compliant_py,
117 """fix: message creates a bugfix/ branch."""
118 path = make_compliant_py(
"src/fix_it.py")
119 _git(temp_git_project,
"add",
"src/fix_it.py")
120 _run_commit(temp_git_project,
"-m",
"fix: patch memory leak")
121 proc = _git(temp_git_project,
"rev-parse",
"--abbrev-ref",
"HEAD")
122 assert proc.stdout.strip().startswith(
"bugfix/")
124 @pytest.mark.skipif(not _git_available(), reason=
"git not on PATH")
126 self, temp_git_project: Path, make_compliant_py,
128 """sec: message creates a hotfix/ branch."""
129 path = make_compliant_py(
"src/sec_fix.py")
130 _git(temp_git_project,
"add",
"src/sec_fix.py")
131 _run_commit(temp_git_project,
"-m",
"sec: patch CVE-2024-9999")
132 proc = _git(temp_git_project,
"rev-parse",
"--abbrev-ref",
"HEAD")
133 assert proc.stdout.strip().startswith(
"hotfix/")
135 @pytest.mark.skipif(not _git_available(), reason=
"git not on PATH")
137 self, temp_git_project: Path, make_compliant_py,
139 """auto_branch_on_protected=false preserves the blocking behaviour."""
141 "linter": {
"profile":
"compact"},
143 "protected_branches": [
"main",
"master"],
144 "auto_branch_on_protected":
False,
147 path = make_compliant_py(
"src/blocked.py")
148 _git(temp_git_project,
"add",
"src/blocked.py")
150 temp_git_project,
"-m",
"feat: should be blocked",
152 assert result.returncode == 1
153 assert "protected branch" in result.stderr.lower()
155 @pytest.mark.skipif(not _git_available(), reason=
"git not on PATH")
157 self, temp_git_project: Path, make_compliant_py,
159 """When the generated branch name already exists, append a counter."""
161 _git(temp_git_project,
"branch",
"feature/dup-test-feature")
162 path = make_compliant_py(
"src/dedup.py")
163 _git(temp_git_project,
"add",
"src/dedup.py")
165 temp_git_project,
"-m",
"feat: dup test feature",
167 assert result.returncode == 0, f
"stderr: {result.stderr}"
168 proc = _git(temp_git_project,
"rev-parse",
"--abbrev-ref",
"HEAD")
169 branch = proc.stdout.strip()
171 assert branch ==
"feature/dup-test-feature-2"
None test_auto_branch_fix_type(self, Path temp_git_project, make_compliant_py)
None test_auto_branch_disabled_blocks(self, Path temp_git_project, make_compliant_py)
None test_auto_branch_commit_lands_on_new_branch(self, Path temp_git_project, make_compliant_py)
None test_auto_branch_creates_feature_branch(self, Path temp_git_project, make_compliant_py)
None test_auto_branch_sec_type(self, Path temp_git_project, make_compliant_py)
None test_auto_branch_deduplication(self, Path temp_git_project, make_compliant_py)
subprocess.CompletedProcess _run_commit(Path root, *str extra_args)
None _set_octrc(Path root, dict octrc)