CI/CD 实战
用 setup-deno、deno ci 与分层门禁构建可复现的 Deno CI,并把产物发布到静态托管或 Deno Deploy
前提:仓库已提交 deno.json 与 deno.lock,本地门禁已通过。本页只讲流水线编排;门禁本身与安全基线见生产工程基线。
安装与固定 Deno
GitHub Actions 使用官方 action,并固定 major 版本:
- uses: denoland/setup-deno@v2
with:
deno-version: v2.x
deno-version接受v2.x、v2.1.x、精确版本或lts;追求严格可复现时固定到精确版本,并把升级作为独立变更评审。- 也可用
deno-version-file从.tool-versions等文件读取,保证 CI 与本地一致。
缓存依赖
setup-deno 内置缓存,无需手写 actions/cache:
- uses: denoland/setup-deno@v2
with:
deno-version: v2.x
cache: true
cache: true 缓存 Deno 下载的依赖(即 DENO_DIR 内容),缓存键由 job id、runner OS/arch 和 deno.lock 哈希组成;需要自定义哈希时用 cache-hash(设置它即隐含开启缓存)。若 workflow 自行设置了 DENO_DIR 环境变量,保证 action 与后续步骤使用同一目录。
安装依赖:deno ci
deno ci
deno ci(Deno 2.8+)是 CI 与 Dockerfile 的可复现安装命令:deno.lock 缺失时报错,删除已有 node_modules,并以 frozen 语义安装——lockfile 必须与配置文件精确匹配,任何漂移都会失败而不是静默更新。构建生产产物时加 --prod 跳过 devDependencies;要连 @types/* 一起排除需另加 --skip-types——它按包名启发式判断,可能误跳过附带运行时代码的包,用前核对产物是否仍完整。
门禁顺序
按"廉价且快失败在前"排序:
deno ci
deno fmt --check
deno lint
deno check "**/*.ts" "**/*.tsx"
deno test
格式与 lint 秒级完成,先拦住机械性问题;类型检查再拦住接口错误;测试最贵,放最后。不要把门禁合并成一条命令,分开才能在 CI 日志里一眼定位失败层级。glob 要加引号交给 Deno 展开(裸 **/*.ts 由 shell 展开,各 runner 行为不一,而且漏掉 .tsx);Fresh 等有自带 check task 的项目直接跑 deno task check。
跨 OS/arch 矩阵
库与 CLI 至少跑三个系统:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
Windows 注意 CRLF:在 checkout 前设置 git config --system core.autocrlf false,避免 deno fmt --check 因换行符误报。可用 continue-on-error 加一个 canary Deno 版本任务,提前发现上游变更,但不阻塞合并。覆盖率报告等只需一次的步骤用 if: matrix.os == 'ubuntu-latest' 限定。
构建与发布产物
- 静态站点:
deno task build生成产物目录,用actions/upload-artifact传递或直接交给部署步骤。 - 单文件二进制:
deno compile --target <target>交叉编译各平台产物,随 release 上传。编译参数以当前deno help compile为准。 - 发布 JSR 包:不要在每个 push 上发布。按 tag 触发,用 OIDC 发布以获得 provenance,完整配置见发布 JSR 包。
部署到 Deno Deploy
两条路径,按团队习惯选一条:
- 内置 GitHub 集成(默认路径):在 Deno Deploy 控制台把 app 关联到 GitHub 仓库,推送即触发构建,不需要自己维护部署 YAML。
- 外部 CI 部署:需要自定义流水线(例如先跑完整矩阵再发布)时,用
deno deployCLI:
deno deploy --org <org> --app <app> --prod
CLI 在 CI 中的认证方式是组织 token:创建 organization token,存入 GitHub 仓库 secret,通过 DENO_DEPLOY_TOKEN 环境变量传入。注意 Deno Deploy 文档中的 OIDC 页面讲的是运行中的应用向第三方服务(AWS、Vault 等)认证,不是 CLI 部署的认证方式——不要把两者混淆。Deploy Classic 已被官方宣布于 2026-07-20 停用,不要在新项目中使用 deployctl。
完整示例
name: ci
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
# Windows runner 上先关掉 CRLF 转换,否则 fmt --check 会误报
steps:
- run: |
git config --system core.autocrlf false
git config --system core.eol lf
- uses: actions/checkout@v7
- uses: denoland/setup-deno@v2
with:
deno-version: v2.x
cache: true
- run: deno ci
- run: deno fmt --check
- run: deno lint
- run: deno check "**/*.ts" "**/*.tsx"
- run: deno test
deploy:
needs: test
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v7
- uses: denoland/setup-deno@v2
with:
deno-version: v2.x
- run: deno ci --prod
- run: deno task build # 需要构建步骤的项目
- run: deno deploy --org my-org --app my-app --prod
env:
DENO_DEPLOY_TOKEN: ${{ secrets.DENO_DEPLOY_TOKEN }}
要点:environment: production 配合 GitHub 环境保护规则做人工审批;token 只授予目标组织;deploy job 与测试矩阵使用同一 Deno major 版本。
官方参考:Continuous integration、setup-deno、Deno 2.8 发布说明(deno ci)、deno deploy CLI 参考、Deno Deploy changelog。