Beads 与 Azure DevOps(ADO)双向同步配置完全指南
【免费下载链接】beadsBeads - A memory upgrade for your coding agent项目地址: https://gitcode.com/GitHub_Trending/beads1/beads
本篇指南围绕 Beads 提供的bd ado sync命令展开,讲解如何将 Beads 中基于 Dolt 数据库的 issue 体系与 Azure DevOps 工作项(Work Item)进行双向同步。你将掌握连接配置、过滤条件、优先级/状态/类型映射、Agile/Scrum/CMMI 过程模板适配、冲突解决、协调扫描与故障排查等完整实战方案,并深入了解底层实现(对应仓库源码 cmd/bd/ado.go 与 internal/ado/ 包)。
一、功能概览与适用场景
Beads 通过bd ado sync实现与 Azure DevOps 的双向同步:
- Pull(导入):将 ADO 中新建/更新的工作项拉取为 Beads issue;
- Push(导出):将本地 Beads issue 推送为 ADO 工作项,包括创建与更新;
- 链接同步:将 Beads 的依赖关系(dependency)同步为 ADO 工作项关联(relations);
- 协调扫描(Reconciliation):周期性检测 ADO 中已被删除或不可读的工作项,避免本地残留"幽灵 issue"。
重要限制(Proxied-server 模式):bd ado sync、bd ado status、bd ado projects在 Beads 连接代理服务器(proxied server)时不受支持,会直接报错ado sync is not supported in proxied-server mode(见 cmd/bd/ado.go 中runADOSync的守卫逻辑)。这三个命令必须在拥有直接数据库访问权限的工作区中运行。
二、快速开始
2.1 使用配置项(推荐)
# 设置必需配置 bd config set ado.pat "your-personal-access-token" bd config set ado.org "your-organization" bd config set ado.project "your-project"2.2 使用环境变量
export AZURE_DEVOPS_PAT="your-personal-access-token" export AZURE_DEVOPS_ORG="your-organization" export AZURE_DEVOPS_PROJECT="your-project"2.3 执行同步
# 双向同步(先拉后推,默认) bd ado sync # 仅拉取(从 ADO 导入) bd ado sync --pull-only # 仅推送(导出到 ADO) bd ado sync --push-only # 预览模式,不做任何变更 bd ado sync --dry-run配置优先级:通过bd config set设置的配置键(config key)优先于环境变量。源码中getADOConfigValue(cmd/bd/ado.go)的读取顺序正是"先查存储配置,再回退到环境变量"。
安全存储:ado.pat是敏感密钥,存储在config.yaml(仓库级或用户全局级)中,永远不会写入共享数据库,因此 PAT 不会通过dolt push泄露。此外 internal/ado/types.go 中定义了SecretString类型,其String()与MarshalJSON()均返回[REDACTED],确保密钥不会出现在日志、JSON 输出或fmt格式化中。
三、连接配置详解
3.1 配置键与环境变量对照表
| 配置键 | 环境变量 | 是否必需 | 说明 |
|---|---|---|---|
ado.pat | AZURE_DEVOPS_PAT | 是 | 个人访问令牌(Personal Access Token) |
ado.org | AZURE_DEVOPS_ORG | 条件¹ | 组织名(如myorg) |
ado.url | AZURE_DEVOPS_URL | 条件¹ | 自定义基础 URL(本地部署的 ADO Server) |
ado.project | AZURE_DEVOPS_PROJECT | 条件² | 单个项目名 |
ado.projects | AZURE_DEVOPS_PROJECTS | 条件² | 逗号分隔的多项目名 |
¹
ado.org与ado.url必须设置其一:云版使用ado.org,本地部署(on-premises Azure DevOps Server)使用ado.url。²
ado.project与ado.projects至少配置其一。
源码中validateADOConfig(cmd/bd/ado.go)会依次校验 PAT、org/url、project 三个条件,缺失时会给出明确的错误提示。
3.2 连接参数的解析细节
getADOConfig在解析项目时有一个细节:它会同时读取ado.projects(复数)与ado.project(单数)两个来源,并通过tracker.ResolveProjectIDs合并解析;当存在多个项目时,第一个项目被用作 URL 构造的主项目(cfg.Project = cfg.Projects[0])。
环境变量映射由adoConfigToEnvVar完成,支持的映射如下:
| 配置键 | 环境变量 |
|---|---|
ado.pat | AZURE_DEVOPS_PAT |
ado.org | AZURE_DEVOPS_ORG |
ado.project | AZURE_DEVOPS_PROJECT |
ado.projects | AZURE_DEVOPS_PROJECTS |
ado.url | AZURE_DEVOPS_URL |
3.3 本地部署 ADO Server(On-Premises)
对于本地部署的 Azure DevOps Server,改用ado.url而非ado.org:
bd config set ado.url "https://tfs.company.com/DefaultCollection" bd config set ado.project "MyProject"底层 API 客户端通过WithBaseURL设置自定义基础 URL(internal/ado/client.go)。有一个值得注意的安全校验:validateURLScheme会拒绝非 HTTPS 的 URL,除非主机是localhost、127.0.0.1或::1(用于本地测试模拟服务器)。也就是说,指向公网或内网其他主机的明文 HTTP 地址会被直接拒绝。
3.4 多项目同步
单个命令跨多个项目同步:
bd config set ado.projects "ProjectA,ProjectB,ProjectC"多项目模式下,拉取查询会使用[System.TeamProject] IN (...)形式的 WIQL 子句;单项目则使用[System.TeamProject] = '...'(见 internal/ado/client.go 中buildPullWIQLMulti)。另外,bd ado sync还提供可重复的--project标志,在单次运行中覆盖ado.project/ado.projects配置。
3.5 用status与projects验证连接
# 查看当前 ADO 配置与同步状态(含脱敏后的 PAT,仅显示前 4 位) bd ado status # 以 JSON 输出(便于脚本解析) bd ado status --json # 列出令牌可访问的所有项目 bd ado projectsrunADOStatus在输出中会用maskADOToken对 PAT 脱敏(仅显示前 4 个字符加****,见 cmd/bd/ado.go),并输出Status: ✓ Configured或具体的缺失项错误。
四、过滤配置(Filters)
过滤器控制哪些 ADO 工作项参与同步。
4.1 配置键与 CLI 标志对照
| 配置键 | CLI 标志 | 说明 | 示例 |
|---|---|---|---|
ado.filter.area_path | --area-path | 区域路径(Area path,层级使用 UNDER 语义) | Project\Team |
ado.filter.iteration_path | --iteration-path | 迭代/冲刺路径 | Project\Sprint 1 |
ado.filter.types | --types | 工作项类型(逗号分隔) | Bug,Task,User Story |
ado.filter.states | --states | ADO 状态(逗号分隔) | New,Active,Resolved |
CLI 标志优先于配置值:buildADOPullFilters(cmd/bd/ado.go)通过cmd.Flags().Changed(...)判断标志是否被显式设置,只有未设置时才回退读取ado.filter.*配置。
双向语义:
- Pull 方向:过滤器限制 WIQL 查询(
--area-path/--iteration-path对应UNDER子句,--types/--states对应IN子句); - Push 方向:
--types与--states会先把 ADO 过滤值反向映射为 Beads 的类型与状态,再在推送前过滤本地 issue(见buildADOPushHooks的实现逻辑)。
4.2 生成的 WIQL 查询示例
SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject] = 'MyProject' AND [System.IsDeleted] = false AND [System.AreaPath] UNDER 'Project\Team' AND [System.WorkItemType] IN ('Bug', 'Task') AND [System.State] IN ('New', 'Active') ORDER BY [System.ChangedDate] ASC4.3 过滤值的合法性校验
PullFilters.Validate()(internal/ado/client.go)会对所有过滤值做白名单正则校验,防止 WIQL 注入:
- 区域/迭代路径:
^[a-zA-Z0-9 ._\\/-]+$ - 状态名:
^[a-zA-Z0-9 _]+$ - 组织名:
^[a-zA-Z0-9._-]+$ - 项目名:
^[a-zA-Z0-9 ._'-]+$
同时 WIQL 字面量统一经escapeWIQL转义(反斜杠翻倍、单引号翻倍),查询中的字符串全部转义后才拼接。增量拉取还会自动追加[System.ChangedDate] >= 'YYYY-MM-DD'子句(日期按 UTC 截断到天,见formatWIQLDate,因为 ADO 日期精度字段拒绝带时间部分的值)。
五、默认字段映射
5.1 优先级映射(双向但 P3/P4 有损)
| Beads 优先级 | ADO 优先级 | 方向 | 备注 |
|---|---|---|---|
| 0(Critical) | 1 | ↔ | |
| 1(High) | 2 | ↔ | |
| 2(Medium) | 3 | ↔ | 未知值默认 |
| 3(Low) | 4 | → | |
| 4(Backlog) | 4 | → | 有损:拉回时变成 P3 |
注意:Beads 的 P3 和 P4 都映射到 ADO 优先级 4。在空数据库上全新拉取时,ADO 4 会被映射回 Beads P3。因此对 P4 issue 而言,完整往返一次后原始优先级无法保留。
源码级缓解机制:adoFieldMapper(internal/ado/fieldmapper.go)的PriorityToTracker将 Beads 3、4 均映射为 ADO 4(有损方向);但 internal/ado/mapping.go 中IssueToTracker会在 Beads 优先级为 3 或 4 时把原始值写入元数据键beads_priority,而IssueToBeads在拉回时会优先从该元数据恢复原始优先级——只要该 issue 仍由 Beads 管理(即有本地元数据),往返可近似无损;只有"直接导入一个陌生 ADO 工作项"才会落到默认的 P3。
Bug 类型额外要求:ADO 的 Bug 工作项必须有 Severity 字段,映射如下:
| Beads 优先级 | ADO Severity |
|---|---|
| 0 | 1 - Critical |
| 1 | 2 - High |
| 2 | 3 - Medium |
| 3, 4 | 4 - Low |
该逻辑对应adoFieldMapper.SeverityForBug:0→1 - Critical、1→2 - High、2→3 - Medium、3/4→4 - Low,未知值默认3 - Medium。
5.2 状态映射
| Beads 状态 | 默认 ADO 状态 | 配置键 |
|---|---|---|
open | New | ado.state_map.open |
in_progress | Active | ado.state_map.in_progress |
blocked | Active+beads:blocked标签 | ado.state_map.blocked |
deferred | Removed | ado.state_map.deferred |
closed | Closed | ado.state_map.closed |
Blocked 状态的处理:ADO 没有原生的 blocked 状态。Beads 将blocked映射为Active并附加beads:blocked标签;拉回时,如果工作项状态为Active且带beads:blocked标签,则恢复为StatusBlocked(见 internal/ado/mapping.go 中IssueToBeads的恢复逻辑)。
自定义状态映射(适配你的过程模板):
# 示例:Scrum 模板 bd config set ado.state_map.open "To Do" bd config set ado.state_map.in_progress "In Progress" bd config set ado.state_map.closed "Done"adoFieldMapper在双向转换时都优先查找自定义stateMap(反向查表,大小写不敏感),未命中才回退 Agile 默认值;反向查表失败的 ADO 状态在拉取时默认映射为StatusOpen。
5.3 类型映射
| Beads 类型 | 默认 ADO 类型 | 配置键 |
|---|---|---|
bug | Bug | ado.type_map.bug |
feature | User Story | ado.type_map.feature |
task | Task | ado.type_map.task |
epic | Epic | ado.type_map.epic |
chore | Task | ado.type_map.chore |
反向映射(ADO → Beads)还会识别:
Product Backlog Item→feature(Scrum 模板)Issue→task
自定义示例:
# 示例:Scrum 模板 bd config set ado.type_map.feature "Product Backlog Item"TypeToTracker/TypeToBeads均采用"自定义表优先 + 大小写不敏感"的策略,未匹配的 ADO 类型默认映射为task。
六、过程模板配置(Process Template)
ADO 支持多种过程模板,各自的工作项类型与状态流转不同。默认映射基于 Agile 模板,使用其他模板时需覆盖相应映射。
6.1 Agile(默认)
无需任何配置,默认映射开箱即用。状态流转:
Bug: New → Active → Resolved → Closed Task: New → Active → Closed User Story: New → Active → Resolved → Closed Epic: New → Active → Resolved → Closed6.2 Scrum
bd config set ado.type_map.feature "Product Backlog Item" bd config set ado.state_map.open "New" bd config set ado.state_map.in_progress "Committed" bd config set ado.state_map.closed "Done"状态流转:
Product Backlog Item: New → Approved → Committed → Done Task: To Do → In Progress → Done Bug: New → Approved → Committed → Done6.3 CMMI
bd config set ado.type_map.feature "Requirement" bd config set ado.state_map.open "Proposed" bd config set ado.state_map.in_progress "Active" bd config set ado.state_map.closed "Closed"状态流转:
Requirement: Proposed → Active → Resolved → Closed Task: Proposed → Active → Closed Bug: Proposed → Active → Resolved → Closed6.4 状态转换处理(State Transition Handling)
当需要把工作项创建在非初始状态(例如推送一个已关闭的 issue)时,Beads 的执行策略是:
- 以初始状态创建工作项(如
New,ADO 可用的初始状态包括New、To Do、Proposed,见 internal/ado/statetransition.go 的initialStates); - 沿中间状态逐级转换直至目标状态;
- 示例:创建已关闭的 Bug →
New → Active → Resolved → Closed。
失败回退机制:transitionWorkItem会先尝试直接更新状态;若 ADO 返回400 Bad Request(说明过程模板不支持直接跳转),则自动按已知转换路径(defaultTransitions,覆盖 Agile/Scrum/CMMI 常见类型与状态组合)逐级推进;若路径未知则返回带原始错误上下文的报错。
七、同步选项(Sync Options)
7.1 同步方向
| 标志 | 说明 |
|---|---|
| (无) | 双向:先拉后推 |
--pull-only | 仅从 ADO 导入 |
--push-only | 仅导出到 ADO |
注意--pull-only与--push-only不能同时使用(源码会报错cannot use both --pull-only and --push-only)。
7.2 冲突解决策略
当同一 issue 在本地与 ADO 都发生过修改时:
| 标志 | 说明 |
|---|---|
--prefer-newer | 最近更新时间者胜出(默认) |
--prefer-local | 始终保留本地 Beads 版本 |
--prefer-ado | 始终采用 ADO 版本 |
三个冲突标志互斥:getADOConflictStrategy(cmd/bd/ado.go)会检测同时设置多个标志的情况并直接报错。底层对应tracker.ConflictTimestamp/ConflictLocal/ConflictExternal三种策略。
7.3 其他常用标志
| 标志 | 说明 |
|---|---|
--dry-run | 预览同步结果,不落任何变更 |
--no-create | 只更新已有工作项/issue,绝不新建(双向生效) |
--bootstrap-match | 首次同步时启用启发式标题匹配(见下文) |
--reconcile | 强制执行协调扫描(见下文) |
--issues | 按 Bead ID 或 ADO 工作项 ID 只同步指定 issue |
--parent | 只推送某 bead 及其后代(仅推送模式,与--issues互斥) |
--project | 本次运行的项目名,可重复,覆盖ado.project/ado.projects |
--states | 按工作项状态过滤(逗号分隔) |
--types | 按工作项类型过滤(逗号分隔) |
--no-create的底层行为:
- Pull 方向:
buildADOPullHooks的ShouldImport在无法通过 external_ref 或引导匹配关联到本地 issue 时,直接跳过(不新建); - Push 方向:
buildADOPushHooks的ShouldPush只允许推送"已带 ADO external ref"的本地 issue,未关联的绝不创建新工作项。
--bootstrap-match的底层行为:BootstrapMatcher(internal/ado/bootstrap.go)按优先级执行三种匹配策略:
- external_ref 精确匹配:本地 issue 的 ExternalRef 与 ADO 工作项 URL 一致;
- source_system 匹配:本地 issue 的 SourceSystem 中记录的 ADO ID 一致;
- 启发式匹配(需
--bootstrap-match开启):标题 + 类型 + 创建时间(时间窗口 24 小时)同时吻合。
匹配成功后会把已有本地 issue 直接关联到 ADO 工作项(写入 external_ref 与 source_system),从而避免首次同步产生大量重复 issue;出现多个候选时会输出歧义警告。bd ado status的 JSON 输出会包含bootstrap_matched计数,方便验证匹配结果。
7.4 协调扫描(Reconciliation)
协调扫描会重新检查 Beads 已跟踪的工作项,从而发现**在 ADO 中被删除(404)或已不可读(403)**的工作项,避免本地残留陈旧 issue。它不会在每次同步都运行——那样会对每个被跟踪项都多消耗一次 API 调用——因此采用周期性执行策略:
| 配置键 | 默认值 | 说明 |
|---|---|---|
ado.reconcile_interval | 10 | 每 N 次同步执行一次自动协调扫描 |
--reconcile可立即强制执行一次扫描;- 扫描发现 ADO 中已删除的工作项时,会以
ADO work item <id> deleted为原因自动关闭对应的本地 issue(见 cmd/bd/ado.go 中runADOSync的协调处理段); - 不可读(403)的工作项会输出访问被拒的警告,不关闭 issue。
两个容易混淆的配置键:ado.syncs_since_reconcile也会出现在 config 中,但它是 Beads 用来记录"距上次协调已同步几次"的计数器,由 internal/ado/reconcile.go 的IncrementCounter/ResetCounter自动维护,不是需要用户编辑的设置项。Reconciler.Reconcile按MaxBatchSize(200)批量抓取工作项,批量失败时会对单项逐一验证,精确区分 404(deleted)、403(denied)与其它错误。
八、依赖关系同步与链接(Links)
同步完成后(非 dry-run 且非 pull-only 模式),runADOSync还会额外执行一轮依赖链接推送(pushADOLinks):遍历所有带 ADO external ref 的本地 issue,把它们的依赖关系映射为 ADO 工作项关联(相关链接类型常量见 internal/ado/types.go,包括System.LinkTypes.Related、System.LinkTypes.Dependency-Forward/Reverse、System.LinkTypes.Hierarchy-Forward/Reverse等)。
这里有一个防止"误删人工链接"的细节:pushADOLinks会先构建managedTargets集合(Beads 正在跟踪的 ADO 工作项 ID),PushLinks只删除"目标在该集合内"的当前关联,从而保留人工创建的 Related / Predecessor-Successor 链接,避免被同步逻辑清空。拉取方向则通过ExtractLinkDeps把工作项关联恢复为 Beads 依赖。
九、PAT 权限要求
个人访问令牌(PAT)需要如下作用域:
| 作用域 | 访问级别 | 用途 |
|---|---|---|
| Work Items | Read & Write | 创建和更新工作项 |
生成地址:https://dev.azure.com/{org}/_usersettings/tokens。建议在受限范围的基础上按最小权限原则发放令牌。
十、往返保真:保留的元数据与描述转换
10.1 保留的 ADO 元数据
为保证"拉-改-推"往返的一致性,Beads 会把 ADO 特有字段存入 issue 元数据(buildMetadata/restoreMetadata,见 internal/ado/mapping.go):
| 元数据键 | 说明 |
|---|---|
ado.rev | ADO 修订号(rev) |
ado.area_path | 区域路径 |
ado.iteration_path | 迭代/冲刺路径 |
ado.story_points | 故事点估算 |
ado.remaining_work | 剩余工时 |
ado.severity | Bug 严重级别 |
推送时restoreMetadata会把这些值回写进 ADO 字段——例如先前从 ADO 拉取的 severity 会优先于按优先级计算出的 severity,避免往返改写;拉取时buildMetadata同步保留这些字段。另有ado.external_ref机制:每个 ADO 工作项的 Web 编辑 URL(.../_workitems/edit/{id})会被记录为本地 issue 的外部引用,作为两边的关联锚点。
10.2 描述(Description)转换
- Push(Beads → ADO):Markdown 转为 HTML。使用 goldmark 渲染器(XHTML 输出,不穿透原始 HTML,见 internal/ado/richtext.go 的
MarkdownToHTML); - Pull(ADO → Beads):HTML 转为 Markdown。
HTMLToMarkdown先用 bluemonday 的 UGC 策略清洗 HTML(剥离<script>、事件处理器等危险元素),再转换为 Markdown。
这意味着两边编辑器中都可以使用各自的原生富文本能力,而 Beads 侧始终以安全的 Markdown 落库。
十一、标签与标签映射(Tags and Labels)
- ADO 标签是分号分隔的字符串;Beads 标签是数组;
- 用户的标签通过 ADO 标签往返保留(
buildTagString以"; "连接,parseTags按;切分并 trim); - 内部
beads:*标签(如beads:blocked)在拉取时会被filterBeadsTags过滤掉,不会作为用户标签出现在本地 issue 中,但其存在与否决定了 blocked 状态能否恢复。
十二、API 限制与客户端行为
以下常量定义于 internal/ado/types.go,构成了 ADO 客户端的硬性边界:
| 限制项 | 值 |
|---|---|
| 单次 GET 请求最大批量 | 200 个工作项 |
| 最大响应体 | 50 MB |
| 请求超时 | 30 秒 |
| 最大重试次数 | 3(仅 GET 与 WIQL) |
| 重试退避 | 指数退避 + 抖动,尊重Retry-After响应头 |
重试语义值得注意(internal/ado/client.go 的isIdempotent):只有 GET 请求和 WIQL 查询(POST 到/wit/wiql)允许重试;创建/更新等变更型 POST/PATCH 请求不会重试,因为服务端可能已应用该变更。退避策略为RetryDelay(1s)* 2^attempt再加随机抖动;若响应带Retry-After头,则直接采用服务端指定的延迟且不再叠加抖动。响应体通过io.LimitReader限制为 50 MB,防止异常响应撑爆内存。永久性错误(400/401/403/404)立即返回APIError(携带状态码,调用方可用errors.As精确判断),只有 429 与 5xx 才进入重试。
十三、故障排查
13.1 常见错误
ado.pat not configured: set via 'bd config set ado.pat <token>' or AZURE_DEVOPS_PAT env var
bd config set ado.pat "your-pat-here" # 或 export AZURE_DEVOPS_PAT="your-pat-here"ado.org not configured: set via 'bd config set ado.org <org>' or AZURE_DEVOPS_ORG env var
bd config set ado.org "your-org" # 本地部署则用: bd config set ado.url "https://tfs.company.com/DefaultCollection"状态转换错误(400 Bad Request):通常意味着过程模板不支持直接的状态跳转。请核对ado.state_map.*配置与实际过程模板是否一致;若仍失败,Beads 会自动沿已知转换路径(Agile/Scrum/CMMI 内置路径)推进,参见 internal/ado/statetransition.go。
类型不存在错误:核对ado.type_map.*配置与项目内实际可用的工作项类型是否一致;可以用--types过滤来限制参与同步的类型。也可用bd ado projects验证令牌对目标项目的访问权限。
HTTPS 校验失败:ado.url使用非 localhost 的http://地址会被拒绝,请改用https://(本地联调可用http://localhost或http://127.0.0.1)。
13.2 调试手段
# 预览将要发生的同步(不产生任何变更) bd ado sync --dry-run # 查看当前配置 bd config get ado.pat bd config get ado.org bd config get ado.project # 检查连接配置与令牌状态 bd ado status bd ado status --json十四、推荐的上手路径
- 在 ADO 端按 第九节 生成具备 Work Items Read & Write 权限的 PAT;
- 使用
bd config set配置ado.pat、ado.org、ado.project(本地部署用ado.url); - 用
bd ado projects确认令牌可访问的项目,用bd ado status确认配置完整; - 首次同步前先跑
bd ado sync --dry-run预览;若本地已有大量 issue,可配合--bootstrap-match减少重复创建; - 正式执行
bd ado sync,并根据实际过程模板调整ado.state_map.*与ado.type_map.*; - 周期性同步可依赖内置协调扫描(
ado.reconcile_interval,默认 10 次)自动清理 ADO 侧已删除的工作项。
提示:更完整的 Beads 集成生态可参考 docs/integrations/index.md;
bd ado相关命令的实现细节集中在 cmd/bd/ado.go,同步引擎与数据模型分别在 internal/tracker/ 与 internal/ado/ 中。
【免费下载链接】beadsBeads - A memory upgrade for your coding agent项目地址: https://gitcode.com/GitHub_Trending/beads1/beads
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考