Skip to content

Commit 3aeabd4

Browse files
committed
Fix codecov upload to use correct repository slug
1 parent 42c6e43 commit 3aeabd4

7 files changed

Lines changed: 192 additions & 13 deletions

File tree

.github/workflows/codecov-coverage.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@ jobs:
2626
uses: codecov/codecov-action@v5
2727
with:
2828
token: ${{ secrets.CODECOV_TOKEN }}
29+
slug: wende/codebook

codebook/CLIENT_SERVER.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ export CODEBOOK_BASE_URL=http://localhost:3000
105105

106106
See also: [Configuration](CONFIGURATION.md) | [Templates](TEMPLATES.md)
107107

108-
Rendered by CodeBook [`v0.1.1-2-g73f4032`](codebook:codebook.version)
108+
Rendered by CodeBook [`v0.1.1-3-g42c6e43`](codebook:codebook.version)
109109

110110
--- BACKLINKS ---
111111
[TEMPLATES](TEMPLATES.md "codebook:backlink")

codebook/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ codebook run
5555

5656
| Metric | Value |
5757
| --------- | ----------------------------------- |
58-
| Version | [`v0.1.1-2-g73f4032`](codebook:codebook.version) |
58+
| Version | [`v0.1.1-3-g42c6e43`](codebook:codebook.version) |
5959

6060
## Documentation Files
6161

codebook/TEMPLATES.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ These templates are resolved **locally by the CLI** - no server required.
1212

1313
**Example:**
1414
```markdown
15-
[`v0.1.1-2-g73f4032`](codebook:codebook.version)
15+
[`v0.1.1-3-g42c6e43`](codebook:codebook.version)
1616
```
1717

18-
**Current version:** [`v0.1.1-2-g73f4032`](codebook:codebook.version)
18+
**Current version:** [`v0.1.1-3-g42c6e43`](codebook:codebook.version)
1919

2020
## Server Templates
2121

codebook/edge-cases/TASK_VERSION_DIFF_SKIPPING.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
When creating a task with `codebook task new`, files containing only version changes (like `codebook.version` updates) would create noise in the task output:
66

77
```diff
8-
-Rendered by CodeBook [`v0.1.1-2-g73f4032`](codebook:codebook.version)
9-
+Rendered by CodeBook [`v0.1.1-2-g73f4032`](codebook:codebook.version)
8+
-Rendered by CodeBook [`v0.1.1-3-g42c6e43`](codebook:codebook.version)
9+
+Rendered by CodeBook [`v0.1.1-3-g42c6e43`](codebook:codebook.version)
1010
```
1111

1212
These diffs provide no useful information for the task.
@@ -33,8 +33,8 @@ A diff is considered "version-only" if:
3333
--- a/README.md
3434
+++ b/README.md
3535
@@ -1,3 +1,3 @@
36-
-Rendered by CodeBook [`v0.1.1-2-g73f4032`](codebook:codebook.version)
37-
+Rendered by CodeBook [`v0.1.1-2-g73f4032`](codebook:codebook.version)
36+
-Rendered by CodeBook [`v0.1.1-3-g42c6e43`](codebook:codebook.version)
37+
+Rendered by CodeBook [`v0.1.1-3-g42c6e43`](codebook:codebook.version)
3838
```
3939

4040
This file would be **skipped** from the task.
@@ -50,8 +50,8 @@ This file would be **skipped** from the task.
5050
+## New Section
5151
+Added new content here.
5252
+
53-
-Rendered by CodeBook [`v0.1.1-2-g73f4032`](codebook:codebook.version)
54-
+Rendered by CodeBook [`v0.1.1-2-g73f4032`](codebook:codebook.version)
53+
-Rendered by CodeBook [`v0.1.1-3-g42c6e43`](codebook:codebook.version)
54+
+Rendered by CodeBook [`v0.1.1-3-g42c6e43`](codebook:codebook.version)
5555
```
5656

5757
This file would be **included** because it has non-version changes.

src/codebook/cli.py

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1494,6 +1494,66 @@ def _parse_task_frontmatter(content: str) -> dict:
14941494
return {}
14951495

14961496

