返回 文章 apply CMS 文章

在 Cloudflare 上为百万仓库运行 CI/CD:用 TypeScript 工作流替代 YAML

用 TypeScript 工作流在 Cloudflare 上构建可定制、沙箱化的 CI/CD 管道,支持自愈 AI 代理。

CloudflareCI/CDWorkflowsSandbox
成长分 / 100 70 综合收获、行动、留存与影响

在 Cloudflare 上为百万仓库运行 CI/CD:用 TypeScript 工作流替代 YAML
为什么值得读了解如何用 TypeScript 替代 YAML 定义 CI/CD 管道,避免 YAML 疲劳。

学习如何利用 Cloudflare Workflows 和 Sandbox 构建安全、隔离的 CI 步骤。

关键洞察
  1. CI/CD 管道本质上是一个工作流,每个步骤可转换为 step.do()。
  2. CI SDK 允许在沙箱环境中运行构建、lint、测试等步骤,并支持依赖缓存。
  3. 通过 wrangler 配置中的 events 字段,可直接将 artifact push 事件触发工作流实例。
转成行动

深入阅读

正文与原文对照

原文保真覆盖:全文原文字符:16614

我们正朝着这样一个世界迈进:你可以完全在 Cloudflare 上存储、构建、测试和部署代码。我们用 Artifacts 构建了第一块拼图,这是一种可扩展到数百万仓库的、带版本管理的代码存储。

我们通过构建在 Cloudflare Workflows 之上的 CI SDK,把存储、构建和部署这几个环节串联起来,让你可以在 Cloudflare 上运行持续集成(CI)流水线。你可以把 artifact push 事件直接发送给你的 Workflow,通过 wrangler 配置文件中的一个新 events 字段,触发其执行的一个实例,本质上就是一个 CI 作业。

然后,在安装了 @cloudflare/ci 的 Workflow 中,你可以直接:

  • 自动化构建:在安全、隔离的环境中编译 Artifacts 仓库里的代码
  • 运行 linter 和类型检查:强制执行代码风格、捕获类型错误,并标记任何潜在问题
  • 缓存依赖:只运行一次 install,并在 CI 作业的各个步骤之间缓存依赖
  • 执行单元测试:验证代码的每个部分都按预期工作
  • 自愈:集成 AI 审查智能体,捕获构建中失败的步骤并推送提交来修复
  • 条件部署:仅当构建步骤成功时,才自动部署代码

BLOG-3435 2.png

如今,每个人都在构建平台,无论是内部的 vibe coding 平台,还是通过代码定制来扩展面向客户的产品。平台目前在 Artifacts 上使用数百万个仓库,来存储自己的代码和客户的代码,并管理两者之间的版本控制。但每个团队对持续集成和部署流水线都有自己的需求。对平台而言,他们可能希望以不同于客户代码的方式,为自己的代码定义 CI 作业。

许多在这些平台上构建应用的终端客户并不想额外操心管理持续集成和持续部署(CI/CD)流水线。平台可以代表客户管理构建流程:只需编写一次 CI/CD 流水线,就能在客户构建的所有应用之间共享。平台的部分客户可能想定义自己的 CI;如果是这样,他们可以编写自己的 Workflow,仅针对自己的仓库运行自定义 CI 作业,这由 dynamic workflows 提供支持。妙处在于,你不必二选一:平台托管的 CI 和自定义 CI 可以在同一个命名空间中同时运行。

BLOG-3435 3.png

CI/CD 流水线就是一个 Workflow

在今天之前,我们已经具备了让平台在 Cloudflare 上搭建 CI/CD 流水线所需的所有部件。现在,我们带来更好的开发者体验,让这件事变得简单。

CI/CD 流水线通常用 GitHub Actions 来编排,是一系列按特定顺序运行的步骤,如果任何一步失败,就停止运行流水线并报告错误。本质上,CI/CD 流水线就是一个 Workflow。用 YAML 文件定义 CI/CD 时,由于种种限制,很容易变得复杂,这也常常导致人们对 YAML 感到厌倦。但 CI/CD 流水线中的每一步都可以简单地转换成一个 Workflow 的 step.do()。你可以用 Typescript 而不是 YAML 来定义 CI/CD 流水线,获得更高的自定义程度和可配置性。

