fix: add repo auto-detection and improve org validation

1. Repo Auto-Detection (config.py):
   - Added _detect_repo_from_git() to parse git remote URL
   - Supports SSH, SSH short, HTTPS, HTTP URL formats
   - Falls back to git remote when GITEA_REPO not set

2. Organization Validation (gitea_client.py):
   - Changed is_org_repo() to use /orgs/{owner} endpoint
   - Added _is_organization() method for reliable org detection
   - Fixes issue where owner.type was null in Gitea API

3. Tests:
   - Added 6 tests for git URL parsing
   - Added 3 tests for org detection

Fixes #64

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-21 15:10:53 -05:00
parent feb86b059f
commit ad56700059
4 changed files with 210 additions and 4 deletions

View File

@@ -149,3 +149,65 @@ def test_mode_detection_company(tmp_path, monkeypatch):
assert result['mode'] == 'company'
assert result['repo'] is None
# ========================================
# GIT URL PARSING TESTS
# ========================================
def test_parse_git_url_ssh_format():
"""Test parsing SSH format git URL"""
config = GiteaConfig()
# SSH with port: ssh://git@host:port/owner/repo.git
url = "ssh://git@hotserv.tailc9b278.ts.net:2222/personal-projects/personal-portfolio.git"
result = config._parse_git_url(url)
assert result == "personal-projects/personal-portfolio"
def test_parse_git_url_ssh_short_format():
"""Test parsing SSH short format git URL"""
config = GiteaConfig()
# SSH short: git@host:owner/repo.git
url = "git@github.com:owner/repo.git"
result = config._parse_git_url(url)
assert result == "owner/repo"
def test_parse_git_url_https_format():
"""Test parsing HTTPS format git URL"""
config = GiteaConfig()
# HTTPS: https://host/owner/repo.git
url = "https://gitea.hotserv.cloud/personal-projects/leo-claude-mktplace.git"
result = config._parse_git_url(url)
assert result == "personal-projects/leo-claude-mktplace"
def test_parse_git_url_http_format():
"""Test parsing HTTP format git URL"""
config = GiteaConfig()
# HTTP: http://host/owner/repo.git
url = "http://gitea.hotserv.cloud/personal-projects/repo.git"
result = config._parse_git_url(url)
assert result == "personal-projects/repo"
def test_parse_git_url_without_git_suffix():
"""Test parsing git URL without .git suffix"""
config = GiteaConfig()
url = "https://github.com/owner/repo"
result = config._parse_git_url(url)
assert result == "owner/repo"
def test_parse_git_url_invalid_format():
"""Test parsing invalid git URL returns None"""
config = GiteaConfig()
url = "not-a-valid-url"
result = config._parse_git_url(url)
assert result is None

View File

@@ -222,3 +222,47 @@ def test_no_repo_specified_error(gitea_client):
client.list_issues()
assert "Repository not specified" in str(exc_info.value)
# ========================================
# ORGANIZATION DETECTION TESTS
# ========================================
def test_is_organization_true(gitea_client):
"""Test _is_organization returns True for valid organization"""
mock_response = Mock()
mock_response.status_code = 200
with patch.object(gitea_client.session, 'get', return_value=mock_response):
result = gitea_client._is_organization('personal-projects')
assert result is True
gitea_client.session.get.assert_called_once_with(
'https://test.com/api/v1/orgs/personal-projects'
)
def test_is_organization_false(gitea_client):
"""Test _is_organization returns False for user account"""
mock_response = Mock()
mock_response.status_code = 404
with patch.object(gitea_client.session, 'get', return_value=mock_response):
result = gitea_client._is_organization('lmiranda')
assert result is False
def test_is_org_repo_uses_orgs_endpoint(gitea_client):
"""Test is_org_repo uses /orgs endpoint instead of owner.type"""
mock_response = Mock()
mock_response.status_code = 200
with patch.object(gitea_client.session, 'get', return_value=mock_response):
result = gitea_client.is_org_repo('personal-projects/repo')
assert result is True
# Should call /orgs/personal-projects, not /repos/.../
gitea_client.session.get.assert_called_once_with(
'https://test.com/api/v1/orgs/personal-projects'
)