You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure DevOps扩展两级配置信息的API存储位置咨询

解决Azure DevOps扩展的组织/项目两级配置存储问题

嘿,我刚好在Azure DevOps扩展开发里踩过类似的配置存储坑,给你分享几个官方推荐的靠谱方案,完美适配你要的组织+项目两级配置需求:


首选方案:Extension Data Service(官方扩展数据服务)

这是微软专门为Azure DevOps扩展设计的配置存储方案,完全支持组织和项目级别的隔离存储,不需要依赖工作项字段,权限控制也刚好匹配你的需求——组织级配置需要组织管理员权限,项目级需要项目管理员权限。

1. 存储组织级配置

用ExtensionDataClient的setDocument方法,指定scopeType="Organization"即可:

import { ExtensionDataClient } from "azure-devops-extension-api";

async function saveOrganizationConfig(orgUrl: string, configData: { externalSystemUrl: string }) {
    const dataClient = await getClient(ExtensionDataClient, orgUrl);
    // 存储组织级配置,文档名可以自定义(比如"org-external-system-settings")
    await dataClient.setDocument(
        "com.your-company.your-extension-id", // 替换成你的扩展ID
        "org-external-system-settings",
        configData,
        { 
            scopeType: "Organization", 
            scopeName: orgUrl.split("/").pop() // 组织名称/ID
        }
    );
}

2. 存储项目级配置

逻辑和组织级几乎一致,只需要把scopeType改成"Project":

async function saveProjectConfig(projectUrl: string, configData: { isEnabled: boolean, externalUid: string }) {
    const dataClient = await getClient(ExtensionDataClient, projectUrl);
    await dataClient.setDocument(
        "com.your-company.your-extension-id",
        "project-extension-settings",
        configData,
        { 
            scopeType: "Project", 
            scopeName: projectUrl.split("/").pop() // 项目名称/ID
        }
    );
}

3. 读取并合并两级配置

当响应工作项事件时,你可以先读取组织级配置,再读取项目级配置,用项目级的配置覆盖组织级的对应字段:

async function getCombinedConfig(orgUrl: string, projectUrl: string) {
    const dataClient = await getClient(ExtensionDataClient, orgUrl);
    
    // 读取组织级配置(如果不存在则返回空对象)
    const orgConfig = await dataClient.getDocument(
        "com.your-company.your-extension-id",
        "org-external-system-settings",
        { scopeType: "Organization", scopeName: orgUrl.split("/").pop() }
    ).catch(() => ({}));

    // 读取项目级配置(如果不存在则返回空对象)
    const projectConfig = await dataClient.getDocument(
        "com.your-company.your-extension-id",
        "project-extension-settings",
        { scopeType: "Project", scopeName: projectUrl.split("/").pop() }
    ).catch(() => ({}));

    // 合并配置:项目级配置优先级更高
    return { ...orgConfig, ...projectConfig };
}

备选方案:利用Service Endpoints(适合外部系统连接场景)

如果你的组织级配置主要是外部系统URL、API密钥这类信息,其实可以用Azure DevOps原生的服务端点功能——它支持组织/项目级创建,自带安全存储(可以加密存储密钥),用户还能在Azure DevOps原生界面配置,不用你额外开发配置UI。

读取项目级服务端点的示例代码:

import { ServiceEndpointHttpClient } from "azure-devops-extension-api";

async function getExternalSystemEndpoint(projectUrl: string, endpointName: string) {
    const endpointClient = await getClient(ServiceEndpointHttpClient, projectUrl);
    const projectId = projectUrl.split("/").pop();
    const endpoints = await endpointClient.getServiceEndpoints(projectId);
    return endpoints.find(endpoint => endpoint.name === endpointName);
}

这两个方案都比你之前尝试的自定义工作项字段靠谱得多,完全避开了工作项类型关联的限制。我自己做的几个OSS扩展也是用Extension Data Service来存储层级配置的,稳定性没问题~

内容的提问来源于stack exchange,提问作者Jesper Lund Stocholm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:55:34