[Feat]: Add suggested tasks for Gitlab (#8049)

This commit is contained in:
Rohit Malhotra
2025-04-24 13:26:52 -04:00
committed by GitHub
parent 50baf3fd18
commit e694fc2d58
12 changed files with 298 additions and 41 deletions

View File

@@ -10,6 +10,8 @@ from openhands.integrations.service_types import (
ProviderType,
Repository,
RequestMethod,
SuggestedTask,
TaskType,
UnknownException,
User,
)
@@ -106,7 +108,7 @@ class GitLabService(BaseGitService, GitService):
except httpx.HTTPError as e:
raise self.handle_http_error(e)
async def execute_graphql_query(self, query: str, variables: dict[str, Any]) -> Any:
async def execute_graphql_query(self, query: str, variables: dict[str, Any] = {}) -> Any:
"""
Execute a GraphQL query against the GitLab GraphQL API
@@ -244,6 +246,138 @@ class GitLabService(BaseGitService, GitService):
for repo in all_repos
]
async def get_suggested_tasks(self) -> list[SuggestedTask]:
"""Get suggested tasks for the authenticated user across all repositories.
Returns:
- Merge requests authored by the user.
- Issues assigned to the user.
"""
# Get user info to use in queries
user = await self.get_user()
username = user.login
# GraphQL query to get merge requests
query = """
query GetUserTasks {
currentUser {
authoredMergeRequests(state: opened, sort: UPDATED_DESC, first: 100) {
nodes {
id
iid
title
project {
fullPath
}
conflicts
mergeStatus
pipelines(first: 1) {
nodes {
status
}
}
discussions(first: 100) {
nodes {
notes {
nodes {
resolvable
resolved
}
}
}
}
}
}
}
}
"""
try:
tasks: list[SuggestedTask] = []
# Get merge requests using GraphQL
response = await self.execute_graphql_query(query)
data = response.get('currentUser', {})
# Process merge requests
merge_requests = data.get('authoredMergeRequests', {}).get('nodes', [])
for mr in merge_requests:
repo_name = mr.get('project', {}).get('fullPath', '')
mr_number = mr.get('iid')
title = mr.get('title', '')
# Start with default task type
task_type = TaskType.OPEN_PR
# Check for specific states
if mr.get('conflicts'):
task_type = TaskType.MERGE_CONFLICTS
elif (
mr.get('pipelines', {}).get('nodes', [])
and mr.get('pipelines', {}).get('nodes', [])[0].get('status')
== 'FAILED'
):
task_type = TaskType.FAILING_CHECKS
else:
# Check for unresolved comments
has_unresolved_comments = False
for discussion in mr.get('discussions', {}).get('nodes', []):
for note in discussion.get('notes', {}).get('nodes', []):
if note.get('resolvable') and not note.get('resolved'):
has_unresolved_comments = True
break
if has_unresolved_comments:
break
if has_unresolved_comments:
task_type = TaskType.UNRESOLVED_COMMENTS
# Only add the task if it's not OPEN_PR
if task_type != TaskType.OPEN_PR:
tasks.append(
SuggestedTask(
git_provider=ProviderType.GITLAB,
task_type=task_type,
repo=repo_name,
issue_number=mr_number,
title=title,
)
)
# Get assigned issues using REST API
url = f"{self.BASE_URL}/issues"
params = {
"assignee_username": username,
"state": "opened",
"scope": "assigned_to_me"
}
issues_response, _ = await self._make_request(
method=RequestMethod.GET,
url=url,
params=params
)
# Process issues
for issue in issues_response:
repo_name = issue.get('references', {}).get('full', '').split('#')[0].strip()
issue_number = issue.get('iid')
title = issue.get('title', '')
tasks.append(
SuggestedTask(
git_provider=ProviderType.GITLAB,
task_type=TaskType.OPEN_ISSUE,
repo=repo_name,
issue_number=issue_number,
title=title,
)
)
return tasks
except Exception:
return []
gitlab_service_cls = os.environ.get(
'OPENHANDS_GITLAB_SERVICE_CLS',