← Artifacts / artifacts / guides
Сборка и развёртывание репозиториев Artifacts
События Artifacts могут собирать и развёртывать проекты, хранящиеся в репозиториях Artifacts. Когда пользователь или агент отправляет коммит, это событие запускает Экземпляр Workflow.
В рамках Workflow вы определяете конвейер непрерывной интеграции (CI) с помощью @cloudflare/ci SDK для кэширования зависимостей, запуска проверок и сборки проекта. Последний шаг вашего конвейера CI может развернуть результат в Worker или Workers for Platforms User Worker.
Это полезно, когда нужно:
- Автоматически собирайте и развёртывайте код приложений, хранящийся в Artifacts.
- Выполняйте линтинг, проверку типов, тесты и другие проверки при каждом push.
- Используйте повторно зависимости, если файл блокировки (например,
pnpm-lock.yaml) не изменилось. - Останавливайте развёртывание, если проверка или сборка завершается ошибкой.
- Ограничьте доступ API-токена этапом развёртывания.
- Разверните результат в Worker или Workers for Platforms User Worker.
Как это работает
- Отправляйте изменения репозитория :
git pushв репозиторий Artifacts генерируетartifacts.repo.pushedсобытие, которое указывает репозиторий, ветку и commit, куда был выполнен push. - Запустите рабочий процесс CI : событие запускает Workflow, который выполняет checkout коммита, устанавливает и кеширует зависимости, а затем параллельно выполняет этапы CI: сборку, lint, проверку типов и форматирование. Если какой-либо этап завершается с ошибкой, Workflow останавливается до развёртывания.
- Разверните Worker : Workflow разворачивает собранный Worker либо напрямую в вашем аккаунте, либо как User Worker, если используется Workers for Platforms
Запустите рабочий процесс CI
Используйте @cloudflare/ci SDK для описания этапов CI. SDK предоставляет два инструмента для создания конвейера:
- Раннеры : каждое
runner()вызов создаёт изолированный sandbox и выполняет shell-команду. Вы используете те же команды, что уже запускаете локально или в другой системе CI. Каждый раннер сохраняет собственные логи, статус и файлы вывода. - Кеш
cacheопция раннера кэширует установленные зависимости, чтобы последующие запуски не устанавливали их заново. Передайте файлы, определяющие зависимости, напримерpnpm-lock.yaml, доcache.inputs. Если эти файлы не изменились, SDK восстанавливает закешированный результат вместо повторного выполнения команды.
Кэшированный раннер запускается за снимок своего sandbox, который затем повторно используют другие раннеры. Несколько раннеров могут ответвляться от одного и того же закэшированного результата: например, раннеры для lint, type-check и test могут использовать одну и ту же закэшированную установку.
Раннер, завершившийся ошибкой, повторяет попытку согласно своей конфигурация шага, где можно задать количество попыток повтора, график задержек и тайм-ауты. Раннеры, зависящие от предыдущего шага, не запускаются, пока его повтор не завершится успешно. Если достигнут заданный лимит попыток, Workflow завершается с Errored состояние.
Ниже приведён пример того, как настроить ваш Workflow для использования раннеров и кеша, чтобы устанавливать зависимости, запускать проверки, собирать проект и разворачивать Worker:
import { CIWorkflow } from "./src/pipeline";
export class CI extends CIWorkflow {
async pipeline(_event, _step, ci) {
// Install once, then run independent checks from the shared snapshot.
const 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" }),
]);
await deps.runner({
name: "deploy",
command: "bun wrangler deploy",
cloudflareCredentials: {
accountId: this.env.CLOUDFLARE_DEPLOY_ACCOUNT_ID,
},
});
}
}import { CIWorkflow } from "./src/pipeline";
import type {
CiContext,
CiParams,
CiRunnerResult,
CloudflareArtifacts,
} from "./src/pipeline";
import type { WorkflowEvent, WorkflowStep } from "cloudflare:workers";
export class CI extends CIWorkflow {
protected async pipeline(
_event: WorkflowEvent<CiParams<CloudflareArtifacts>>,
_step: WorkflowStep,
ci: CiContext,
): Promise<void> {
// Install once, then run independent checks from the shared snapshot.
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,
},
});
}
}Запускайте сборку при изменении кода
Когда пользователь или агент отправляет коммит в репозиторий Artifacts, Artifacts создаёт событие, которое указывает изменённые репозиторий, ветку и коммит. Это событие можно использовать для запуска экземпляра Workflow, который выполняет CI-конвейер: он автоматически получает нужный коммит и клонирует репозиторий, а затем устанавливает зависимости, запускает проверки, собирает проект и (или) развёртывает Worker в соответствии с вашим кодом.
В этом руководстве эти шаги CI определены в классе Workflow с именем CIWorkflow. Чтобы запускать этот Workflow автоматически после каждого push, добавьте cf.artifacts.repo.pushed триггер в конфигурацию Wrangler. Также добавьте:
- Привязка R2: бакет, в котором будет храниться снимок ваших кешированных зависимостей
- Привязка Container (и Durable Object): создайте привязку к своему контейнеру, чтобы обращаться к песочницам во время каждого
runner()шаг - Привязка Workflows
- Привязка Artifacts
- Observability (опционально): проверяйте задания CI как экземпляр Workflow с помощью Наблюдаемость Workers
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "<worker-name>",
"main": "src/index.ts",
"compatibility_date": "2026-06-16",
"compatibility_flags": ["nodejs_compat"],
"artifacts": [
{
"binding": "ARTIFACTS",
"namespace": "<artifacts-namespace>"
}
],
"containers": [
{
"class_name": "CiSandbox",
"image": "./Dockerfile",
"max_instances": 10,
"instance_type": "standard-4"
}
],
"durable_objects": {
"bindings": [
{
"name": "SANDBOX",
"class_name": "CiSandbox"
}
]
},
"workflows": [
{
"name": "<workflow-name>",
"binding": "CI_WORKFLOW",
"class_name": "CI"
}
],
"exports": {
"CiSandbox": {
"type": "durable-object",
"storage": "sqlite"
}
},
"r2_buckets": [
{
"binding": "BACKUP_BUCKET",
"bucket_name": "<backup-bucket-name>"
}
],
"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": {
"scriptName": "<worker-name>",
"workflowName": "<workflow-name>"
}
}
]
},
"observability": {
"enabled": true,
"logs": {
"enabled": true
}
}
}"$schema" = "node_modules/wrangler/config-schema.json"
name = "<worker-name>"
main = "src/index.ts"
compatibility_date = "2026-06-16"
compatibility_flags = [ "nodejs_compat" ]
[[artifacts]]
binding = "ARTIFACTS"
namespace = "<artifacts-namespace>"
[[containers]]
class_name = "CiSandbox"
image = "./Dockerfile"
max_instances = 10
instance_type = "standard-4"
[[durable_objects.bindings]]
name = "SANDBOX"
class_name = "CiSandbox"
[[workflows]]
name = "<workflow-name>"
binding = "CI_WORKFLOW"
class_name = "CI"
[exports.CiSandbox]
type = "durable-object"
storage = "sqlite"
[[r2_buckets]]
binding = "BACKUP_BUCKET"
bucket_name = "<backup-bucket-name>"
[[triggers.events]]
type = "cf.artifacts.repo.pushed"
[triggers.events.filter]
namespace = "CI"
repoName = "my-repo"
[triggers.events.target]
scriptName = "<worker-name>"
workflowName = "<workflow-name>"
[observability]
enabled = true
[observability.logs]
enabled = trueПросмотр статуса сборки
[observability] параметр в конфигурации Wrangler фиксирует статус и логи каждого запуска конвейера. Чтобы определить, на каком этапе произошёл сбой, проверьте экземпляр на панели управления Workflows:
Каждый раннер отображает собственные входные данные, вывод и статус, поэтому вы можете определить, какая команда завершилась ошибкой. Если раннер завершается ошибкой, Workflow сохраняет его вывод и не запускает этапы, которым нужны его файлы.
Разверните приложение
Чтобы задеплоить Worker, передайте wrangler deploy в итоговый runner() шаг, то есть workspace.runner({ name: "deploy", command: "wrangler deploy" }).
Чтобы задеплоить User Worker, передайте wrangler deploy --dispatch_namespace <DISPATCH_NAMESPACE> в итоговый runner() шаг.
Запускайте один рабочий процесс для каждого репозитория в пространстве имён
filter в вашем триггере необязателен. Когда вы задаёте repoName, Workflow запускается только при push в этот конкретный репозиторий. Если не указать repoName, Cloudflare запускает один и тот же Workflow при каждом push в любой репозиторий вашего пространства имён Artifacts.
Это полезно для платформ, которые создают и поддерживают единый CI Workflow и хотят применять его одинаково ко всем репозиториям клиентов в пространстве имен. Вместо отдельного триггера для каждого репозитория один общий Workflow собирает, проверяет и деплоит каждый репозиторий при push.
Чтобы запускать один и тот же Workflow для каждого репозитория в пространстве имен, поместите repoName из триггера filter и оставьте только namespace:
{
"triggers": {
"events": [
{
"type": "cf.artifacts.repo.pushed",
"filter": {
"namespace": "CI"
},
"target": {
"scriptName": "my-ci-worker",
"workflowName": "ci-workflow"
}
}
]
}
}[[triggers.events]]
type = "cf.artifacts.repo.pushed"
[triggers.events.filter]
namespace = "CI"
[triggers.events.target]
scriptName = "my-ci-worker"
workflowName = "ci-workflow"Каждый push по-прежнему запускает отдельный экземпляр Workflow для репозитория, ветки и коммита, которые изменились, поэтому вы можете разворачивать отдельный Worker для каждого репозитория на основе одного общего определения Workflow.