fix: resolve API field mismatches and issue count fetching

- Fix PoolStatus.to_dict() field names to match frontend types
  (active_count, active_tasks instead of active, tasks)
- Fix AgentTaskInfo.to_dict() to use start_time instead of started_at
- Fix _get_issues() to use correct YouTrackClient method signature
  (get_issues_by_state takes project and state, not state and limit)
- Fix _get_builds() to use get_running_builds() instead of non-existent
  get_builds() method
- Fix _get_issue_counts() to actually fetch counts from YouTrack API
  instead of returning all zeros

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CI System
2025-12-11 07:18:44 -07:00
parent 41d751b678
commit d218c49b2f
2 changed files with 56 additions and 51 deletions

View File

@@ -508,33 +508,35 @@ class DashboardAPIHandler(BaseHTTPRequestHandler):
# Helper methods for external service calls
def _get_issues(self, states: list[str], limit: int) -> dict:
def _get_issues(self, states: list[str], limit: int) -> list:
"""Fetch issues from YouTrack."""
if not self.runner:
return {"issues": [], "counts": {}}
return []
try:
issues = []
counts = {}
project = self.runner.config.get("project", {}).get("name", "CG")
for state in states:
state_issues = self.runner.youtrack.get_issues_by_state(state, limit=limit)
counts[state] = len(state_issues)
for issue in state_issues:
issues.append({
"id": issue.id,
"summary": issue.summary,
"state": state,
"priority": issue.priority,
"repository": getattr(issue, 'repository', None),
"created": getattr(issue, 'created', None),
"updated": getattr(issue, 'updated', None),
})
try:
state_issues = self.runner.youtrack.get_issues_by_state(project, state)
for issue in state_issues[:limit]: # Apply limit after fetching
issues.append({
"id": issue.id,
"summary": issue.summary,
"state": state,
"priority": getattr(issue, 'priority', None),
"type": getattr(issue, 'type', None),
"created": getattr(issue, 'created', None),
"updated": getattr(issue, 'updated', None),
})
except Exception as e:
logger.warning(f"Failed to fetch issues for state {state}: {e}")
return {"issues": issues, "counts": counts}
return issues
except Exception as e:
logger.error(f"Failed to fetch issues: {e}")
return {"issues": [], "counts": {}, "error": str(e)}
return []
def _get_issue(self, issue_id: str) -> dict:
"""Fetch single issue from YouTrack."""
@@ -592,45 +594,42 @@ class DashboardAPIHandler(BaseHTTPRequestHandler):
# TODO: Implement issue creation
return {"success": False, "message": "Issue creation not yet implemented"}
def _get_builds(self, repo: Optional[str], status: Optional[str], limit: int) -> dict:
def _get_builds(self, repo: Optional[str], status: Optional[str], limit: int) -> list:
"""Fetch builds from Woodpecker."""
if not self.runner:
return {"builds": []}
if not self.runner or not self.runner.woodpecker:
return []
try:
builds = []
repos = [repo] if repo else list(self.runner.config.get("repos", {}).keys())
for repo_name in repos[:3]: # Limit repos to avoid too many API calls
repo_config = self.runner.config.get("repos", {}).get(repo_name, {})
woodpecker_repo = repo_config.get("name")
if not woodpecker_repo:
continue
# Get running builds
try:
build_type = repo if repo else None
running = self.runner.woodpecker.get_running_builds(build_type)
for build in running:
builds.append({
"id": build.pipeline_id,
"number": build.pipeline_id,
"status": build.status,
"event": "push",
"branch": build.branch,
"message": build.commit_message or "",
"author": build.author or "",
"started": int(build.started.timestamp()) if build.started else None,
"finished": int(build.finished.timestamp()) if build.finished else None,
"created": int(build.started.timestamp()) if build.started else 0,
})
except Exception as e:
logger.warning(f"Failed to fetch running builds: {e}")
try:
repo_builds = self.runner.woodpecker.get_builds(
woodpecker_repo,
limit=limit
)
for build in repo_builds:
if status and build.status.lower() != status.lower():
continue
builds.append({
"build_id": build.id,
"repo": repo_name,
"branch": build.branch,
"status": build.status,
"commit": build.commit[:8] if build.commit else "",
"started": build.started,
"web_url": build.web_url,
})
except Exception as e:
logger.warning(f"Failed to fetch builds for {repo_name}: {e}")
# Filter by status if requested
if status:
builds = [b for b in builds if b["status"].lower() == status.lower()]
return {"builds": builds[:limit]}
return builds[:limit]
except Exception as e:
logger.error(f"Failed to fetch builds: {e}")
return {"builds": [], "error": str(e)}
return []
def setup_api_handler(runner: "Runner", oauth=None):

View File

@@ -53,7 +53,7 @@ class AgentTaskInfo:
"repo": self.repo,
"platform": self.platform,
"task_type": self.task_type,
"started_at": self.started_at.isoformat() if self.started_at else None,
"start_time": self.started_at.isoformat() if self.started_at else None,
"elapsed_seconds": round(self.elapsed_seconds, 1),
}
@@ -70,10 +70,10 @@ class PoolStatus:
def to_dict(self) -> dict:
return {
"max_agents": self.max_agents,
"active": self.active,
"active_count": self.active,
"available": self.available,
"timeout_seconds": self.timeout_seconds,
"tasks": [t.to_dict() for t in self.tasks],
"active_tasks": [t.to_dict() for t in self.tasks],
}
@@ -253,13 +253,19 @@ class DashboardAPI:
Consider caching in production.
"""
states = self._runner.config.get("project", {}).get("states", {})
project = self._runner.config.get("project", {}).get("name", "CG")
counts = {}
for state_key, state_name in states.items():
# Skip certain states we don't track
if state_key in ("triage", "backlog", "done"):
continue
counts[state_name] = 0 # Default to 0, actual counts fetched on demand
try:
issues = self._runner.youtrack.get_issues_by_state(project, state_name)
counts[state_name] = len(issues)
except Exception as e:
logger.warning(f"Failed to get count for state {state_name}: {e}")
counts[state_name] = 0
return counts