mirror of
https://github.com/OpenHands/OpenHands.git
synced 2025-12-26 05:48:36 +08:00
Add ENABLE_AZURE_DEVOPS feature flag to disable Azure DevOps UI on cloud
- Add ENABLE_AZURE_DEVOPS constant to enterprise/server/auth/constants.py - Add AZURE_DEVOPS_APP_CLIENT_ID and AZURE_DEVOPS_APP_CLIENT_SECRET constants - Update SaaSServerConfig to include enable_azure_devops field - Add ENABLE_AZURE_DEVOPS to FEATURE_FLAGS and PROVIDERS_CONFIGURED in get_config() - Update frontend git-settings.tsx to conditionally render Azure DevOps section based on FEATURE_FLAGS.ENABLE_AZURE_DEVOPS - Import ENABLE_AZURE_DEVOPS in enterprise/saas_server.py - Add ENABLE_AZURE_DEVOPS to frontend TypeScript types, mocks, and test files This ensures the 'Connect Azure DevOps Account' interface only appears when Azure DevOps OAuth credentials are configured, similar to existing patterns for Jira and Linear integrations.
This commit is contained in:
parent
b532a5e7fe
commit
d25650efb5
@ -10,6 +10,7 @@ from fastapi.middleware.cors import CORSMiddleware # noqa: E402
|
||||
from fastapi.responses import JSONResponse # noqa: E402
|
||||
from server.auth.auth_error import ExpiredError, NoCredentialsError # noqa: E402
|
||||
from server.auth.constants import ( # noqa: E402
|
||||
ENABLE_AZURE_DEVOPS,
|
||||
ENABLE_JIRA,
|
||||
ENABLE_JIRA_DC,
|
||||
ENABLE_LINEAR,
|
||||
|
||||
@ -17,7 +17,10 @@ GITLAB_APP_CLIENT_ID = os.getenv('GITLAB_APP_CLIENT_ID', '').strip()
|
||||
GITLAB_APP_CLIENT_SECRET = os.getenv('GITLAB_APP_CLIENT_SECRET', '').strip()
|
||||
BITBUCKET_APP_CLIENT_ID = os.getenv('BITBUCKET_APP_CLIENT_ID', '').strip()
|
||||
BITBUCKET_APP_CLIENT_SECRET = os.getenv('BITBUCKET_APP_CLIENT_SECRET', '').strip()
|
||||
AZURE_DEVOPS_APP_CLIENT_ID = os.getenv('AZURE_DEVOPS_APP_CLIENT_ID', '').strip()
|
||||
AZURE_DEVOPS_APP_CLIENT_SECRET = os.getenv('AZURE_DEVOPS_APP_CLIENT_SECRET', '').strip()
|
||||
ENABLE_ENTERPRISE_SSO = os.getenv('ENABLE_ENTERPRISE_SSO', '').strip()
|
||||
ENABLE_AZURE_DEVOPS = os.environ.get('ENABLE_AZURE_DEVOPS', 'false') == 'true'
|
||||
ENABLE_JIRA = os.environ.get('ENABLE_JIRA', 'false') == 'true'
|
||||
ENABLE_JIRA_DC = os.environ.get('ENABLE_JIRA_DC', 'false') == 'true'
|
||||
ENABLE_LINEAR = os.environ.get('ENABLE_LINEAR', 'false') == 'true'
|
||||
|
||||
@ -8,7 +8,9 @@ import jwt
|
||||
import requests # type: ignore
|
||||
from fastapi import HTTPException
|
||||
from server.auth.constants import (
|
||||
AZURE_DEVOPS_APP_CLIENT_ID,
|
||||
BITBUCKET_APP_CLIENT_ID,
|
||||
ENABLE_AZURE_DEVOPS,
|
||||
ENABLE_ENTERPRISE_SSO,
|
||||
ENABLE_JIRA,
|
||||
ENABLE_JIRA_DC,
|
||||
@ -84,6 +86,7 @@ class SaaSServerConfig(ServerConfig):
|
||||
maintenance_start_time: str = os.environ.get(
|
||||
'MAINTENANCE_START_TIME', ''
|
||||
) # Timestamp in EST e.g 2025-07-29T14:18:01.219616-04:00
|
||||
enable_azure_devops = ENABLE_AZURE_DEVOPS
|
||||
enable_jira = ENABLE_JIRA
|
||||
enable_jira_dc = ENABLE_JIRA_DC
|
||||
enable_linear = ENABLE_LINEAR
|
||||
@ -160,6 +163,9 @@ class SaaSServerConfig(ServerConfig):
|
||||
if BITBUCKET_APP_CLIENT_ID:
|
||||
providers_configured.append(ProviderType.BITBUCKET)
|
||||
|
||||
if AZURE_DEVOPS_APP_CLIENT_ID:
|
||||
providers_configured.append(ProviderType.AZURE_DEVOPS)
|
||||
|
||||
if ENABLE_ENTERPRISE_SSO:
|
||||
providers_configured.append(ProviderType.ENTERPRISE_SSO)
|
||||
|
||||
@ -171,6 +177,7 @@ class SaaSServerConfig(ServerConfig):
|
||||
'FEATURE_FLAGS': {
|
||||
'ENABLE_BILLING': self.enable_billing,
|
||||
'HIDE_LLM_SETTINGS': self.hide_llm_settings,
|
||||
'ENABLE_AZURE_DEVOPS': self.enable_azure_devops,
|
||||
'ENABLE_JIRA': self.enable_jira,
|
||||
'ENABLE_JIRA_DC': self.enable_jira_dc,
|
||||
'ENABLE_LINEAR': self.enable_linear,
|
||||
|
||||
@ -123,6 +123,7 @@ describe("ExpandableMessage", () => {
|
||||
ENABLE_JIRA: false,
|
||||
ENABLE_JIRA_DC: false,
|
||||
ENABLE_LINEAR: false,
|
||||
ENABLE_AZURE_DEVOPS: false,
|
||||
},
|
||||
});
|
||||
const RouterStub = createRoutesStub([
|
||||
|
||||
@ -38,6 +38,7 @@ describe("PaymentForm", () => {
|
||||
ENABLE_JIRA: false,
|
||||
ENABLE_JIRA_DC: false,
|
||||
ENABLE_LINEAR: false,
|
||||
ENABLE_AZURE_DEVOPS: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@ -80,6 +80,7 @@ describe("frontend/routes/_oh", () => {
|
||||
ENABLE_JIRA: false,
|
||||
ENABLE_JIRA_DC: false,
|
||||
ENABLE_LINEAR: false,
|
||||
ENABLE_AZURE_DEVOPS: false,
|
||||
},
|
||||
});
|
||||
|
||||
@ -118,6 +119,7 @@ describe("frontend/routes/_oh", () => {
|
||||
ENABLE_JIRA: false,
|
||||
ENABLE_JIRA_DC: false,
|
||||
ENABLE_LINEAR: false,
|
||||
ENABLE_AZURE_DEVOPS: false,
|
||||
},
|
||||
});
|
||||
|
||||
@ -202,6 +204,7 @@ describe("frontend/routes/_oh", () => {
|
||||
ENABLE_JIRA: false,
|
||||
ENABLE_JIRA_DC: false,
|
||||
ENABLE_LINEAR: false,
|
||||
ENABLE_AZURE_DEVOPS: false,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -24,6 +24,7 @@ const VALID_OSS_CONFIG: GetConfigResponse = {
|
||||
ENABLE_JIRA: false,
|
||||
ENABLE_JIRA_DC: false,
|
||||
ENABLE_LINEAR: false,
|
||||
ENABLE_AZURE_DEVOPS: false,
|
||||
},
|
||||
};
|
||||
|
||||
@ -37,6 +38,7 @@ const VALID_SAAS_CONFIG: GetConfigResponse = {
|
||||
ENABLE_JIRA: false,
|
||||
ENABLE_JIRA_DC: false,
|
||||
ENABLE_LINEAR: false,
|
||||
ENABLE_AZURE_DEVOPS: false,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -404,6 +404,7 @@ describe("Settings 404", () => {
|
||||
ENABLE_JIRA: false,
|
||||
ENABLE_JIRA_DC: false,
|
||||
ENABLE_LINEAR: false,
|
||||
ENABLE_AZURE_DEVOPS: false,
|
||||
},
|
||||
});
|
||||
const error = createAxiosNotFoundErrorObject();
|
||||
@ -429,6 +430,7 @@ describe("Setup Payment modal", () => {
|
||||
ENABLE_JIRA: false,
|
||||
ENABLE_JIRA_DC: false,
|
||||
ENABLE_LINEAR: false,
|
||||
ENABLE_AZURE_DEVOPS: false,
|
||||
},
|
||||
});
|
||||
const error = createAxiosNotFoundErrorObject();
|
||||
|
||||
@ -73,6 +73,7 @@ describe("Settings Billing", () => {
|
||||
ENABLE_JIRA: false,
|
||||
ENABLE_JIRA_DC: false,
|
||||
ENABLE_LINEAR: false,
|
||||
ENABLE_AZURE_DEVOPS: false,
|
||||
},
|
||||
},
|
||||
isLoading: false,
|
||||
@ -128,6 +129,7 @@ describe("Settings Billing", () => {
|
||||
ENABLE_JIRA: false,
|
||||
ENABLE_JIRA_DC: false,
|
||||
ENABLE_LINEAR: false,
|
||||
ENABLE_AZURE_DEVOPS: false,
|
||||
},
|
||||
},
|
||||
isLoading: false,
|
||||
@ -152,6 +154,7 @@ describe("Settings Billing", () => {
|
||||
ENABLE_JIRA: false,
|
||||
ENABLE_JIRA_DC: false,
|
||||
ENABLE_LINEAR: false,
|
||||
ENABLE_AZURE_DEVOPS: false,
|
||||
},
|
||||
},
|
||||
isLoading: false,
|
||||
|
||||
@ -13,6 +13,7 @@ export interface GetConfigResponse {
|
||||
ENABLE_JIRA: boolean;
|
||||
ENABLE_JIRA_DC: boolean;
|
||||
ENABLE_LINEAR: boolean;
|
||||
ENABLE_AZURE_DEVOPS: boolean;
|
||||
};
|
||||
MAINTENANCE?: {
|
||||
startTime: string;
|
||||
|
||||
@ -180,6 +180,7 @@ export const handlers = [
|
||||
ENABLE_JIRA: false,
|
||||
ENABLE_JIRA_DC: false,
|
||||
ENABLE_LINEAR: false,
|
||||
ENABLE_AZURE_DEVOPS: false,
|
||||
},
|
||||
// Uncomment the following to test the maintenance banner
|
||||
// MAINTENANCE: {
|
||||
|
||||
@ -128,6 +128,9 @@ function GitSettingsScreen() {
|
||||
!bitbucketHostInputHasValue &&
|
||||
!azureDevOpsHostInputHasValue;
|
||||
const shouldRenderExternalConfigureButtons = isSaas && config.APP_SLUG;
|
||||
const shouldRenderAzureDevOpsSection =
|
||||
shouldRenderExternalConfigureButtons &&
|
||||
config?.FEATURE_FLAGS?.ENABLE_AZURE_DEVOPS;
|
||||
const shouldRenderProjectManagementIntegrations =
|
||||
config?.FEATURE_FLAGS?.ENABLE_JIRA ||
|
||||
config?.FEATURE_FLAGS?.ENABLE_JIRA_DC ||
|
||||
@ -153,7 +156,7 @@ function GitSettingsScreen() {
|
||||
</>
|
||||
)}
|
||||
|
||||
{shouldRenderExternalConfigureButtons && !isLoading && (
|
||||
{shouldRenderAzureDevOpsSection && !isLoading && (
|
||||
<>
|
||||
<div className="pb-1 mt-6 flex flex-col">
|
||||
<h3 className="text-xl font-medium text-white">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user