feat: add provider-neutral tracker automation

This commit is contained in:
2026-08-17 22:36:05 -04:00
parent f65a6ec812
commit dead6ca2bb
28 changed files with 1557 additions and 17 deletions
View File
+125
View File
@@ -0,0 +1,125 @@
import unittest
from tracker import CompletedCommand, RecordingRunner, RetryPolicy, Tracker # type: ignore[reportMissingImports]
class TrackerOperationTests(unittest.TestCase):
def test_add_label_ensures_missing_label_before_assignment(self):
runner = RecordingRunner(
[
CompletedCommand("[]"),
CompletedCommand('{"name":"ready","color":"ededed"}'),
CompletedCommand('{"number":7,"labels":[{"name":"ready"}]}'),
]
)
result = Tracker(provider="github", runner=runner).add_label("issue", 7, "ready")
self.assertTrue(result["ok"])
self.assertEqual([call[0][:3] for call in runner.calls], [["gh", "label", "list"], ["gh", "label", "create"], ["gh", "issue", "edit"]])
self.assertEqual(result["details"]["ensured"]["created"], True)
def test_existing_label_is_not_recreated(self):
runner = RecordingRunner(
[
CompletedCommand('[{"name":"ready","color":"ff0000"}]'),
CompletedCommand('{"number":7,"labels":[{"name":"ready"}]}'),
]
)
result = Tracker(provider="gitea", runner=runner).add_label("issue", 7, "ready")
self.assertTrue(result["ok"])
self.assertEqual(len(runner.calls), 2)
self.assertEqual(result["details"]["ensured"]["created"], False)
def test_transient_failure_is_retried_and_normalized(self):
runner = RecordingRunner(
[
CompletedCommand("", "connection reset", 1),
CompletedCommand('{"number":4,"iid":4,"title":"Fix","description":"body","state":"opened","labels":[]}'),
]
)
result = Tracker(provider="gitlab", runner=runner, retry=RetryPolicy(attempts=2)).get_issue(4)
self.assertTrue(result["ok"])
self.assertEqual(len(runner.calls), 2)
self.assertEqual(result["result"]["number"], 4)
self.assertEqual(result["result"]["body"], "body")
def test_external_pr_filter_normalizes_github_associations(self):
runner = RecordingRunner([
CompletedCommand('[{"number":1,"title":"inside","authorAssociation":"MEMBER"},{"number":2,"title":"outside","authorAssociation":"NONE"}]')
])
result = Tracker(provider="github", runner=runner).list_external_prs()
self.assertTrue(result["ok"])
self.assertEqual([item["number"] for item in result["result"]], [2])
def test_external_filter_reports_missing_membership_metadata(self):
runner = RecordingRunner([CompletedCommand('[{"number":1,"title":"unknown"}]')])
result = Tracker(provider="gitea", runner=runner).list_external_prs()
self.assertFalse(result["ok"])
self.assertEqual(result["error"]["code"], "unsupported_capability")
def test_pr_get_can_include_diff(self):
runner = RecordingRunner([
CompletedCommand('{"number":3,"title":"Change","state":"open"}'),
CompletedCommand("diff --git a/a b/a"),
])
result = Tracker(provider="gitlab", runner=runner).get_pr(3, diff=True)
self.assertTrue(result["ok"])
self.assertEqual(result["result"]["diff"], "diff --git a/a b/a")
def test_child_creation_links_native_and_updates_map_order(self):
runner = RecordingRunner([
CompletedCommand("[]"),
CompletedCommand("{}"),
CompletedCommand('{"number":7,"title":"Research"}'),
CompletedCommand("{}"),
CompletedCommand('{"number":9,"body":"Notes"}'),
CompletedCommand("{}"),
])
result = Tracker(provider="github", runner=runner).create_child(9, "Research", wayfinder_type="research")
self.assertTrue(result["ok"])
self.assertEqual(result["result"]["number"], 7)
self.assertEqual(result["details"]["relationship"], "native")
self.assertTrue(result["details"]["map_updated"])
self.assertTrue(any("sub_issues" in part for part in runner.calls[3][0]))
def test_resolve_reports_completed_steps_after_partial_failure(self):
runner = RecordingRunner([
CompletedCommand("{}"),
CompletedCommand("", "connection reset", 1),
])
result = Tracker(provider="gitea", runner=runner, retry=RetryPolicy(attempts=1)).resolve("issue", 7, "answer")
self.assertFalse(result["ok"])
self.assertEqual(result["error"]["code"], "partial_failure")
self.assertEqual(result["error"]["details"]["completed"], ["comment"])
def test_frontier_uses_map_task_order_and_filters_closed_or_claimed(self):
runner = RecordingRunner([
CompletedCommand('{"number":9,"body":"- [ ] #2 second\\n- [ ] #1 first","state":"open"}'),
CompletedCommand('{"number":2,"title":"second","state":"open","assignees":[]}'),
CompletedCommand('{"number":1,"title":"first","state":"closed","assignees":[]}'),
])
result = Tracker(provider="github", runner=runner).frontier(9)
self.assertTrue(result["ok"])
self.assertEqual([item["number"] for item in result["result"]], [2])
self.assertTrue(result["details"]["deterministic"])
def test_authentication_failure_is_not_retryable(self):
runner = RecordingRunner([CompletedCommand("", "not logged in", 1)])
result = Tracker(provider="github", runner=runner).get_issue(4)
self.assertFalse(result["ok"])
self.assertEqual(result["error"]["code"], "auth_required")
self.assertFalse(result["error"]["retryable"])
self.assertEqual(len(runner.calls), 1)
if __name__ == "__main__":
unittest.main()
+37
View File
@@ -0,0 +1,37 @@
import unittest
from tracker import TrackerError, resolve_provider # type: ignore[reportMissingImports]
class ProviderResolutionTests(unittest.TestCase):
def test_cli_provider_wins_over_environment_and_remote(self):
self.assertEqual(
resolve_provider(
explicit="github",
env={"TRACKER_PROVIDER": "gitlab"},
remote="https://gitea.example.com/team/repo.git",
),
"github",
)
def test_environment_provider_wins_over_remote(self):
self.assertEqual(
resolve_provider(
env={"TRACKER_PROVIDER": "gitlab"},
remote="git@github.com:team/repo.git",
),
"gitlab",
)
def test_remote_provider_is_detected(self):
self.assertEqual(resolve_provider(remote="git@gitea.example.com:team/repo.git"), "gitea")
def test_unsupported_remote_is_structured_error(self):
with self.assertRaises(TrackerError) as context:
resolve_provider(remote="https://example.com/team/repo.git")
self.assertEqual(context.exception.code, "provider_detection_failed")
self.assertFalse(context.exception.retryable)
if __name__ == "__main__":
unittest.main()