AdGuard Browser Extension 部署指南:基于 Bamboo 的多管道构建与发布体系深度解析
AdGuard Browser Extension 部署指南:基于 Bamboo 的多管道构建与发布体系深度解析
AdGuard Browser Extension 是一个同时面向 Chrome、Edge、Firefox、Opera 等浏览器分发的开源扩展,其构建产物既要发布到各浏览器官方商店(Chrome Web Store、Mozilla Add-ons、Edge Add-ons),又要自托管到官方静态服务器用于自分发更新,还要附带 Chrome 的 CRX 自更新通道与 GitHub Release 附件。为了支撑如此复杂的多渠道发布,项目在 DEPLOYMENT.md 中系统性地定义了以 Atlassian Bamboo 为核心的构建/部署管道体系。本文以该文档为主体,结合仓库内真实的 Bamboo 配置、Dockerfile 多阶段构建与工具脚本,完整讲解 beta、release 以及两条 Firefox beta 管道的设计思路、部署目标、手动发布步骤与故障排查方法,帮助读者掌握从版本提升、本地校验到云端签名、多渠道部署的完整链路。
管道总览:四类构建与部署计划
DEPLOYMENT.md 用一张表格概括了整个仓库的 CI/CD 拓扑:每一类产物都由独立的 Build plan(构建计划) 和 Deploy plan(部署计划) 组成,二者通过 Bamboo 的 source-plan 字段关联。
| 类型 | Build plan | Deploy plan | 部署目标 |
|---|---|---|---|
| Beta | ADGEXT-BEBETASPECS |
deploy beta |
static.adtidy.org、Chrome WebStore MV3、GitHub |
| Release | ADGEXT-BERELEASESPECS |
deploy release |
static.adtidy.org、Chrome WebStore MV2、Chrome WebStore MV3、Addons Mozilla、Edge Add-ons、GitHub |
| Firefox standalone beta | ADGEXT-BEFIREFOXSTANDALONEBETASPECS |
deploy firefox standalone beta |
static.adtidy.org、GitHub |
| Firefox AMO beta | ADGEXT-BEFIREFOXAMOBETASPECS |
deploy firefox amo beta |
Addons Mozilla |
所有计划定义在 bamboo-specs/ 目录中,并通过 bamboo-specs/bamboo.yaml 统一注册。该文件本身并不包含计划内容,而是通过 YAML 的 !include 指令按顺序导入各计划:
- 构建计划:
build-beta.yaml、build-release.yaml、build-firefox-standalone-beta.yaml、build-firefox-amo-beta.yaml; - 部署计划:
deploy-beta.yaml、deploy-release.yaml、deploy-firefox-standalone-beta.yaml、deploy-firefox-amo-beta.yaml; - 权限计划:
permissions-beta.yaml、permissions-release.yaml、permissions-firefox-standalone-beta.yaml、permissions-firefox-amo-beta.yaml; - 配套计划:
tests.yaml、e2e-tests.yaml、increment.yaml(版本自增)、auto-build.yaml、auto-publish.yaml及其权限文件。
由此可以看出,AdGuard 的发布体系遵循“一个发布渠道 = 一个构建计划 + 一个部署计划 + 一份权限声明”的三件套模式,四个渠道互不干扰。
Beta 管道:构建与部署的完整生命周期
构建计划:两阶段校验
Beta 的构建计划 ADGEXT-BEBETASPECS(定义于 bamboo-specs/build-beta.yaml)包含两个 stage:
- Size and locales check(尺寸与语言包校验):并行执行两个 job——
- Check Bundle Size:通过 Docker 目标
bundle-size-check-output运行pnpm ${BUILD_TYPE} --zip与pnpm check-bundle-size beta; - Check translations:通过 Docker 目标
locales-check-output运行pnpm locales validate --min。
- Check Bundle Size:通过 Docker 目标
- Build(构建):通过 Docker 目标
beta-build-output执行pnpm beta --zip,产出build.txt、chrome.zip、chrome-mv3.zip、edge.zip;随后再通过beta-chrome-crx-output目标执行pnpm beta chrome-crx,额外产出chrome.crx与update.xml(用于 Chrome 的自更新通道)。
构建完成后,计划还会执行 VCS 打标签任务,生成 v${bamboo.inject.version}-beta 标签,并将构建号注入到后续部署步骤中。所有产物声明为 shared: true 的共享产物,供部署计划下载。
部署计划:三个环境
Beta 的部署计划定义于 bamboo-specs/deploy-beta.yaml,source-plan: ADGEXT-BEBETASPECS,release-naming: ${bamboo.inject.version}-beta,包含三个 environment:
- static.adtidy.org:下载
chrome.zip、chrome-mv3.zip、build.txt、chrome.crx、update.xml,然后执行./bamboo-deploy-publisher/deploy.sh chrome-extension-beta发布 Chrome beta 扩展包; - Chrome WebStore MV3:仅下载
chrome-mv3.zip,执行deploy.sh browser-extension-webstore-beta,将 MV3 beta 发布到 Chrome Web Store 的 Experimental(实验性)MV3 条目; - GitHub:下载
chrome.zip、chrome-mv3.zip、edge.zip、chrome.crx、build.txt,使用 Bamboo 变量bamboo.githubPublicRepoPassword作为 GitHub Token,执行deploy.sh browser-extension-github-beta,将各浏览器 bundle 附件到 GitHub beta Release。
每个环境的任务模板高度一致:clean → checkout 部署发布器仓库(bamboo-deploy-publisher)→ artifact-download 按需拉取产物 → 执行 deploy.sh 子命令。这种“一次构建、按环境挑产物”的写法是整组部署 YAML 的通用模式。
Release 管道:覆盖全部商店渠道
构建计划
Release 构建计划 ADGEXT-BERELEASESPECS(bamboo-specs/build-release.yaml)与 beta 结构相同(Size check + Build 两个 stage),但构建覆盖所有浏览器目标:Chrome MV2、Chrome MV3、Edge、Opera、Opera MV3、Firefox AMO、Firefox standalone。构建产物包括 chrome.zip、chrome-mv3.zip、edge.zip、opera.zip、opera-mv3.zip、firefox.zip(由 firefox-amo.zip 重命名而来)、source.zip 与 approval-notes.txt。同样会执行 inject-variables 与 VCS 打标签(v${bamboo.inject.version})。
部署计划:六个环境
Release 部署计划定义于 bamboo-specs/deploy-release.yaml,release-naming 不再带 -beta 后缀,环境清单:
- static.adtidy.org:同时执行
deploy.sh chrome-extension-release与deploy.sh firefox-extension-release。DEPLOYMENT.md 特别强调:此位置必须同时保留chrome.zip和chrome-mv3.zip,因为不同浏览器(例如 Brave)会从这里拉取静态构建包使用; - Chrome WebStore MV2:下载
chrome.zip,执行deploy.sh browser-extension-webstore-release-mv2; - Chrome WebStore MV3:下载
chrome-mv3.zip,执行deploy.sh browser-extension-webstore-release; - Addons Mozilla:下载
firefox.zip、source.zip、approval-notes.txt,执行deploy.sh browser-extension-amo向 AMO 提交; - Edge Addons:下载
edge.zip,执行deploy.sh browser-extension-edge向微软 Edge 插件商店提交; - GitHub:下载全部 bundle 与
build.txt,执行deploy.sh browser-extension-github-release发布 GitHub Release。
注意 Chrome WebStore 的 MV2 与 MV3 是两个独立环境、独立执行脚本;而 AMO 渠道之所以需要 source.zip 与 approval-notes.txt,是因为 Mozilla 的审核流程要求附带源码包与构建复现说明(详见后文“源码归档”小节)。
Firefox Beta 双管道:为什么必须拆分
Firefox beta 存在两种彼此独立的分发形态:
- Standalone(独立签名版):由 Mozilla 通过
go-webext签名后自分发,用户通过update.json更新通道自行安装; - AMO(商店托管版):提交到 Mozilla Add-ons 审核列表,由 AMO 在审核期间完成签名。
DEPLOYMENT.md 用专门一节解释了“Why two Firefox beta pipelines”:standalone 版需要等待 Mozilla 的签名服务,go-webext 在等待期间最长可阻塞到 20 分钟的 CI 超时;此前两种形态共用同一套构建/部署计划,一次缓慢或失败的签名会连带阻塞 AMO 的提交。拆分后,AMO 的构建与提交完全不受 standalone 签名状态影响,反之亦然。
Standalone Firefox Beta 管道
构建计划 ADGEXT-BEFIREFOXSTANDALONEBETASPECS(bamboo-specs/build-firefox-standalone-beta.yaml)只有一个 job Build and Sign Standalone,通过两次 docker build 完成:
- 先构建
firefox.zip(Docker 目标firefox-beta-build-output,对应 Dockerfile 中pnpm beta firefox-standalone --zip); - 再用
adguard/extension-builder:22.22--0.4.1--0镜像(预装了go-webext)执行签名(Docker 目标firefox-beta-sign-output),产出firefox.xpi与update.json。
签名阶段通过 --build-context firefox-artifacts=output/artifacts 复用第一步的产物,AMO 凭据通过 --build-arg FIREFOX_CLIENT_ID 与 --secret id=FIREFOX_CLIENT_SECRET 传入。签名命令为:
go-webext -v sign firefox -f 'firefox.zip' -s 'source.zip' -o 'firefox.xpi' -n "$(cat approval-notes.txt)"
共享产物为 build.txt、firefox.zip、firefox.xpi、update.json。当 Mozilla 签名缓慢触发 20 分钟超时时,重跑同一次构建即可——重跑是安全的,因为幂等性位于 go-webext 而非 Bamboo:第二次运行时它会检测到该版本已上传至 Mozilla,跳过重复上传、轮询签名状态并下载已签名的 .xpi。管道层面没有任何需要重试的逻辑。
部署计划 browser extension - deploy firefox standalone beta(bamboo-specs/deploy-firefox-standalone-beta.yaml):
- static.adtidy.org →
deploy.sh firefox-extension-beta,更新通道产物为firefox.zip、firefox.xpi、update.json、build.txt; - GitHub →
deploy.sh browser-extension-github-beta-firefox,将firefox.zip、firefox.xpi追加到 GitHub beta Release。
AMO Firefox Beta 管道
构建计划 ADGEXT-BEFIREFOXAMOBETASPECS(bamboo-specs/build-firefox-amo-beta.yaml)只有一个 job Build AMO:通过 Docker 目标 firefox-amo-beta-build-output 执行 pnpm beta firefox-amo --zip,产出未签名的 firefox-amo.zip。AMO 托管的附加组件不在本地签名,由 Mozilla 在审核时签名,因此该管道完全不受 go-webext 阻塞。
共享产物为 build.txt、firefox-amo.zip、source.zip、approval-notes.txt。部署计划 browser extension - deploy firefox amo beta(bamboo-specs/deploy-firefox-amo-beta.yaml)只有 Addons Mozilla 一个环境,执行 deploy.sh browser-extension-amo-beta,将 firefox-amo.zip + source.zip + approval-notes.txt 一并提交给 AMO 审核。
如何发布一个 Firefox Beta
两个 build plan 都声明了 triggers: [] 与 branches.create: manually,意味着只能由人在 Bamboo 上手动触发。DEPLOYMENT.md 给出的操作顺序:
- 同时运行 standalone 与 AMO 两个构建计划(二者独立、可并行);
- 各自完成后运行对应的部署计划,两个部署计划相互独立,可按任意顺序单独或同时执行;
- 若 standalone 签名超时,不要阻塞 AMO,让 AMO 照常提交;待 Mozilla 签名完成后重跑 standalone 构建以取回签名后的
.xpi。
准备一次新发布:七个关键步骤
DEPLOYMENT.md 指出,以下步骤对 beta 与 release 均适用,差异点会分别标注。下面结合 package.json 中真实存在的脚本逐一展开。
-
在
package.json中提升依赖库版本。需要更新的通常是@adguard/tsurlfilter、@adguard/tswebextension、@adguard/scriptlets等近期发布过的库。当前仓库中的依赖版本可作参照:@adguard/tsurlfilter: 6.0.3、@adguard/tswebextension: 5.0.3、@adguard/scriptlets: 2.5.1。命名规则:beta 使用-beta后缀(如5.5.0-beta),release 使用正式版本(如5.5.0)。 -
设置
TSURLFILTER_REF=""以禁用本地链接。仓库内的 bamboo-specs/scripts/clone-tsurlfilter.sh 默认TSURLFILTER_REF="",此时不会克隆 tsurlfilter 源码、直接使用 npm 版本;只有当该变量指向某个分支、commit 或 tag 时,才会用git archive克隆干净的源码目录并通过 bamboo-specs/scripts/link-tsurlfilter.sh 以pnpm link的方式链接本地构建的tswebextension(可选附带agtree、tsurlfilter、dnr-converter、css-tokenizer)。发布前必须置空,因为库已发布到 npm。clone-tsurlfilter.sh的注释还解释了为什么用git archive而非裸 clone:Docker 会对--build-context中每个文件做 checksum 以决定缓存是否命中,而裸 clone 的.git元数据每次克隆都不同、必然击穿缓存,git archive则能产出字节一致的输出,从而让 tsurlfilter 构建阶段命中缓存、耗时趋近于 0。 -
运行
pnpm dev确保 scriptlets 脚本是最新的(对应 package.json 中"dev": "cross-env BUILD_ENV=dev tsx tools/bundle.ts")。 -
运行
pnpm resources && pnpm resources:mv3更新过滤规则、公共后缀列表与 DNR ruleset。resources:mv3脚本会先pnpm remove @adguard/dnr-rulesets、再pnpm add -D @adguard/dnr-rulesets@~5.0,最后执行 tools/resources-mv3.ts,产物落入Extension/filters/下的各浏览器目录(如Extension/filters/chromium-mv3/declarative/的各个ruleset_*JSON)。 -
构建并检查包体积:
- Beta:
pnpm beta --zip,然后pnpm check-bundle-size beta; - Release:
pnpm release --zip,然后pnpm check-bundle-size release。
若尺寸差异在可接受范围内,运行
pnpm update-bundle-size beta(或release)更新基准;否则需排查体积增长原因。体积检查的实现见 tools/bundle-size/check.ts 与 tools/bundle-size/constants.ts:常量 值 含义 DEFAULT_SIZE_THRESHOLD_PERCENTAGE10 默认允许的体积增长阈值(百分比),可由 CLI --threshold覆盖MAX_MV3_SIZE_BYTES30 MB Chrome MV3 构建的硬性上限 MAX_FIREFOX_AMO_SIZE_BYTES200 MB AMO 提交整体大小上限 MAX_FIREFOX_SIZE_BYTES4 MB AMO 对 zip 内单个文件的限制(Firefox 浏览器本身并不强制) 检查工具同时还会检测 MV3 bundle 是否超限、通过
pnpm why检测重复的包版本,并把历史数据写入.bundle-sizes.json;tools/bundle-size/update.ts 负责用最新构建统计刷新该基准文件。 - Beta:
-
运行
pnpm locales validate校验翻译文件,如发现问题则创建翻译任务分发给译者。Bamboo 构建中对应的自动化校验是 Docker 目标locales-check-output内的pnpm locales validate --min。 -
合并 PR 并在 Bamboo 中触发构建。
此外,仓库还通过 increment.yaml(bamboo-specs/increment.yaml)在每次构建后自动递增版本号:构建产物 increment-output 会把修改后的 package.json 复制回工作树并执行 VCS commit,提交信息为 skipci: Automatic increment build number。package.json 中的版本号 5.5.2+3.build.20260825090125 正是该机制的产物。
部署权限控制
每个部署计划都配有对应的 permissions-*.yaml,遵循“部署计划 name 必须与权限文件中的 deployment.name 完全一致”的约束。以 bamboo-specs/permissions-firefox-standalone-beta.yaml 为例:
- 部署级权限:
extensions-developers与adguard-qa两个组拥有view权限; - 环境级权限:
static.adtidy.org与GitHub环境仅对extensions-developers开放view+deploy。
permissions-firefox-amo-beta.yaml 采用相同模式,仅环境改为 Addons Mozilla。因此,当某个部署计划报权限错误时,应优先核对部署 YAML 的 deployment.name 与权限 YAML 的 deployment.name 是否逐字符一致(这是 Troubleshooting 一节明确给出的排查方向之一)。
源码归档与 AMO 审核配套产物
Firefox 渠道(AMO 与 standalone 签名)都要求提交 source.zip 和 approval-notes.txt,二者由 bamboo-specs/scripts/archive-source.sh 在 Docker 构建阶段生成。该脚本的要点:
- 打包全部源码文件,排除
.git/、.gitignore命中的模式,以及Extension/filters/目录(但保留Extension/filters/firefox的过滤规则,因为 Firefox 构建需要它们); - 在
source.zip内的README.md末尾追加 “Building Instructions for Firefox Add-ons Review Team” 章节,给出仅依赖 Docker 的构建复现命令,例如:
并分别列出 AMO beta(扩展 IDdocker run --rm \ -v "$(pwd)":/workspace \ -w /workspace \ adguard/extension-builder:22.22--0.4.1--0 \ bash -c "pnpm install && pnpm release firefox-amo"adguardadblockeramobeta@adguard.com)与 standalone beta(扩展 IDadguardadblockerbeta@adguard.com)对应的pnpm beta firefox-amo/pnpm beta firefox-standalone命令; - 同步生成纯文本的
approval-notes.txt,通过 AMO API 的approval_notes字段提交,让审核员无需解包源码即可看到构建说明。
archive-source.sh 依赖同目录下的 bamboo-specs/scripts/generate-find-excludes.sh(在宿主机上、.git 可用时生成 gitignore-excludes.txt)与 parse-gitignore.sh(容器内 .git 不可用时的回退方案)。
Docker 多阶段构建:管道背后的构建矩阵
所有构建产物都来自仓库根目录的 Dockerfile,采用多阶段构建,配合 Bamboo YAML 中 docker build --target ... 的调用方式。以下 stage 与 DEPLOYMENT.md 描述的管道一一对应:
| Docker 目标 | 对应计划/阶段 | 主要产物 |
|---|---|---|
bundle-size-check-output |
beta/release 的 Size check | 体积检查标记文件 |
locales-check-output |
beta/release 的 Check translations | 语言包校验标记文件 |
beta-build-output |
Beta Build | build.txt、chrome.zip、chrome-mv3.zip、edge.zip |
beta-chrome-crx-output |
Beta Build(第二阶段) | chrome.crx、update.xml |
firefox-beta-build-output |
Firefox standalone beta 构建 | firefox.zip(由 firefox-standalone.zip 重命名)、update.json、source.zip、approval-notes.txt |
firefox-beta-sign-output |
Firefox standalone beta 签名 | firefox.xpi(依赖 --build-context firefox-artifacts) |
firefox-amo-beta-build-output |
Firefox AMO beta 构建 | firefox-amo.zip、source.zip、approval-notes.txt |
release-build-output |
Release Build | 全部浏览器 zip + source.zip + approval-notes.txt |
increment-output |
increment 计划 | 修改后的 package.json |
Dockerfile 还包含 tsurlfilter-build stage:当 TSURLFILTER_REF 非空时,从命名构建上下文复制 tsurlfilter 源码并执行 pnpm install + lerna run build,构建 @adguard/tswebextension 与 @adguard/dnr-rulesets;为空时则跳过,直接使用 package.json 声明的 npm 版本(对应发布流程步骤 2)。
Troubleshooting:常见故障与处理
DEPENDENCY.md 的 Troubleshooting 一节针对四个高频问题给出明确处理路径:
- Standalone 签名超时(20 分钟):Mozilla 响应慢时的预期行为,不影响 AMO。等 Mozilla 完成签名后重跑同一构建计划即可取回
.xpi。幂等性在go-webext侧:第二次运行会识别出版本已上传、跳过重复上传、轮询签名状态并下载签名产物;Bamboo 只是再次调用同一个签名步骤,管道层面无需任何重试逻辑。 - 部署失败、缺少产物:多半是部署计划在源构建计划完成之前被触发,或构建本身失败。确认源构建计划已产出全部共享产物后重跑部署。
- AMO 与 standalone 相互干扰:理论上不应发生——它们是独立的计划与独立产物。若出现串扰,逐个核对每个部署计划的
source-plan是否指向正确的构建计划,并确认两个构建计划基于同一 commit/版本运行。 - 部署计划权限错误:部署 YAML 中的
name必须与对应权限 YAML(permissions-firefox-standalone-beta.yaml/permissions-firefox-amo-beta.yaml)中的deployment.name完全一致。
小结
AdGuard Browser Extension 的发布体系是“Bamboo 计划编排 + Docker 多阶段构建 + 部署发布器脚本”三层结构的典型实践:构建阶段统一在 Docker 内完成、产出可共享的制品;部署阶段按渠道挑取产物、分发到自托管静态服务器、各浏览器商店与 GitHub Release;Firefox 特有的“独立签名”与“AMO 审核”双管道通过彻底解耦来规避签名阻塞。对于希望理解该项目发布机制、或参考其 CI/CD 设计的读者,建议从 DEPLOYMENT.md 入手,对照本文涉及的 bamboo-specs/bamboo.yaml、bamboo-specs/build-*.yaml、bamboo-specs/deploy-*.yaml、Dockerfile 与 tools/bundle-size/ 逐一阅读,即可还原整条从“提交代码”到“商店上架”的完整链路。