我们在 CI SDK 中推出了新工具,让你可以在安全、隔离的环境中运行 CI 流水线的每一步(例如 build、lint 和 typecheck),这些环境通过 Workflows 和 Sandbox SDK 直接构建在 Cloudflare 的开发者平台上。此外,现在你可以直接在 push 时启动 CI 作业,而不必配置事件订阅、队列和队列消费者。

以前,你需要直接调用 Sandbox API,并自行管理 CI 流水线不同步骤之间的状态。现在 SDK 让你可以在各自独立的 Workflow 步骤中运行每条沙箱命令,并获得 Cloudflare Workflows 内置的重试和超时机制。

你还可以通过缓存步骤结果来加快 CI 流水线,例如安装步骤,这样后续所有操作就不必重新安装。依赖缓存降低了 CI/CD 流水线的延迟,因为每个 CI 步骤都不需要重新运行安装。

BLOG-3435 4.png

要定义 CI 作业,你只需要:

  1. 为所有依赖(CI 作业所需的外部软件包或工具)定义 install 步骤,例如打包器(如 esbuild)、linter(如 eslint)或测试运行器(如 vitest)。
  2. 为 CI 作业中的每个步骤指定命令(例如 bun run build、bun run test、bun run lint)。依赖缓存之后,各个 CI 步骤就可以并行执行,从而降低整个运行的延迟。
  3. 在 deploy 步骤中传入 wrangler deploy。CI 流水线通过后,你的 Worker 会自动部署。
const deps: CiRunnerResult = await ci.runner({
  name: 'install',
  command: 'bun install --frozen-lockfile',
  cache: { inputs: ['package.json', 'bun.lock'] },
});

await Promise.all([
  deps.runner({ name: 'lint', command: 'bun run lint' }),
  deps.runner({ name: 'test', command: 'bun run test' }),
  deps.runner({ name: 'typecheck', command: 'bun run typecheck' }),
  deps.runner({ name: 'build', command: 'bun run build' }),
]);

await deps.runner({
  name: 'deploy',
  command: 'bun wrangler deploy',
  cloudflareCredentials: {
    accountId: this.env.CLOUDFLARE_DEPLOY_ACCOUNT_ID,
  },
});

在 Workflow 中编写自己的 CI 流水线,你可以随心所欲地自定义。例如,你可以在 CI Workflow 中调用一个智能体,让 CI 作业具备自愈功能:如果构建中某一步出错,智能体可以自动修复,并推送一个提交等待你批准。

BLOG-3435 5.png

试试用 Project Think 实现的自愈 CI Workflow 示例:https://github.com/cloudflare/ci/blob/main/examples/self-healing

部署到 Cloudflare

编写你自己的 CI Workflow

要编写自己的 CI Workflow,请从 import { CIWorkflow } from@cloudflare/ci 开始。
首先是一个 install 步骤:

  • 下载你的依赖,包括 CI 步骤所需的任何外部工具或库(例如 vite、react)。
  • 指定你的锁文件,用来跟踪依赖是否发生变化。
  • 通过沙箱快照缓存你的依赖,使后续所有步骤都能访问。该快照会存储在你账户下的 R2 存储桶中。
const deps = await ci.runner({
  name: 'install',
  command: 'bun install --frozen-lockfile',
  cache: { inputs: ['package.json', 'bun.lock'] },
});

然后为构建和检查定义步骤,每个步骤都在各自安全、隔离的沙箱环境中执行。

BLOG-3435 6.png

默认情况下,Workflow 中的每个步骤都是独立启动的,也就是说除非另行指定,各步骤会并发执行。并行运行每个步骤可以降低 CI 运行的延迟。若要确保所有检查完成后 CI 流水线才继续(例如在部署步骤开始之前先完成 build、lint、test 和 typecheck),请用 Promise.all() 包裹:

