mcpField
M
motoko-github-ci-workflow

motoko-github-ci-workflow

github.com/research-ag云与 DevOps035 次安装9 周前更新
代码仓库

关于 motoko-github-ci-workflow

motoko-github-ci-workflow 是为 Motoko 项目新增或更新 GitHub Actions CI 的技能,适用于维护 Motoko 包、Canister 和示例的开发者。它会先检查项目结构与现有工具,再按需配置测试、基准测试、格式检查和构建任务。

主要功能

  1. 01检查 Motoko 项目类型与现有 CI
  2. 02按需配置测试和基准测试
  3. 03加入 Prettier 格式检查
  4. 04构建 Canister 与示例
  5. 05为 PocketIC 和 wasm-opt 配置工具链

适用场景

  1. 01为 Motoko 包添加持续集成
  2. 02补齐现有 CI 中缺少的测试
  3. 03配置基准测试运行环境
  4. 04在 CI 中构建 Canister 或示例

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/research-ag/motoko-skills --skill motoko-github-ci-workflow

安装后在 Claude Code 中输入/motoko-github-ci-workflow确认已加载。

详细介绍

Motoko GitHub CI 工作流

这是什么

此技能提供了一份全面的操作指南,介绍如何为 Motoko 项目添加或更新 GitHub Actions CI 工作流。内容涵盖自动化测试、基准测试、代码格式化,以及使用 mops、moc、prettier、icp-cli 和 dfx 进行构建(canister 或示例)。它与 mops-package-maintenance 技能相得益彰。

如需了解 GitHub Actions 的一般信息,请参阅 GitHub Actions 文档。如需查看 Motoko 专属示例,可以浏览 research-ag 组织中的公开代码仓库。

先决条件

  • mops CLI(本地:npm i -g ic-mops,CI:caffeinelabs/setup-mops@v1)
  • node(建议使用最新 LTS 版本,Prettier 至少需要 v22)
  • 用于运行 mops bench 的 pocket-ic。从 mops CLI v3.0.0 起,已不再支持 dfx-replica——PocketIC 是 mops bench(以及副本测试和 --check-deploy)唯一可用的运行时,并且必须通过 mops.toml 中的 [toolchain] pocket-ic = "<version>" 显式固定版本(例如 mops toolchain use pocket-ic 15.0.0)。如果未固定版本,mops bench 会直接报错。CI 会通过 mops toolchain bin pocket-ic 安装固定版本的二进制文件(见步骤 1)。
  • 用于反映优化后(接近生产环境)的 Wasm 的基准测试所需的 wasm-opt。只有当 mops.toml 包含 [optimize] 部分时,mops bench/mops build 才会运行 Binaryen 的 wasm-opt——并且该部分要求像 pocket-ic 一样,在 [toolchain] wasm-opt = "<version>" 中显式固定版本(见步骤 1)。

工作原理

  1. 分析代码库:
    • 确定它是 Motoko 包(mops.toml 中包含 [package])还是 canister 项目(mops.toml 中包含 [canister],或存在 dfx.json)。
    • 检查测试:查找 test/ 目录和 *.test.mo 文件。如果都没有找到,则不要加入 mops test 步骤。
    • 检查基准测试:查找 bench/ 目录和 *.bench.mo 文件。如果都没有找到,则不要加入 mops bench 步骤。
  2. 分析现有 CI:
    • 如果 .github/workflows/ 中已有 CI 文件,分析它们使用了哪些工具(dfx、icp-cli 或都没有)。
    • 如果代码库中有测试或基准测试,但 CI 中未包含它们,则将其加入。
  3. 选择 Canister 构建工具:
    • 如果项目是库包(没有 canister,也没有需要 canister 构建工具的示例),则完全跳过 dfx 或 icp-cli 的安装。请注意,测试和基准测试仍需要 moc(Motoko 编译器),通常由 mops 管理。
    • 对于包含 canister 或示例的新项目,优先使用较新且更轻量的 icp-cli。
    • 对于现有项目,沿用现有工具集(dfx 或 icp-cli)。
    • 重要:不要同时安装 dfx 和 icp-cli。
  4. 检查 mops.toml:读取现有的 [toolchain] 部分。与 moc 不同,当包包含基准测试(或副本测试 / --check-deploy)时,pocket-ic 并非可选项——mops bench 要求固定其版本。如果缺少 [toolchain] pocket-ic,且包包含基准测试,请提醒用户并添加版本固定项(mops toolchain use pocket-ic <version>,例如 15.0.0),不要等到 CI 运行失败。如果检查发现 [optimize] 缺失,且包包含基准测试,则添加该部分(并固定 [toolchain] wasm-opt),以确保基准测试数据反映优化后的 Wasm;如果已运行 mops-package-maintenance 技能,通常已完成此操作。其他 [toolchain] 条目和 files 字段不要修改(参见步骤 1)。
  5. 创建或更新工作流文件:确定 .github/workflows/ 中现有的工作流文件(例如 pull_request_build.yml、test.yml、ci.yml)。如果没有,则创建 .github/workflows/ci.yml。确保使用并行任务以提高效率。
  6. 配置并行任务:
    • test 任务:负责安装依赖、运行 mops test 和 mops bench。
    • fmt 任务:负责检查 prettier 格式。
  7. 添加构建步骤:如果存在示例或 canister,则添加步骤,使用所选的 canister 构建工具构建它们。

实现

第 1 步 — 检查 mops.toml,必要时固定 pocket-ic/wasm-opt 版本

添加 CI 之前,先阅读 mops.toml。保持 [toolchain] moc 和其他条目不变。

基准测试必须使用 pocket-ic(mops CLI v3.0.0+):mops bench 已完全移除对 dfx-replica 的支持,PocketIC 现在是唯一的运行时,并且必须在 [toolchain] 中固定版本,否则 mops bench 会立即失败,并报错指出修复命令(mops toolchain use pocket-ic <version>)。mops test 仍然不需要 pocket-ic(它通过 Motoko 解释器或 WASI 运行);只有当软件包包含基准测试、Replica 测试或使用 --check-deploy 时,才需要固定该版本。

根据当前 [toolchain] 内容,确定要使用的 CI 策略:

  • 软件包包含基准测试,且 [toolchain] 中已固定 pocket-ic:在 CI 中通过 mops toolchain bin pocket-ic 安装,并运行 mops bench。确切代码片段请参阅第 2 步模板和陷阱 #2。
  • 软件包包含基准测试,但 [toolchain] 中没有 pocket-ic:告知用户,如果没有固定版本,mops bench 将在 CI 中失败,并添加固定版本(mops toolchain use pocket-ic <version> — mops 自己的错误消息会指出一个具体版本,例如 15.0.0)。与 files 字段不同,这项配置不能置之不理;未固定版本的软件包根本无法运行 mops bench。
  • 没有基准测试:无需处理 — mops test 不需要 pocket-ic,也不需要基准测试运行时。

**[optimize] + wasm-opt — 基准测试应反映优化后的 Wasm。**只有当 mops.toml 中存在 [optimize] 节时,mops bench 才会运行 Binaryen 的 wasm-opt(即使该节为空,默认也会使用 level = "O3");如果没有该节,基准测试会在不提示的情况下测量未优化的代码。与 pocket-ic 一样,一旦配置了 [optimize],就必须固定 [toolchain] wasm-opt 版本,否则构建会在编译前失败。

  • 软件包包含基准测试,且已配置 [optimize]:在运行 mops bench 前,通过 mops toolchain bin wasm-opt 在 CI 中安装 wasm-opt,并同时安装 pocket-ic。
  • 软件包包含基准测试,但缺少 [optimize]:按照上述固定 pocket-ic 版本的方式添加该节(并固定 [toolchain] wasm-opt 版本,例如 mops toolchain use wasm-opt <version>)— 通常由 mops-package-maintenance 技能在维护过程中处理;如果尚未处理,也请在此添加,以免 CI 发布测量未优化代码的基准测试结果。
  • 没有基准测试:无需处理。

此外,检查 mops.toml 的 [package] 下是否包含 files 字段。如果有,请勿修改。试图自行调整 files 字段可能导致意外副作用。请改为向用户报告其当前配置,并在它似乎缺少重要目录(如 examples/)或包含不受支持的扩展名(mops publish 仅允许 .mo、.did、.md 和 .toml)时提醒用户。

第 2 步 — 创建或更新 GitHub CI 工作流

检查 .github/workflows/ 中是否已有工作流文件。如果有,请更新;否则,创建 .github/workflows/ci.yml。使用最新版本的 Actions(例如 actions/checkout@v6、actions/setup-node@v6),并行执行任务。

注意:使用最新的主要版本 Actions,可确保获得最新功能和安全更新。

name: CI

on:
  push:
    branches: [main, master]
  pull_request:
    types: [opened, synchronize, reopened, ready_for_review]

jobs:
  test:
    name: Tests and Benchmarks
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: latest

      - name: Install mops
        uses: caffeinelabs/setup-mops@v1

      - name: Make sure moc is installed
        run: mops toolchain bin moc

      - name: Show versions
        run: |
          mops --version
          $(mops toolchain bin moc) --version

      - name: Install dependencies
        run: mops install

      # Bench runtime: PocketIC is the only runtime `mops bench` supports
      # (dfx-replica support was removed in mops CLI v3.0.0). `[toolchain]
      # pocket-ic` must already be pinned in mops.toml (see Step 1) —
      # `mops toolchain bin pocket-ic` downloads that pinned version.
      # `mops bench` starts (and stops) PocketIC itself, so there is no
      # separate "start" step. Omit both steps if the package has no
      # benchmarks.
      - name: Make sure pocket-ic is installed
        run: mops toolchain bin pocket-ic

      # Only if mops.toml has an [optimize] section (see Step 1) — it
      # requires a [toolchain] wasm-opt pin, downloaded the same way.
      # Omit this step if the package has no [optimize] section.
      - name: Make sure wasm-opt is installed
        run: mops toolchain bin wasm-opt

      - name: Run tests
        run: mops test  # Omit this step if the package has no tests. Note: `mops test` does not use pocket-ic.

      - name: Run benchmarks
        run: mops bench  # Omit this step if the package has no benchmarks.

  fmt:
    name: Formatting Check
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: latest

      - name: Prettier Check
        run: |
          npm install prettier prettier-plugin-motoko --no-save
          npx -y prettier --plugin prettier-plugin-motoko --check '**/*.{mo,json,md}'
第 3 步 — 处理示例和 Canister(可选)
如果仓库有作为 Canister 的示例:

在 test 任务中添加一个步骤(或新建一个任务)来构建示例。使用项目中已有的工具;对于新项目,则使用 icp-cli。如果没有需要构建的示例/Canister,请省略本节。

      - name: Build examples
        run: |
          # Detect and build examples/example
          EXAMPLES_DIR=""
          if [ -d "examples" ]; then
            EXAMPLES_DIR="examples"
          elif [ -d "example" ]; then
            EXAMPLES_DIR="example"
          fi

          if [ -n "$EXAMPLES_DIR" ]; then
            cd "$EXAMPLES_DIR"
            if [ -f "mops.toml" ]; then
              mops install
            fi
            
            # Use icp if it exists, otherwise fallback to dfx if dfx.json is present
            if [ -f "icp.yaml" ] && command -v icp >/dev/null; then
              icp build --all
            elif [ -f "dfx.json" ]; then
              # Only run dfx build if dfx is already installed in this job
              if command -v dfx >/dev/null; then
                dfx build
              fi
            fi
            cd ..
          fi
如果仓库是一个 Canister(而非软件包):

如果项目是一个 Canister,你应构建这些 Canister,并可选择比较 .did 文件。

安装工具(任选其一):

      # Option A: For new projects or those already using icp
      - name: Install icp-cli
        run: npm i -g icp-cli

      # Option B: For existing projects already using dfx
      - name: Install dfx
        uses: dfinity/setup-dfx@main

构建并比较 DID: 比较 .did 文件通常需要 didc 来检查最新接口。

      - name: Build canisters
        run: |
          if [ -f "icp.yaml" ] && command -v icp >/dev/null; then
            icp build
          else
            dfx build
          fi

      - name: Get didc
        run: |
          mkdir -p /home/runner/bin
          release=$(curl --silent "https://api.github.com/repos/dfinity/candid/releases/latest" | awk -F\" '/tag_name/ { print $4 }')
          curl -fsSL https://github.com/dfinity/candid/releases/download/$release/didc-linux64 > /home/runner/bin/didc
          chmod +x /home/runner/bin/didc
          echo "/home/runner/bin" >> $GITHUB_PATH

      - name: Check Candid interface
        run: |
          # Compare generated .did with tracked .did
          # e.g., didc check -s did/my_canister.did .dfx/local/canisters/my_canister/my_canister.did
          didc check -s did/backend.did .dfx/local/canisters/backend/backend.did
步骤 4 — 运行端到端测试

如果仓库包含端到端测试(例如位于 test/e2e 或类似目录中),请添加一个运行这些测试的步骤。这通常需要 dfx 和正在运行的本地副本或 pocket-ic。

      - name: Run E2E tests
        run: |
          # Your E2E test command here
          # e.g., npm run test:e2e

常见问题

  1. Node 版本过旧。 Prettier 和某些 Motoko 工具需要较新的 Node.js 版本。在 CI 中始终使用 latest 或至少 v22。

  2. 基准测试需要固定 pocket-ic 工具链版本——没有 dfx 后备方案。 mops CLI v3.0.0 完全移除了对 dfx-replica 的支持(mops test/mops bench 上的 --replica 标志也已移除——自 2.14 起该标志就已弃用)。PocketIC 现在是唯一的运行时。如果包中有基准测试,请确保在 mops.toml 中固定了 [toolchain] pocket-ic(如果缺少,请使用 mops toolchain use pocket-ic <version> 添加——未固定版本的项目会报错,并指出具体的修复方法),然后安装固定版本的二进制文件并运行 bench(仅在运行 mops bench 的任务中)。无需单独的“启动”步骤——mops bench 会自行启动(并停止)PocketIC:

          - name: Make sure pocket-ic is installed
            run: mops toolchain bin pocket-ic
          - run: mops bench
    

    注意:mops test 不使用 pocket-ic(它通过 Motoko 解释器或 WASI 运行),因此只有在运行 mops bench / 副本测试 / --check-deploy 时才需要固定版本。

    移除所有遗留的 dfx 基准测试运行时步骤。 如果你正在更新一个仍会安装 dfx(dfinity/setup-dfx@main)或仅为支持 mops bench 而运行 dfx start --background --clean 的现有工作流,请删除这些步骤——它们对 mops bench 已不起作用,也不能替代固定 pocket-ic 版本:

          # 如果这些步骤仅用于 `mops bench`,且存在,请将其移除——mops CLI v3.0.0
          # 已移除对 dfx-replica 的支持:
          - name: Install dfx
            uses: dfinity/setup-dfx@main
          - name: Start dfx
            run: dfx start --background --clean
    

    (对于其他任务,仍然可以安装 dfx,例如构建 canister/示例或运行 E2E 测试,参见步骤 3/4。此处的陷阱仅针对 mops bench 运行时。)

  3. 未固定 pocket-ic 版本。 如果 mops bench(或 mops toolchain bin pocket-ic)因工具链未固定而立即失败,说明 mops.toml 中缺少 [toolchain] pocket-ic——请使用 mops toolchain use pocket-ic <version> 固定版本(错误消息会给出具体版本),不要尝试用 dfx 绕过问题。

  4. 未配置 [optimize] 就运行基准测试。 只有当 mops.toml 中包含 [optimize] 部分时,mops bench 才会运行 wasm-opt——如果省略该部分,CI 会照常报告未优化 Wasm 的数据,而这些数据并不能反映实际发布到生产环境的版本。如果包中有基准测试但缺少 [optimize],请添加该部分(并固定 [toolchain] wasm-opt 版本),不要把“CI 通过”当作“CI 测量结果准确”——参见步骤 1。

  5. 未显示版本。 务必添加显示 mops 和 moc 版本的步骤。这有助于调试 CI 问题。

  6. 未使用并行作业。 在同一作业中运行格式检查和测试会更慢。请使用单独的作业,让 GitHub 并行运行它们。

  7. 在没有测试时包含 mops test。 务必检查包中是否有包含 *.test.mo 文件的 test/ 目录。如果没有,请省略 mops test 步骤,以避免 CI 失败。

  8. 在没有基准测试时包含 mops bench。 务必检查包中是否有包含 *.bench.mo 文件的 bench/ 目录。如果没有,请省略 mops bench 步骤。

  9. 安装旧版 mops。 避免使用 npm i -g ic-mops 或 ZenVoich/setup-mops@v1。请改用 caffeinelabs/setup-mops@v1。

  10. 同时安装多种工具。 不要同时安装 dfx 和 icp-cli。只选用其中一种。

  11. 跳过现有测试。 如果要更新现有 CI,请确保它运行仓库中的所有测试和基准测试。

  12. 安装不必要的工具。 对于只运行 mops test 且没有基准测试的库包,不要安装 dfx 或 icp-cli。如果包中有基准测试,则必须使用 pocket-ic(它是唯一的 mops bench 运行时)——仅在基准测试作业中通过 mops toolchain bin pocket-ic 安装它(如果设置了 [optimize],还要安装 wasm-opt)。不要仅为了运行 mops bench 而安装 dfx 或 icp-cli。

验证是否正常运行

  1. 检查 GitHub Actions 选项卡。 确保 test 和 fmt 两个作业都存在且正在运行。
  2. 检查日志。 确认 mops install 正确拉取依赖项,且 mops bench 使用 [toolchain] pocket-ic 中固定的版本对 PocketIC 运行(从 mops CLI v3.0.0 起,--replica 标志已不存在)。如果 mops.toml 中有 [optimize] 部分,还要确认运行了 wasm-opt 步骤——其输出应出现在基准测试结果之前。
  3. 检查格式检查。 故意将文件格式弄乱并提交 PR,确保 fmt 作业按预期失败。

评论

支持 Markdown