fix(audit): sort milestones, sort JSON export, extract test helper

- Fix milestone section using unsorted repos list
- Apply --sort to --format json output
- Rename _sort_repos to sort_repos (now used by cli.py)
- Extract shared make_repo helper to tests/helpers.py
- Move exporter import to module level in cli.py

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
sylvain
2026-03-12 04:07:41 +01:00
parent cf6f2dd3c6
commit 50768db31f
5 changed files with 46 additions and 71 deletions

View File

@@ -11,7 +11,8 @@ from rich.console import Console
from gitea_dashboard.client import GiteaClient from gitea_dashboard.client import GiteaClient
from gitea_dashboard.collector import collect_all from gitea_dashboard.collector import collect_all
from gitea_dashboard.display import render_dashboard from gitea_dashboard.display import render_dashboard, sort_repos
from gitea_dashboard.exporter import export_json
_DEFAULT_URL = "http://192.168.0.106:3000" _DEFAULT_URL = "http://192.168.0.106:3000"
@@ -107,8 +108,7 @@ def main(argv: list[str] | None = None) -> None:
sys.exit(1) sys.exit(1)
if args.format == "json": if args.format == "json":
from gitea_dashboard.exporter import export_json sorted_repos = sort_repos(repos, args.sort)
print(export_json(sorted_repos)) # noqa: T201
print(export_json(repos)) # noqa: T201
else: else:
render_dashboard(repos, sort_key=args.sort) render_dashboard(repos, sort_key=args.sort)

View File

