Skip to content

Commit 7963041

Browse files
committed
CM-53811: unified commit range parse
1 parent c0bf190 commit 7963041

File tree

3 files changed

+75
-22
lines changed

3 files changed

+75
-22
lines changed

cycode/cli/apps/scan/commit_range_scanner.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@
2626
get_diff_file_path,
2727
get_pre_commit_modified_documents,
2828
get_safe_head_reference_for_diff,
29-
parse_commit_range_sast,
30-
parse_commit_range_sca,
29+
parse_commit_range,
3130
)
3231
from cycode.cli.files_collector.documents_walk_ignore import filter_documents_with_cycodeignore
3332
from cycode.cli.files_collector.file_excluder import excluder
@@ -187,7 +186,7 @@ def _scan_commit_range_documents(
187186
def _scan_sca_commit_range(ctx: typer.Context, repo_path: str, commit_range: str, **_) -> None:
188187
scan_parameters = get_scan_parameters(ctx, (repo_path,))
189188

190-
from_commit_rev, to_commit_rev = parse_commit_range_sca(commit_range, repo_path)
189+
from_commit_rev, to_commit_rev = parse_commit_range(commit_range, repo_path)
191190
from_commit_documents, to_commit_documents, _ = get_commit_range_modified_documents(
192191
ctx.obj['progress_bar'], ScanProgressBarSection.PREPARE_LOCAL_FILES, repo_path, from_commit_rev, to_commit_rev
193192
)
@@ -228,7 +227,7 @@ def _scan_secret_commit_range(
228227
def _scan_sast_commit_range(ctx: typer.Context, repo_path: str, commit_range: str, **_) -> None:
229228
scan_parameters = get_scan_parameters(ctx, (repo_path,))
230229

231-
from_commit_rev, to_commit_rev = parse_commit_range_sast(commit_range, repo_path)
230+
from_commit_rev, to_commit_rev = parse_commit_range(commit_range, repo_path)
232231
_, commit_documents, diff_documents = get_commit_range_modified_documents(
233232
ctx.obj['progress_bar'],
234233
ScanProgressBarSection.PREPARE_LOCAL_FILES,

cycode/cli/files_collector/commit_range_documents.py

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -408,22 +408,7 @@ def get_pre_commit_modified_documents(
408408
return git_head_documents, pre_committed_documents, diff_documents
409409

410410

411-
def parse_commit_range_sca(commit_range: str, path: str) -> tuple[Optional[str], Optional[str]]:
412-
# FIXME(MarshalX): i truly believe that this function does NOT work as expected
413-
# it does not handle cases like 'A..B' correctly
414-
# i leave it as it for SCA to not break anything
415-
# the more correct approach is implemented for SAST
416-
from_commit_rev = to_commit_rev = None
417-
418-
for commit in git_proxy.get_repo(path).iter_commits(rev=commit_range):
419-
if not to_commit_rev:
420-
to_commit_rev = commit.hexsha
421-
from_commit_rev = commit.hexsha
422-
423-
return from_commit_rev, to_commit_rev
424-
425-
426-
def parse_commit_range_sast(commit_range: str, path: str) -> tuple[Optional[str], Optional[str]]:
411+
def parse_commit_range(commit_range: str, path: str) -> tuple[Optional[str], Optional[str]]:
427412
"""Parses a git commit range string and returns the full SHAs for the 'from' and 'to' commits.
428413
429414
Supports:

tests/cli/files_collector/test_commit_range_documents.py

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
get_diff_file_path,
1616
get_safe_head_reference_for_diff,
1717
parse_pre_push_input,
18+
parse_commit_range,
1819
)
1920
from cycode.cli.utils.path_utils import get_path_by_os
2021

@@ -539,8 +540,12 @@ def test_calculate_range_for_new_branch_with_merge_base(self) -> None:
539540
repo.index.add(['feature.py'])
540541
feature_commit = repo.index.commit('Add feature')
541542

542-
# Switch back to master to simulate we're pushing a feature branch
543-
repo.heads.master.checkout()
543+
# Switch back to the default branch to simulate pushing the feature branch
544+
# Prefer 'main' when present; fallback to 'master'.
545+
if any(h.name == 'main' for h in repo.heads):
546+
repo.heads.main.checkout()
547+
else:
548+
repo.heads.master.checkout()
544549

545550
# Test new branch push
546551
push_details = f'refs/heads/feature {feature_commit.hexsha} refs/heads/feature {consts.EMPTY_COMMIT_SHA}'
@@ -805,3 +810,67 @@ def test_simulate_pre_push_hook_input_format(self) -> None:
805810
parts = push_input.split()
806811
expected_range = f'{parts[3]}..{parts[1]}'
807812
assert commit_range == expected_range
813+
814+
815+
class TestParseCommitRange:
816+
"""Tests to validate unified parse_commit_range behavior matches git semantics."""
817+
818+
def _make_linear_history(self, repo: Repo, base_dir: str) -> tuple[str, str, str]:
819+
"""Create three linear commits A -> B -> C and return their SHAs."""
820+
a_file = os.path.join(base_dir, 'a.txt')
821+
with open(a_file, 'w') as f:
822+
f.write('A')
823+
repo.index.add(['a.txt'])
824+
a = repo.index.commit('A')
825+
826+
with open(a_file, 'a') as f:
827+
f.write('B')
828+
repo.index.add(['a.txt'])
829+
b = repo.index.commit('B')
830+
831+
with open(a_file, 'a') as f:
832+
f.write('C')
833+
repo.index.add(['a.txt'])
834+
c = repo.index.commit('C')
835+
836+
return a.hexsha, b.hexsha, c.hexsha
837+
838+
def test_two_dot_linear_history(self) -> None:
839+
"""For 'A..C', expect (A,C) in linear history."""
840+
with temporary_git_repository() as (temp_dir, repo):
841+
a, b, c = self._make_linear_history(repo, temp_dir)
842+
843+
parsed_from, parsed_to = parse_commit_range(f'{a}..{c}', temp_dir)
844+
assert (parsed_from, parsed_to) == (a, c)
845+
846+
def test_three_dot_linear_history(self) -> None:
847+
"""For 'A...C' in linear history, expect (A,C)."""
848+
with temporary_git_repository() as (temp_dir, repo):
849+
a, b, c = self._make_linear_history(repo, temp_dir)
850+
851+
parsed_from, parsed_to = parse_commit_range(f'{a}...{c}', temp_dir)
852+
assert (parsed_from, parsed_to) == (a, c)
853+
854+
def test_open_right_linear_history(self) -> None:
855+
"""For 'A..', expect (A,HEAD=C)."""
856+
with temporary_git_repository() as (temp_dir, repo):
857+
a, b, c = self._make_linear_history(repo, temp_dir)
858+
859+
parsed_from, parsed_to = parse_commit_range(f'{a}..', temp_dir)
860+
assert (parsed_from, parsed_to) == (a, c)
861+
862+
def test_open_left_linear_history(self) -> None:
863+
"""For '..C' where HEAD==C, expect (HEAD=C,C)."""
864+
with temporary_git_repository() as (temp_dir, repo):
865+
a, b, c = self._make_linear_history(repo, temp_dir)
866+
867+
parsed_from, parsed_to = parse_commit_range(f'..{c}', temp_dir)
868+
assert (parsed_from, parsed_to) == (c, c)
869+
870+
def test_single_commit_spec(self) -> None:
871+
"""For 'A', expect (A,HEAD=C)."""
872+
with temporary_git_repository() as (temp_dir, repo):
873+
a, b, c = self._make_linear_history(repo, temp_dir)
874+
875+
parsed_from, parsed_to = parse_commit_range(a, temp_dir)
876+
assert (parsed_from, parsed_to) == (a, c)

0 commit comments

Comments
 (0)