Skip to content

Commit 2ff2940

Browse files
Merge pull request #3 from kintsugi-tax/fix/bump-ver-0.3.1
Bump version, and ensure new versions always released
2 parents 5fd544a + 5ba78fb commit 2ff2940

5 files changed

Lines changed: 136 additions & 10 deletions

File tree

.github/workflows/ci.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,18 @@ jobs:
4747
fi
4848
echo "Versions match: $PYPROJECT_VERSION"
4949
50+
if [ "${{ github.event_name }}" = "pull_request" ]; then
51+
git fetch origin main --depth=1
52+
MAIN_VERSION=$(git show origin/main:pyproject.toml | grep '^version = ' | sed 's/version = "\(.*\)"/\1/' || true)
53+
if [ -z "$MAIN_VERSION" ]; then
54+
echo "::warning::Could not determine version on main, skipping version bump check"
55+
elif [ "$PYPROJECT_VERSION" = "$MAIN_VERSION" ]; then
56+
echo "::error::Version $PYPROJECT_VERSION is the same as on main. Please bump the version."
57+
echo "Run 'make bump VERSION=x.y.z' to update both files."
58+
exit 1
59+
fi
60+
fi
61+
5062
- name: Run tests
5163
run: poetry run pytest tests/ -v
5264

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
44

55
[tool.poetry]
66
name = "squawk-alembic"
7-
version = "0.3.0"
7+
version = "0.3.1"
88
description = "Pre-commit hook to lint Alembic migration SQL with squawk"
99
packages = [{include = "squawk_alembic"}]
1010
readme = "README.md"

squawk_alembic/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.3.0"
1+
__version__ = "0.3.1"

squawk_alembic/hook.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,11 @@ def generate_sql(filepath):
133133

134134