@@ -93,7 +93,7 @@ def _colorize_milestone_due(due_on: str | None) -> str:
return "green" return "green"
def _sort_repos(repos: list[RepoData], sort_key: str) -> list[RepoData]: def sort_repos(repos: list[RepoData], sort_key: str) -> list[RepoData]:
"""Trie la liste des repos selon le critere donne. """Trie la liste des repos selon le critere donne.
Args: Args:
@@ -144,7 +144,7 @@ def render_dashboard(
return return
# Tri des repos # Tri des repos
sorted_repos = _sort_repos(repos, sort_key) sorted_repos = sort_repos(repos, sort_key)
# Tableau principal # Tableau principal
table = Table(title="Gitea Dashboard") table = Table(title="Gitea Dashboard")
@@ -172,7 +172,7 @@ def render_dashboard(
console.print(table) console.print(table)
# Section milestones — uniquement si au moins un repo en a # Section milestones — uniquement si au moins un repo en a
repos_with_milestones = [r for r in repos if r.milestones] repos_with_milestones = [r for r in sorted_repos if r.milestones]
if repos_with_milestones: if repos_with_milestones:
console.print() console.print()

30
tests/helpers.py Normal file
View File

@@ -0,0 +1,30 @@
"""Shared test fixtures and helpers."""
from gitea_dashboard.collector import RepoData
def make_repo(
name="my-repo",
full_name="admin/my-repo",
description="A repo",
open_issues=3,
is_fork=False,
is_archived=False,
is_mirror=False,
latest_release=None,
milestones=None,
last_commit_date=None,
):
"""Build a RepoData for testing."""
return RepoData(
name=name,
full_name=full_name,
description=description,
open_issues=open_issues,
is_fork=is_fork,
is_archived=is_archived,
is_mirror=is_mirror,
latest_release=latest_release,
milestones=milestones if milestones is not None else [],
last_commit_date=last_commit_date,
)

View File

@@ -4,11 +4,13 @@ from io import StringIO
from rich.console import Console from rich.console import Console
from gitea_dashboard.collector import RepoData
from gitea_dashboard.display import ( from gitea_dashboard.display import (
render_dashboard, render_dashboard,
sort_repos,
) )
from tests.helpers import make_repo as _make_repo
def _make_console(): def _make_console():
"""Create a console that captures output for testing. """Create a console that captures output for testing.
@@ -20,33 +22,6 @@ def _make_console():
return Console(file=buf, force_terminal=True, width=120, highlight=False), buf return Console(file=buf, force_terminal=True, width=120, highlight=False), buf
def _make_repo(
name="my-repo",
full_name="admin/my-repo",
description="A repo",
open_issues=3,
is_fork=False,
is_archived=False,
is_mirror=False,
latest_release=None,
milestones=None,
last_commit_date=None,
):
"""Build a RepoData for testing."""
return RepoData(
name=name,
full_name=full_name,
description=description,
open_issues=open_issues,
is_fork=is_fork,
is_archived=is_archived,
is_mirror=is_mirror,
latest_release=latest_release,
milestones=milestones if milestones is not None else [],
last_commit_date=last_commit_date,
)
class TestRenderDashboardTable: class TestRenderDashboardTable:
"""Test the main repos table rendering.""" """Test the main repos table rendering."""
@@ -290,35 +265,32 @@ class TestColorizeMilestoneDue:
class TestSortRepos: class TestSortRepos:
"""Test _sort_repos function.""" """Test sort_repos function."""
def test_sort_by_name(self): def test_sort_by_name(self):
"""Sorts alphabetically by name (case-insensitive).""" """Sorts alphabetically by name (case-insensitive)."""
from gitea_dashboard.display import _sort_repos
repos = [ repos = [
_make_repo(name="Charlie"), _make_repo(name="Charlie"),
_make_repo(name="alpha"), _make_repo(name="alpha"),
_make_repo(name="Bravo"), _make_repo(name="Bravo"),
] ]
result = _sort_repos(repos, "name") result = sort_repos(repos, "name")
assert [r.name for r in result] == ["alpha", "Bravo", "Charlie"] assert [r.name for r in result] == ["alpha", "Bravo", "Charlie"]
def test_sort_by_issues(self): def test_sort_by_issues(self):
"""Sorts by issues count descending.""" """Sorts by issues count descending."""
from gitea_dashboard.display import _sort_repos
repos = [ repos = [
_make_repo(name="low", open_issues=1), _make_repo(name="low", open_issues=1),
_make_repo(name="high", open_issues=10), _make_repo(name="high", open_issues=10),
_make_repo(name="mid", open_issues=5), _make_repo(name="mid", open_issues=5),
] ]
result = _sort_repos(repos, "issues") result = sort_repos(repos, "issues")
assert [r.name for r in result] == ["high", "mid", "low"] assert [r.name for r in result] == ["high", "mid", "low"]
def test_sort_by_release(self): def test_sort_by_release(self):
"""Sorts by release date descending; repos without release last.""" """Sorts by release date descending; repos without release last."""
from gitea_dashboard.display import _sort_repos
repos = [ repos = [
_make_repo(name="no-rel", latest_release=None), _make_repo(name="no-rel", latest_release=None),
@@ -331,17 +303,16 @@ class TestSortRepos:
latest_release={"tag_name": "v2.0", "published_at": "2026-03-01T00:00:00Z"}, latest_release={"tag_name": "v2.0", "published_at": "2026-03-01T00:00:00Z"},
), ),
] ]
result = _sort_repos(repos, "release") result = sort_repos(repos, "release")
assert [r.name for r in result] == ["new", "old", "no-rel"] assert [r.name for r in result] == ["new", "old", "no-rel"]
def test_sort_by_activity(self): def test_sort_by_activity(self):
"""Sorts by last commit date descending; repos without commit last.""" """Sorts by last commit date descending; repos without commit last."""
from gitea_dashboard.display import _sort_repos
repos = [ repos = [
_make_repo(name="inactive", last_commit_date=None), _make_repo(name="inactive", last_commit_date=None),
_make_repo(name="old-commit", last_commit_date="2025-06-01T00:00:00Z"), _make_repo(name="old-commit", last_commit_date="2025-06-01T00:00:00Z"),
_make_repo(name="recent", last_commit_date="2026-03-10T00:00:00Z"), _make_repo(name="recent", last_commit_date="2026-03-10T00:00:00Z"),
] ]
result = _sort_repos(repos, "activity") result = sort_repos(repos, "activity")
assert [r.name for r in result] == ["recent", "old-commit", "inactive"] assert [r.name for r in result] == ["recent", "old-commit", "inactive"]

View File

@@ -2,35 +2,9 @@
import json import json
from gitea_dashboard.collector import RepoData
from gitea_dashboard.exporter import export_json, repos_to_dicts from gitea_dashboard.exporter import export_json, repos_to_dicts
from tests.helpers import make_repo as _make_repo
def _make_repo(
name="my-repo",
full_name="admin/my-repo",
description="A repo",
open_issues=3,
is_fork=False,
is_archived=False,
is_mirror=False,
latest_release=None,
milestones=None,
last_commit_date=None,
):
"""Build a RepoData for testing."""
return RepoData(
name=name,
full_name=full_name,
description=description,
open_issues=open_issues,
is_fork=is_fork,
is_archived=is_archived,
is_mirror=is_mirror,
latest_release=latest_release,
milestones=milestones if milestones is not None else [],
last_commit_date=last_commit_date,
)
class TestReposToDicts: class TestReposToDicts: