From 8af1f1cac9f33ef97a17093db7b931efcbb68f3b Mon Sep 17 00:00:00 2001 From: Robert Brennan Date: Fri, 4 Jul 2025 03:55:54 -0400 Subject: [PATCH] Add labels support to PR and MR creation tools (#9402) Co-authored-by: openhands --- openhands/integrations/github/github_service.py | 11 +++++++++++ openhands/integrations/gitlab/gitlab_service.py | 6 ++++++ openhands/server/routes/mcp.py | 8 ++++++++ 3 files changed, 25 insertions(+) diff --git a/openhands/integrations/github/github_service.py b/openhands/integrations/github/github_service.py index d31ab76cf4..c547166f68 100644 --- a/openhands/integrations/github/github_service.py +++ b/openhands/integrations/github/github_service.py @@ -470,6 +470,7 @@ class GitHubService(BaseGitService, GitService): title: str, body: str | None = None, draft: bool = True, + labels: list[str] | None = None, ) -> str: """ Creates a PR using user credentials @@ -481,6 +482,7 @@ class GitHubService(BaseGitService, GitService): title: The title of the pull request (optional, defaults to a generic title) body: The body/description of the pull request (optional) draft: Whether to create the PR as a draft (optional, defaults to False) + labels: A list of labels to apply to the pull request (optional) Returns: - PR URL when successful @@ -507,6 +509,15 @@ class GitHubService(BaseGitService, GitService): url=url, params=payload, method=RequestMethod.POST ) + # Add labels if provided (PRs are a type of issue in GitHub's API) + if labels and len(labels) > 0: + pr_number = response['number'] + labels_url = f'{self.BASE_URL}/repos/{repo_name}/issues/{pr_number}/labels' + labels_payload = {'labels': labels} + await self._make_request( + url=labels_url, params=labels_payload, method=RequestMethod.POST + ) + # Return the HTML URL of the created PR return response['html_url'] diff --git a/openhands/integrations/gitlab/gitlab_service.py b/openhands/integrations/gitlab/gitlab_service.py index 5bc00e7a25..78812c1003 100644 --- a/openhands/integrations/gitlab/gitlab_service.py +++ b/openhands/integrations/gitlab/gitlab_service.py @@ -462,6 +462,7 @@ class GitLabService(BaseGitService, GitService): target_branch: str, title: str, description: str | None = None, + labels: list[str] | None = None, ) -> str: """ Creates a merge request in GitLab @@ -472,6 +473,7 @@ class GitLabService(BaseGitService, GitService): target_branch: The name of the branch you want the changes merged into title: The title of the merge request (optional, defaults to a generic title) description: The description of the merge request (optional) + labels: A list of labels to apply to the merge request (optional) Returns: - MR URL when successful @@ -494,6 +496,10 @@ class GitLabService(BaseGitService, GitService): 'description': description, } + # Add labels if provided + if labels and len(labels) > 0: + payload['labels'] = ','.join(labels) + # Make the POST request to create the MR response, _ = await self._make_request( url=url, params=payload, method=RequestMethod.POST diff --git a/openhands/server/routes/mcp.py b/openhands/server/routes/mcp.py index 35ce7c2c08..f858593ea6 100644 --- a/openhands/server/routes/mcp.py +++ b/openhands/server/routes/mcp.py @@ -89,6 +89,9 @@ async def create_pr( title: Annotated[str, Field(description='PR Title')], body: Annotated[str | None, Field(description='PR body')], draft: Annotated[bool, Field(description='Whether PR opened is a draft')] = True, + labels: Annotated[ + list[str] | None, Field(description='Labels to apply to the PR') + ] = None, ) -> str: """Open a PR in GitHub""" @@ -129,6 +132,7 @@ async def create_pr( title=title, body=body, draft=draft, + labels=labels, ) if conversation_id: @@ -156,6 +160,9 @@ async def create_mr( ), ], description: Annotated[str | None, Field(description='MR description')], + labels: Annotated[ + list[str] | None, Field(description='Labels to apply to the MR') + ] = None, ) -> str: """Open a MR in GitLab""" @@ -197,6 +204,7 @@ async def create_mr( target_branch=target_branch, title=title, description=description, + labels=labels, ) if conversation_id and user_id: