Skip to content

Commit 912d72e

Browse files
authored
Merge pull request #436 from lbedner/v0.5.2-rc2
v0.5.2-rc2
2 parents 21c483f + 18ac2ad commit 912d72e

8 files changed

Lines changed: 161 additions & 51 deletions

File tree

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Each generated project includes:
3232

3333
## Installation
3434

35-
**Current Version**: v0.5.2-rc1
35+
**Current Version**: v0.5.2-rc2
3636

3737
```bash
3838
pip install aegis-stack

aegis/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
Aegis Stack CLI - Component generation and project management tools.
33
"""
44

5-
__version__ = "0.5.2-rc1"
5+
__version__ = "0.5.2-rc2"

aegis/commands/update.py

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
from ..core.copier_updater import (
1919
analyze_conflict_files,
2020
cleanup_backup_tag,
21-
count_commits_between,
2221
create_backup_point,
2322
format_conflict_report,
2423
get_changelog,
@@ -156,29 +155,16 @@ def update_command(
156155
target_ref = resolve_version_to_ref(to_version, template_root)
157156
target_version_display = to_version
158157
else:
159-
# Default to HEAD - Copier handles version detection via git describe
160-
# This ensures unreleased commits are picked up (not just tagged releases)
161-
target_ref = "HEAD"
162-
163-
# Show user-friendly version info
164-
head_commit = resolve_ref_to_commit("HEAD", template_root)
158+
# Default to latest release version (not HEAD, not prereleases)
159+
# Prereleases (rc, alpha, beta) are only picked up via explicit --to-version
165160
latest = get_latest_version(template_root)
166161
if latest:
167-
latest_commit = resolve_ref_to_commit(f"v{latest}", template_root)
168-
if head_commit and latest_commit and head_commit == latest_commit:
169-
target_version_display = f"{latest} (latest release)"
170-
elif head_commit:
171-
# Count commits ahead of latest tag
172-
commits_ahead = count_commits_between(
173-
f"v{latest}", "HEAD", template_root
174-
)
175-
if commits_ahead > 0:
176-
target_version_display = f"{latest}+{commits_ahead} commits (HEAD)"
177-
else:
178-
target_version_display = f"HEAD ({head_commit[:8]}...)"
179-
else:
180-
target_version_display = "HEAD (latest commit)"
162+
target_ref = f"v{latest}"
163+
target_version_display = f"{latest} (latest release)"
181164
else:
165+
# Fallback to HEAD only if no versions found
166+
target_ref = "HEAD"
167+
head_commit = resolve_ref_to_commit("HEAD", template_root)
182168
if head_commit:
183169
target_version_display = f"HEAD ({head_commit[:8]}...)"
184170
else:

aegis/core/copier_updater.py

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -347,31 +347,6 @@ def resolve_ref_to_commit(ref: str, repo_path: Path) -> str | None:
347347
return None
348348

349349

350-
def count_commits_between(from_ref: str, to_ref: str, repo_path: Path) -> int:
351-
"""
352-
Count commits between two git references.
353-
354-
Args:
355-
from_ref: Starting git reference (older commit)
356-
to_ref: Ending git reference (newer commit)
357-
repo_path: Path to git repository
358-
359-
Returns:
360-
Number of commits between refs, or 0 if unable to count
361-
"""
362-
try:
363-
result = subprocess.run(
364-
["git", "rev-list", "--count", f"{from_ref}..{to_ref}"],
365-
cwd=repo_path,
366-
capture_output=True,
367-
text=True,
368-
check=True,
369-
)
370-
return int(result.stdout.strip())
371-
except (subprocess.CalledProcessError, ValueError):
372-
return 0
373-
374-
375350
def resolve_version_to_ref(
376351
version: str | None, template_root: Path | None = None
377352
) -> str:

copier.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# - Update support
77

88
_min_copier_version: "9.0.0"
9-
_version: "0.5.2-rc1"
9+
_version: "0.5.2-rc2"
1010

1111
# IMPORTANT: Template content is in subdirectory
1212
# This allows the template to be recognized as git-tracked (aegis-stack repo root has .git)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "aegis-stack"
3-
version = "0.5.2-rc1"
3+
version = "0.5.2-rc2"
44
description = "A production-ready Python foundation for builders who refuse to wait. Try: uvx aegis-stack init my-project"
55
readme = "README.md"
66
requires-python = ">=3.11,<3.15"

tests/core/test_copier_updater.py

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
cleanup_backup_tag,
1717
create_backup_point,
1818
format_conflict_report,
19+
get_available_versions,
20+
get_latest_version,
1921
rollback_to_backup,
2022
)
2123

@@ -352,3 +354,150 @@ def test_returns_fallback_on_invalid_ref(self) -> None:
352354
# Should contain fallback message with "Changelog not available" or actual changelog
353355
assert isinstance(result, str)
354356
assert "Changelog not available" in result or "Changes:" in result
357+
358+
359+
@pytest.fixture
360+
def git_repo_with_tags(tmp_path: Path) -> Path:
361+
"""Initialize a git repository with version tags (including prereleases)."""
362+
subprocess.run(["git", "init"], cwd=tmp_path, capture_output=True, check=True)
363+
subprocess.run(
364+
["git", "config", "user.email", "test@test.com"],
365+
cwd=tmp_path,
366+
capture_output=True,
367+
check=True,
368+
)
369+
subprocess.run(
370+
["git", "config", "user.name", "Test"],
371+
cwd=tmp_path,
372+
capture_output=True,
373+
check=True,
374+
)
375+
376+
# Create a copier.yml to make it a valid template root
377+
(tmp_path / "copier.yml").write_text("_subdirectory: templates\n")
378+
379+
# Create initial commit and tags
380+
(tmp_path / "test.txt").write_text("v0.1.0")
381+
subprocess.run(["git", "add", "."], cwd=tmp_path, capture_output=True, check=True)
382+
subprocess.run(
383+
["git", "commit", "-m", "v0.1.0"], cwd=tmp_path, capture_output=True, check=True
384+
)
385+
subprocess.run(
386+
["git", "tag", "v0.1.0"], cwd=tmp_path, capture_output=True, check=True
387+
)
388+
389+
# Add more commits and tags
390+
(tmp_path / "test.txt").write_text("v0.2.0")
391+
subprocess.run(["git", "add", "."], cwd=tmp_path, capture_output=True, check=True)
392+
subprocess.run(
393+
["git", "commit", "-m", "v0.2.0"], cwd=tmp_path, capture_output=True, check=True
394+
)
395+
subprocess.run(
396+
["git", "tag", "v0.2.0"], cwd=tmp_path, capture_output=True, check=True
397+
)
398+
399+
# Add a prerelease tag
400+
(tmp_path / "test.txt").write_text("v0.3.0rc1")
401+
subprocess.run(["git", "add", "."], cwd=tmp_path, capture_output=True, check=True)
402+
subprocess.run(
403+
["git", "commit", "-m", "v0.3.0rc1"],
404+
cwd=tmp_path,
405+
capture_output=True,
406+
check=True,
407+
)
408+
subprocess.run(
409+
["git", "tag", "v0.3.0rc1"], cwd=tmp_path, capture_output=True, check=True
410+
)
411+
412+
# Add another prerelease
413+
(tmp_path / "test.txt").write_text("v0.3.0-alpha.1")
414+
subprocess.run(["git", "add", "."], cwd=tmp_path, capture_output=True, check=True)
415+
subprocess.run(
416+
["git", "commit", "-m", "v0.3.0-alpha.1"],
417+
cwd=tmp_path,
418+
capture_output=True,
419+
check=True,
420+
)
421+
subprocess.run(
422+
["git", "tag", "v0.3.0-alpha.1"], cwd=tmp_path, capture_output=True, check=True
423+
)
424+
425+
return tmp_path
426+
427+
428+
class TestGetAvailableVersions:
429+
"""Tests for get_available_versions function."""
430+
431+
def test_returns_versions_sorted_newest_first(
432+
self, git_repo_with_tags: Path
433+
) -> None:
434+
"""Test that versions are returned sorted newest first."""
435+
versions = get_available_versions(git_repo_with_tags)
436+
437+
# Should get 0.2.0 and 0.1.0 (no prereleases by default)
438+
assert len(versions) == 2
439+
assert versions[0] == "0.2.0" # Newest first
440+
assert versions[1] == "0.1.0"
441+
442+
def test_excludes_prereleases_by_default(self, git_repo_with_tags: Path) -> None:
443+
"""Test that prereleases are excluded by default."""
444+
versions = get_available_versions(git_repo_with_tags)
445+
446+
# Should NOT contain rc or alpha versions
447+
assert "0.3.0rc1" not in versions
448+
assert "0.3.0-alpha.1" not in versions
449+
450+
def test_includes_prereleases_when_requested(
451+
self, git_repo_with_tags: Path
452+
) -> None:
453+
"""Test that prereleases are included when include_prereleases=True."""
454+
versions = get_available_versions(git_repo_with_tags, include_prereleases=True)
455+
456+
# Should contain all versions including prereleases
457+
assert "0.3.0rc1" in versions
458+
assert "0.3.0-alpha.1" in versions
459+
assert "0.2.0" in versions
460+
assert "0.1.0" in versions
461+
462+
def test_returns_empty_for_no_tags(self, git_repo: Path) -> None:
463+
"""Test that empty list is returned when no version tags exist."""
464+
# Create copier.yml to make it a valid template root
465+
(git_repo / "copier.yml").write_text("_subdirectory: templates\n")
466+
subprocess.run(["git", "add", "."], cwd=git_repo, capture_output=True)
467+
subprocess.run(
468+
["git", "commit", "-m", "Add copier.yml"],
469+
cwd=git_repo,
470+
capture_output=True,
471+
)
472+
473+
versions = get_available_versions(git_repo)
474+
475+
assert versions == []
476+
477+
478+
class TestGetLatestVersion:
479+
"""Tests for get_latest_version function."""
480+
481+
def test_returns_latest_non_prerelease_version(
482+
self, git_repo_with_tags: Path
483+
) -> None:
484+
"""Test that latest version is 0.2.0, not a prerelease."""
485+
latest = get_latest_version(git_repo_with_tags)
486+
487+
# Should be 0.2.0, NOT 0.3.0rc1 or 0.3.0-alpha.1
488+
assert latest == "0.2.0"
489+
490+
def test_returns_none_for_no_versions(self, git_repo: Path) -> None:
491+
"""Test that None is returned when no version tags exist."""
492+
# Create copier.yml to make it a valid template root
493+
(git_repo / "copier.yml").write_text("_subdirectory: templates\n")
494+
subprocess.run(["git", "add", "."], cwd=git_repo, capture_output=True)
495+
subprocess.run(
496+
["git", "commit", "-m", "Add copier.yml"],
497+
cwd=git_repo,
498+
capture_output=True,
499+
)
500+
501+
latest = get_latest_version(git_repo)
502+
503+
assert latest is None

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)