Files
OpenHands/openhands/integrations/utils.py
Pierrick Hymbert e7934ea6e5 feat(bitbucket): supports cloud and server APIs (#11052)
Co-authored-by: Ray Myers <ray.myers@gmail.com>
Co-authored-by: Chris Bagwell <chris@cnpbagwell.com>
Co-authored-by: CHANGE <joe.laverty@openhands.dev>
Co-authored-by: Joe Laverty <jlav@users.noreply.github.com>
2026-03-03 10:51:43 -05:00

101 lines
3.5 KiB
Python

from pydantic import SecretStr
from openhands.core.logger import openhands_logger as logger
from openhands.integrations.azure_devops.azure_devops_service import (
AzureDevOpsServiceImpl as AzureDevOpsService,
)
from openhands.integrations.bitbucket.bitbucket_service import BitBucketService
from openhands.integrations.bitbucket_data_center.bitbucket_dc_service import (
BitbucketDCService,
)
from openhands.integrations.forgejo.forgejo_service import ForgejoService
from openhands.integrations.github.github_service import GitHubService
from openhands.integrations.gitlab.gitlab_service import GitLabService
from openhands.integrations.provider import ProviderType
async def validate_provider_token(
token: SecretStr, base_domain: str | None = None
) -> ProviderType | None:
"""Determine whether a token is for GitHub, GitLab, Bitbucket, Bitbucket Data Center, or Azure DevOps by attempting to get user info from the services.
Args:
token: The token to check
base_domain: Optional base domain for the service
Returns:
'github' if it's a GitHub token
'gitlab' if it's a GitLab token
'bitbucket' if it's a Bitbucket token
'azure_devops' if it's an Azure DevOps token
None if the token is invalid for all services
"""
# Skip validation for empty tokens
if token is None:
return None # type: ignore[unreachable]
# Try GitHub first
github_error = None
try:
github_service = GitHubService(token=token, base_domain=base_domain)
await github_service.verify_access()
return ProviderType.GITHUB
except Exception as e:
github_error = e
# Try GitLab next
gitlab_error = None
try:
gitlab_service = GitLabService(token=token, base_domain=base_domain)
await gitlab_service.get_user()
return ProviderType.GITLAB
except Exception as e:
gitlab_error = e
# Try Forgejo if a base_domain was provided (custom instances may not contain
# the substring 'forgejo' or 'codeberg')
forgejo_error = None
if base_domain:
try:
forgejo_service = ForgejoService(token=token, base_domain=base_domain)
await forgejo_service.get_user()
return ProviderType.FORGEJO
except Exception as e:
forgejo_error = e
# Try Bitbucket next
bitbucket_error = None
try:
bitbucket_service = BitBucketService(token=token, base_domain=base_domain)
await bitbucket_service.get_user()
return ProviderType.BITBUCKET
except Exception as e:
bitbucket_error = e
# Try Bitbucket Data Center if a base_domain was provided (always self-hosted)
bitbucket_dc_error = None
if base_domain:
try:
bitbucket_dc_service = BitbucketDCService(
token=token, base_domain=base_domain
)
await bitbucket_dc_service.verify_access()
return ProviderType.BITBUCKET_DATA_CENTER
except Exception as e:
bitbucket_dc_error = e
# Try Azure DevOps last
azure_devops_error = None
try:
azure_devops_service = AzureDevOpsService(token=token, base_domain=base_domain)
await azure_devops_service.get_user()
return ProviderType.AZURE_DEVOPS
except Exception as e:
azure_devops_error = e
logger.debug(
f'Failed to validate token: {github_error} \n {gitlab_error} \n {forgejo_error} \n {bitbucket_error} \n {bitbucket_dc_error} \n {azure_devops_error}'
)
return None