Compare commits

...

2 Commits

Author SHA1 Message Date
openhands
8656776a84 fix: remove unused ENABLE_AZURE_DEVOPS import from saas_server
Co-authored-by: openhands <openhands@all-hands.dev>
2025-11-25 20:53:38 +00:00
openhands
d25650efb5 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.
2025-11-25 18:24:14 +00:00
11 changed files with 28 additions and 1 deletions

View File

@@ -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'

View File

@@ -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,

View File

@@ -123,6 +123,7 @@ describe("ExpandableMessage", () => {
ENABLE_JIRA: false,
ENABLE_JIRA_DC: false,
ENABLE_LINEAR: false,
ENABLE_AZURE_DEVOPS: false,
},
});
const RouterStub = createRoutesStub([

View File

@@ -38,6 +38,7 @@ describe("PaymentForm", () => {
ENABLE_JIRA: false,
ENABLE_JIRA_DC: false,
ENABLE_LINEAR: false,
ENABLE_AZURE_DEVOPS: false,
},
});
});

View File

@@ -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,
},
});

View File

@@ -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,
},
};

View File

@@ -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();

View File

@@ -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,

View File

@@ -13,6 +13,7 @@ export interface GetConfigResponse {
ENABLE_JIRA: boolean;
ENABLE_JIRA_DC: boolean;
ENABLE_LINEAR: boolean;
ENABLE_AZURE_DEVOPS: boolean;
};
MAINTENANCE?: {
startTime: string;

View File

@@ -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: {

View File

@@ -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">