1497+
def _is_binary_file(file_path: Path, git_root: Path) -> bool:
1498+
"""Check if a file is binary using git's detection.
1499+
1500+
Args:
1501+
file_path: Path to the file to check
1502+
git_root: Path to the git root directory
1503+
1504+
Returns:
1505+
True if the file is binary, False otherwise
1506+
"""
1507+
try:
1508+
# Use git diff to detect binary files - it returns "Binary files differ"
1509+
# for binary files when comparing with empty tree
1510+
result = subprocess.run(
1511+
[
1512+
"git",
1513+
"diff",
1514+
"--numstat",
1515+
"4b825dc642cb6eb9a060e54bf8d69288fbee4904",
1516+
"--",
1517+
str(file_path),
1518+
],
1519+
cwd=git_root,
1520+
capture_output=True,
1521+
text=True,
1522+
)
1523+
if result.returncode == 0 and result.stdout.strip():
1524+
# Binary files show as "-\t-\t" in numstat output
1525+
parts = result.stdout.strip().split("\t")
1526+
if len(parts) >= 2 and parts[0] == "-" and parts[1] == "-":
1527+
return True
1528+
return False
1529+
except Exception:
1530+
return False
1531+
1532+
1533+
def _resolve_sha(sha: str, git_root: Path) -> str | None:
1534+
"""Resolve a SHA (short or full) to its full form.
1535+
1536+
Args:
1537+
sha: The SHA to resolve (can be short or full)
1538+
git_root: Path to the git root directory
1539+
1540+
Returns:
1541+
Full SHA if resolvable, None otherwise
1542+
"""
1543+
try:
1544+
result = subprocess.run(
1545+
["git", "rev-parse", sha],
1546+
cwd=git_root,
1547+
capture_output=True,
1548+
text=True,
1549+
)
1550+
if result.returncode == 0:
1551+
return result.stdout.strip()
1552+
return None
1553+
except Exception:
1554+
return None
1555+
1556+
14971557
def _is_ancestor_commit(ancestor_sha: str, descendant_sha: str, git_root: Path) -> bool:
14981558
"""Check if ancestor_sha is an ancestor of (or equal to) descendant_sha.
14991559
@@ -1522,14 +1582,18 @@ def _is_ancestor_commit(ancestor_sha: str, descendant_sha: str, git_root: Path)
15221582
return False
15231583

15241584

1525-
def _extract_reviewed_files(tasks_dir: Path) -> dict[str, list[tuple[str, str]]]:
1585+
def _extract_reviewed_files(
1586+
tasks_dir: Path, git_root: Path | None = None
1587+
) -> dict[str, list[tuple[str, str]]]:
15261588
"""Extract reviewed file:sha pairs from task frontmatter.
15271589
15281590
Args:
15291591
tasks_dir: Path to the tasks directory
1592+
git_root: Path to the git root directory (for resolving short SHAs)
15301593
15311594
Returns:
15321595
Dict mapping file paths to list of (sha, task_name) tuples
1596+
SHAs are resolved to full form when git_root is provided.
15331597
"""
15341598
reviewed_files: dict[str, list[tuple[str, str]]] = {}
15351599

@@ -1560,6 +1624,11 @@ def _extract_reviewed_files(tasks_dir: Path) -> dict[str, list[tuple[str, str]]]
15601624
file_path = file_path.strip()
15611625
sha = sha.strip()
15621626
if file_path and sha:
1627+
# Resolve short SHA to full SHA if git_root is available
1628+
if git_root and len(sha) < 40:
1629+
resolved = _resolve_sha(sha, git_root)
1630+
if resolved:
1631+
sha = resolved
15631632
if file_path not in reviewed_files:
15641633
reviewed_files[file_path] = []
15651634
reviewed_files[file_path].append((sha, task_name))
@@ -1687,8 +1756,8 @@ def extract_commits_from_tasks() -> dict[str, str]:
16871756
click.echo("Extracting commits from task files...")
16881757
task_commits = extract_commits_from_tasks()
16891758

1690-
# Extract reviewed files from task frontmatter
1691-
reviewed_files = _extract_reviewed_files(tasks_dir)
1759+
# Extract reviewed files from task frontmatter (with short SHA resolution)
1760+
reviewed_files = _extract_reviewed_files(tasks_dir, git_root)
16921761

16931762
if not task_commits and not reviewed_files:
16941763
click.echo("No commits found in task files.", err=True)
@@ -1730,11 +1799,23 @@ def extract_commits_from_tasks() -> dict[str, str]:
17301799
if f.exists() and not str(f.resolve()).startswith(str(tasks_dir_resolved))
17311800
]
17321801

1802+
# Filter out binary files (they can't be blamed meaningfully)
1803+
binary_count = 0
1804+
text_files = []
1805+
for f in files_to_analyze:
1806+
if _is_binary_file(f, git_root):
1807+
binary_count += 1
1808+
else:
1809+
text_files.append(f)
1810+
files_to_analyze = text_files
1811+
17331812
if not files_to_analyze:
17341813
click.echo("No files to analyze in scope.", err=True)
17351814
return
17361815

17371816
if not output_json:
1817+
if binary_count > 0:
1818+
click.echo(f"Skipped {binary_count} binary file(s)")
17381819
click.echo(f"Analyzing {len(files_to_analyze)} file(s)...\n")
17391820

17401821
# Analyze coverage per file

tests/test_cli.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,6 +1299,103 @@ def test_task_coverage_multiple_reviewed_entries(self, git_repo: Path):
12991299
# Both files should be covered
13001300
assert "100.0%" in result.output or "Overall Coverage:" in result.output
13011301

1302+
def test_task_coverage_with_short_sha(self, git_repo: Path):
1303+
"""Should resolve short SHAs in reviewed entries to full SHAs."""
1304+
runner = CliRunner()
1305+
1306+
# Create a source file and commit it
1307+
src_file = git_repo / "short_sha_code.py"
1308+
src_file.write_text("def short_sha():\n return True\n")
1309+
subprocess.run(["git", "add", "short_sha_code.py"], cwd=git_repo, capture_output=True)
1310+
subprocess.run(
1311+
["git", "commit", "-m", "Add short sha code"],
1312+
cwd=git_repo,
1313+
capture_output=True,
1314+
)
1315+
1316+
# Get the full commit SHA and extract a short version
1317+
result_sha = subprocess.run(
1318+
["git", "rev-parse", "HEAD"],
1319+
cwd=git_repo,
1320+
capture_output=True,
1321+
text=True,
1322+
)
1323+
full_sha = result_sha.stdout.strip()
1324+
short_sha = full_sha[:7] # Use 7-char short SHA
1325+
1326+
# Create a task file with short SHA in reviewed frontmatter
1327+
tasks_dir = git_repo / "tasks"
1328+
tasks_dir.mkdir(parents=True)
1329+
task_file = tasks_dir / "202412281530-SHORT_SHA_TASK.md"
1330+
task_content = f"""---
1331+
reviewed:
1332+
- short_sha_code.py:{short_sha}
1333+
---
1334+
# Short SHA Task
1335+
1336+
This task uses a short SHA for reviewed entry.
1337+
"""
1338+
task_file.write_text(task_content)
1339+
1340+
# Commit the task file
1341+
subprocess.run(["git", "add", str(task_file)], cwd=git_repo, capture_output=True)
1342+
subprocess.run(
1343+
["git", "commit", "-m", "Add short sha task"],
1344+
cwd=git_repo,
1345+
capture_output=True,
1346+
)
1347+
1348+
# Run coverage
1349+
result = runner.invoke(main, ["task", "coverage", str(git_repo)])
1350+
1351+
assert result.exit_code == 0
1352+
assert "reviewed file(s)" in result.output
1353+
assert "short_sha_code.py" in result.output
1354+
# The file should show as covered (short SHA was resolved)
1355+
assert "100.0%" in result.output or "✓" in result.output
1356+
1357+
def test_task_coverage_skips_binary_files(self, git_repo: Path):
1358+
"""Should skip binary files in coverage analysis."""
1359+
runner = CliRunner()
1360+
1361+
# Create a text source file
1362+
src_file = git_repo / "text_code.py"
1363+
src_file.write_text("def text():\n return True\n")
1364+
1365+
# Create a binary file (PNG header bytes)
1366+
binary_file = git_repo / "image.png"
1367+
binary_file.write_bytes(b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00")
1368+
1369+
subprocess.run(["git", "add", "."], cwd=git_repo, capture_output=True)
1370+
subprocess.run(
1371+
["git", "commit", "-m", "Add text and binary files"],
1372+
cwd=git_repo,
1373+
capture_output=True,
1374+
)
1375+
1376+
# Create a minimal task file to enable coverage
1377+
tasks_dir = git_repo / "tasks"
1378+
tasks_dir.mkdir(parents=True)
1379+
task_file = tasks_dir / "202412281530-BINARY_TEST.md"
1380+
task_file.write_text("# Binary Test\n\nTest binary file skipping.\n")
1381+
subprocess.run(["git", "add", str(task_file)], cwd=git_repo, capture_output=True)
1382+
subprocess.run(
1383+
["git", "commit", "-m", "Add binary test task"],
1384+
cwd=git_repo,
1385+
capture_output=True,
1386+
)
1387+
1388+
# Run coverage
1389+
result = runner.invoke(main, ["task", "coverage", str(git_repo)])
1390+
1391+
assert result.exit_code == 0
1392+
# Should mention skipping binary files
1393+
assert "Skipped" in result.output and "binary" in result.output
1394+
# Should analyze text file
1395+
assert "text_code.py" in result.output
1396+
# Should NOT analyze binary file
1397+
assert "image.png" not in result.output or "Could not analyze" not in result.output
1398+
13021399
def test_task_mark_reviewed_help(self, runner: CliRunner):
13031400
"""Should show mark-reviewed help."""
13041401
result = runner.invoke(main, ["task", "mark-reviewed", "--help"])

0 commit comments

Comments
 (0)