135135
def validate_branch(branch):
136-
"""Validate that a branch name is safe and exists in git."""
136+
"""Validate that a branch name is safe and exists in git.
137+
138+
For remote refs (origin/...), attempts a shallow fetch when the ref is
139+
missing locally — common in CI shallow clones.
140+
"""
137141
if not _BRANCH_RE.match(branch) or ".." in branch:
138142
print(
139143
f"squawk-alembic: invalid branch name: {branch!r}",
@@ -148,13 +152,23 @@ def validate_branch(branch):
148152
except FileNotFoundError:
149153
print("squawk-alembic: git not found", file=sys.stderr)
150154
return False
151-
if result.returncode != 0:
152-
print(
153-
f"squawk-alembic: branch '{branch}' not found in git",
154-
file=sys.stderr,
155+
if result.returncode == 0:
156+
return True
157+
158+
if branch.startswith("origin/"):
159+
remote_branch = branch.removeprefix("origin/")
160+
fetch = subprocess.run(
161+
["git", "fetch", "origin", remote_branch, "--depth=1"],
162+
capture_output=True,
155163
)
156-
return False
157-
return True
164+
if fetch.returncode == 0:
165+
return True
166+
167+
print(
168+
f"squawk-alembic: branch '{branch}' not found in git",
169+
file=sys.stderr,
170+
)
171+
return False
158172

159173

160174
def file_exists_on_branch(filepath, branch):

tests/test_main.py

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ def fake_subprocess(
3535
squawk_result=None,
3636
git_exists_on_branch=False,
3737
git_branch_valid=True,
38+
git_fetch_succeeds=False,
3839
):
3940
"""Return a side_effect function that dispatches based on the command."""
4041
alembic_res = alembic_result or make_result(stdout="CREATE TABLE foo (id int);\n")
@@ -44,7 +45,11 @@ def side_effect(cmd, **kwargs):
4445
if cmd[0] == "git":
4546
if "rev-parse" in cmd:
4647
return make_result(returncode=0 if git_branch_valid else 1)
47-
return make_result(returncode=0 if git_exists_on_branch else 1)
48+
if "fetch" in cmd:
49+
return make_result(returncode=0 if git_fetch_succeeds else 1)
50+
if "cat-file" in cmd:
51+
return make_result(returncode=0 if git_exists_on_branch else 1)
52+
return make_result(returncode=1)
4853
if cmd[0] == "alembic":
4954
return alembic_res
5055
if cmd[0] == "squawk":
@@ -381,3 +386,98 @@ def upgrade():
381386
assert main() == 0
382387
# No git call, just alembic + squawk = 2 calls
383388
assert mock_run.call_count == 2
389+
390+
391+
def test_origin_branch_shallow_fetch_succeeds(repo):
392+
"""In CI shallow clones, origin/main may not exist locally; the hook should fetch it."""
393+
path = write_migration(
394+
repo,
395+
"016_shallow.py",
396+
"""
397+
revision = 'sha001'
398+
down_revision = 'prev001'
399+
400+
from alembic import op
401+
402+
def upgrade():
403+
op.execute("CREATE TABLE foo (id int)")
404+
""",
405+
)
406+
with (
407+
patch("sys.argv", ["squawk-alembic", "--diff-branch", "origin/main", path]),
408+
patch(
409+
"subprocess.run",
410+
side_effect=fake_subprocess(
411+
git_branch_valid=False,
412+
git_fetch_succeeds=True,
413+
git_exists_on_branch=False,
414+
),
415+
) as mock_run,
416+
):
417+
assert main() == 0
418+
# git rev-parse (fail) + git fetch + git cat-file + alembic + squawk = 5 calls
419+
assert mock_run.call_count == 5
420+
assert mock_run.call_args_list[0][0][0][0] == "git"
421+
assert "fetch" in mock_run.call_args_list[1][0][0]
422+
assert "cat-file" in mock_run.call_args_list[2][0][0]
423+
424+
425+
def test_origin_branch_shallow_fetch_fails(repo, capsys):
426+
"""When both rev-parse and fetch fail, the hook should error."""
427+
path = write_migration(
428+
repo,
429+
"017_fetch_fail.py",
430+
"""
431+
revision = 'ff001'
432+
down_revision = 'prev001'
433+
434+
from alembic import op
435+
436+
def upgrade():
437+
op.execute("CREATE TABLE foo (id int)")
438+
""",
439+
)
440+
with (
441+
patch("sys.argv", ["squawk-alembic", "--diff-branch", "origin/main", path]),
442+
patch(
443+
"subprocess.run",
444+
side_effect=fake_subprocess(
445+
git_branch_valid=False,
446+
git_fetch_succeeds=False,
447+
),
448+
) as mock_run,
449+
):
450+
assert main() == 1
451+
# git rev-parse (fail) + git fetch (fail) = 2 calls
452+
assert mock_run.call_count == 2
453+
captured = capsys.readouterr()
454+
assert "not found in git" in captured.err
455+
456+
457+
def test_non_origin_branch_no_fetch_attempted(repo, capsys):
458+
"""Non-origin branches should not trigger a fetch attempt."""
459+
path = write_migration(
460+
repo,
461+
"018_no_fetch.py",
462+
"""
463+
revision = 'nf001'
464+
down_revision = 'prev001'
465+
466+
from alembic import op
467+
468+
def upgrade():
469+
op.execute("CREATE TABLE foo (id int)")
470+
""",
471+
)
472+
with (
473+
patch("sys.argv", ["squawk-alembic", "--diff-branch", "main", path]),
474+
patch(
475+
"subprocess.run",
476+
side_effect=fake_subprocess(git_branch_valid=False),
477+
) as mock_run,
478+
):
479+
assert main() == 1
480+
# Only git rev-parse (fail), no fetch attempted
481+
assert mock_run.call_count == 1
482+
captured = capsys.readouterr()
483+
assert "not found in git" in captured.err

0 commit comments

Comments
 (0)