await Promise.all([
   deps.runner({ name: 'lint', command: 'bun run lint' }),
   deps.runner({ name: 'test', command: 'bun run test' }),
   deps.runner({ name: 'typecheck', command: 'bun run typecheck' }),
   deps.runner({ name: 'build', command: 'bun run build' }),
]);

现在,要真正触发你的 CI Workflow,请在 Worker 的 wrangler 配置中添加一个 events 字段,与你的 Workflow 和 Artifact 绑定放在一起。events 字段是 triggers 字段中新增支持的字段。

你本来就可以通过事件订阅经由 Cloudflare Queues 订阅 Artifacts,并在每次出现 push 事件时启动构建流水线。但这需要设置事件订阅、Queue、消费者和队列处理程序。现在,你可以让 Workflow 成为该事件的目标,每当该事件触发,就会触发 Workflow 的一个实例。

将 CI Workflow 指定为 artifact push 触发器的目标,即可在每个 cf.artifacts.repo.pushed 事件上自动触发一个 Workflow 实例。每次 CI 运行都会呈现为一个 Workflow 实例,因此你可以直接在 Workflows 仪表盘中查看其逐步执行情况和可观测性数据。这是一个以 Artifacts 优先的集成;不久之后,types 将支持来自你 Cloudflare 账户中各处来源的事件,以便在整个产品套件中以编程方式消费。

如果你想在命名空间中的每个仓库上运行 CI Workflow,例如你是一个在所有客户仓库上运行 CI 的平台,请省略 repoName,只在 filter 中指定 namespace。

{
  "triggers": {
    "events": [
      {
        "type": "cf.artifacts.repo.pushed",
        // filter is optional. If you don't set repoName we will run the same workflow for every push on any repo in your Artifacts namespace
        "filter": {
          "namespace": "CI",
          "repoName": "my-repo"
        },
        "target": {
          "type": "workflow",
          "workflow_name": "ci-workflow"
        }
      }
    ]
  }
}

要完整配置你的 CI Workflow,请为驱动流水线的每一块基础设施添加绑定:artifacts、workflows、containers 和 durable_objects(以及 exports 配置)绑定(用于访问你的沙箱),如果你使用 cache,还需要一个 r2 绑定。R2 绑定是必需的,因为你的 install 步骤沙箱的快照存储在一个存储桶中。

自愈式 CI 运行

要让 CI 作业具备自愈能力,你需要两个部分:LLM 及其智能体 harness。在上面的示例中,我们加入了一个使用 Workers AI 的 Think 智能体,用来捕获流水线中的错误并代你执行修复。你的 CI 作业可以远程运行和重新运行,不需要开着笔记本盯着,也不必每隔几分钟回来查看。Cloudflare 会在云端处理,在容器中与 CI 步骤一起运行你的修复智能体。你不必再看护 CI 作业、手动修复、重新运行流水线,只需在智能体完成修复后合并提交即可。

要设置自愈你的 CI 流水线的智能体,请为你的 Think 智能体添加一个 Durable Object 绑定:

"durable_objects": {
   "bindings": [
     {
       "name": "HEALER",
       "class_name": "Healer",
     },
   ],
 },

通过扩展 HealingAgent 类来创建你的 Think 智能体 Healer,该类包含一个 heal 方法,供你在失败时调用。传入你想使用的任何模型:

export class Healer extends HealingAgent {
 getModel() {
   return '@cf/moonshotai/kimi-k2.7-code';
 }
}

然后,把你的步骤包裹在一个 try/catch 代码块中,一旦失败就触发修复智能体:

let deps: CiRunnerResult;
try {
  // Install once, then run independent checks from the shared and cached snapshot
  deps = await ci.runner({
    name: 'install',
    command: 'bun install --frozen-lockfile',
    cache: { inputs: ['package.json', 'bun.lock'] },
  });

  await Promise.all([
    deps.runner({ name: 'lint', command: 'bun run lint' }),
    deps.runner({ name: 'test', command: 'bun run test' }),
    deps.runner({ name: 'typecheck', command: 'bun run typecheck' }),
    deps.runner({ name: 'build', command: 'bun run build' }),
  ]);
} catch (failure) {
  // This catches both failed Sandbox commands and ordinary Workflow errors.
  // Only failures reported by a runner should be healed; rethrow the rest.
  if (!isCiRunnerFailure(failure)) {
    throw failure;
  }

  // Pass the error along to the agent so that it can fix it
  const healed = await step.do(
    'heal',
    { retries: { limit: 0, delay: 0 }, timeout: '5 hours' },
    async () => {
      const healer = await getAgentByName(this.env.HEALER, event.instanceId);
      using result = await healer.heal({
        failure: enrichFailure({ failure, event, baseBranch }),
        prompt: 'Fix every observed failure without weakening validation.',
      });
      // Report the Fix Branch, its commit, and how many steps it took.
      const { branch, commit, steps } = result;
      return { branch, commit, steps };
    }
  );

  // The source run stays failed; its verified fix lives on another branch
  throw new CiRunFailedWithFix(failure, healed);
}

await deps.runner({
  name: 'deploy',
  command: 'bun wrangler deploy',
});

这个示例演示的是自愈式 CI 流水线,但实际上,Bring Your Own Workflow 模式允许你随心所欲地定制 CI 作业。这里可以添加安全规则、过滤器或条件性的 CI 步骤。借助 BYO-W 模式,平台可以针对不同团队、客户或应用,根据各自的具体用例来配置 CI/CD 流水线。

使用 Workflow 的好处

在 Cloudflare Workflow 上运行 CI 流水线,你会自动获得:

  1. 弹性重试(持久化执行):如果 CI 作业中的任何步骤失败,它会在保留状态的情况下自动重试,不会丢失任何进度。每个步骤都支持自定义的重试和超时行为,因此你可以为每个步骤定义不同的失败逻辑。此外,你还可以从特定步骤重新开始,例如只有 lint 失败时,不必重新运行整个 CI 流水线。
  2. Workflows 可观测性:在 Workflows 仪表盘中逐步检查你的 CI 作业,每个实例都会展示各步骤及其输入、输出以及墙钟时间和 CPU 时间。你可以通过仪表盘中的 Workflows 图示将 CI 作业可视化,轻松看出哪些步骤并发运行、哪些顺序运行。你还可以通过 Workers Observability 和 GraphQL 查看 Workflows 日志,更深入地了解 CI 作业的各次运行。
  3. 代码的力量:在 Workflow 中运行 CI,你可以为任何事情编写一个步骤。例如,你可能想把 AI 代码审查器作为 CI/CD 流水线的一部分来运行。你可以通过 Workflows 的 step.do() 调用你的代码审查智能体,或处理任何能写进代码的自定义逻辑。其他例子包括把构建产物写入 R2,以及在 CI 失败、完成或合并到 main 时发送邮件。

download.png

下一步

CI/CD 流水线就是一个 Workflow。借助 CI SDK,你可以用简单的 Typescript 而不是缺乏灵活性的 YAML,在你的代码以及客户的代码上定义 CI。基于 Cloudflare Workflows 的原语,你可以定义任何想要的逻辑,无论是像我们的 Think 示例那样的修复智能体,还是把构建产物写入 R2。在 Workflows 上运行 CI,有助于弥合存储(通过 Artifacts)、构建和部署之间的鸿沟。作为平台,你可以借此轻松地管理自己代码以及代表客户管理的代码的每一个步骤。

申请加入 Artifacts 私有测试版,并从我们的 Workflows CI 指南开始上手。如果你有任何功能请求,或发现了任何缺陷,请加入 Discord 上的 Cloudflare Developers 社区,直接向 Cloudflare 团队反馈。

接下来会推出:

  1. 对 Workers & Workers for Platforms 的直接集成:build.preview() 和 build.deploy() 原语,可在推送到 main 时自动部署,并在推送到非默认分支时创建预览
  2. 渐进式部署:通过 Workflows 管理按百分比推进的发布,以自定义部署推进和回滚逻辑
  3. Monorepo:使用一条 CI 流水线简化多 Worker 部署的管理
  4. 触发器:从不同来源发送 push 事件,在任何版本控制系统(而不仅是 Artifacts)的仓库上运行 CI 作业