Ameba集成技能Skill ameba-integration

这个技能用于集成 Ameba 工具到开发工作流中,实现自动化 Crystal 代码质量检查。它支持 CI/CD 管道集成、预提交钩子、GitHub Actions 和代码审查过程,帮助团队提高代码质量和开发效率。关键词:Ameba, Crystal, 代码质量, CI/CD, 自动化检查, 开发工作流, 代码审查, 预提交钩子, GitHub Actions, 静态分析。

DevOps 0 次安装 0 次浏览 更新于 3/25/2026

名称: ameba-integration 用户可调用: false 描述: 在将 Ameba 集成到开发工作流时使用,包括 CI/CD 管道、预提交钩子、GitHub Actions 和自动化代码审查过程。 允许的工具:

  • Bash
  • Read

Ameba 集成

将 Ameba 集成到您的开发工作流中,用于在 CI/CD 管道、预提交钩子和代码审查过程中进行自动化 Crystal 代码质量检查。

集成概述

Ameba 可以在您的开发工作流的多个点集成:

  • 预提交钩子 - 在提交前捕获问题
  • CI/CD 管道 - 在自动化构建中强制执行质量门
  • GitHub Actions - 自动化 PR 审查和状态检查
  • 编辑器集成 - 编码时的实时反馈
  • 代码审查 - 在拉取请求上的自动化评论
  • 预推送钩子 - 推送到远程前的最终检查

命令行使用

基本命令

# 在整个项目上运行 Ameba
ameba

# 在特定文件上运行
ameba src/models/user.cr

# 在特定目录上运行
ameba src/services/

# 使用特定配置运行
ameba --config .ameba.custom.yml

# 生成默认配置
ameba --gen-config

# 自动修复可纠正的问题
ameba --fix

# 仅检查特定规则
ameba --only Style/RedundantReturn

# 排除特定规则
ameba --except Style/LargeNumbers

# 格式化输出
ameba --format json
ameba --format junit
ameba --format flycheck

# 解释特定位置的问题
ameba --explain src/models/user.cr:10:5

# 运行所有输出
ameba --all

# 无问题时静默失败
ameba --silent

输出格式

# 默认:人类可读
ameba
# 输出:
# src/user.cr:10:5: Style/RedundantReturn: 检测到冗余返回

# JSON 格式(用于解析)
ameba --format json
# 输出: {"sources": [...], "summary": {...}}

# JUnit XML(用于 CI 集成)
ameba --format junit > ameba-results.xml

# Flycheck 格式(用于 Emacs)
ameba --format flycheck

高级使用

# 仅检查更改的文件(git)
git diff --name-only --diff-filter=ACM | grep '\.cr$' | xargs ameba

# 仅检查暂存文件
git diff --cached --name-only --diff-filter=ACM | grep '\.cr$' | xargs ameba

# 使用并行处理运行(如果可用)
ameba --parallel

# 基于严重性设置退出代码
ameba --fail-level error    # 仅对错误失败
ameba --fail-level warning  # 对警告和错误失败
ameba --fail-level convention  # 对所有问题失败

# 生成格式化报告
ameba --format json | jq '.summary'

预提交钩子

Git 钩子设置

创建 .git/hooks/pre-commit

#!/bin/sh
# .git/hooks/pre-commit - 在暂存的 Crystal 文件上运行 Ameba

echo "在暂存文件上运行 Ameba..."

# 获取暂存的 Crystal 文件
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.cr$')

if [ -z "$STAGED_FILES" ]; then
  echo "没有暂存的 Crystal 文件,跳过 Ameba"
  exit 0
fi

# 在暂存文件上运行 Ameba
echo "$STAGED_FILES" | xargs ameba

# 捕获退出代码
AMEBA_EXIT=$?

if [ $AMEBA_EXIT -ne 0 ]; then
  echo "❌ Ameba 发现问题。请在提交前修复它们。"
  echo "运行 'ameba --fix' 自动纠正一些问题。"
  exit 1
fi

echo "✅ Ameba 检查通过"
exit 0

使其可执行:

chmod +x .git/hooks/pre-commit

高级预提交钩子

#!/bin/sh
# 带自动修复选项的高级预提交钩子

echo "在暂存文件上运行 Ameba..."

STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.cr$')

if [ -z "$STAGED_FILES" ]; then
  exit 0
fi

# 运行 Ameba
echo "$STAGED_FILES" | xargs ameba
AMEBA_EXIT=$?

if [ $AMEBA_EXIT -ne 0 ]; then
  echo ""
  echo "❌ Ameba 发现问题。"
  echo ""
  read -p "是否要自动修复可纠正的问题?(y/n) " -n 1 -r
  echo

  if [[ $REPLY =~ ^[Yy]$ ]]; then
    echo "运行 ameba --fix..."
    echo "$STAGED_FILES" | xargs ameba --fix

    # 重新添加修复后的文件
    echo "$STAGED_FILES" | xargs git add

    echo "✅ 自动修复问题并重新暂存文件"
    echo "⚠️  请在再次提交前审查更改"
    exit 1  # 退出以允许审查
  else
    echo "请在提交前手动修复问题"
    exit 1
  fi
fi

echo "✅ Ameba 检查通过"
exit 0

预提交框架集成

使用 pre-commit 框架:

创建 .pre-commit-config.yaml

# .pre-commit-config.yaml
存储库:
  - 存储库: 本地
    钩子:
      - id: ameba
        名称: Ameba (Crystal 代码检查器)
        入口: ameba
        语言: 系统
        文件: \.cr$
        传递文件名: true

  - 存储库: 本地
    钩子:
      - id: crystal-format
        名称: Crystal 格式化
        入口: crystal tool format
        语言: 系统
        文件: \.cr$
        传递文件名: true

安装和使用:

# 安装 pre-commit
pip install pre-commit  # 或 brew install pre-commit

# 安装钩子
pre-commit install

# 手动运行
pre-commit run --all-files

# 在特定文件上运行
pre-commit run --files src/user.cr

预提交配置选项

# .pre-commit-config.yaml 带选项
存储库:
  - 存储库: 本地
    钩子:
      - id: ameba
        名称: Ameba
        入口: ameba
        语言: 系统
        文件: \.cr$
        传递文件名: true

      - id: ameba-strict
        名称: Ameba (严格)
        入口: ameba --fail-level convention
        语言: 系统
        文件: ^src/.*\.cr$  # 仅 src 目录
        传递文件名: true

      - id: ameba-autofix
        名称: Ameba 自动修复
        入口: ameba --fix
        语言: 系统
        文件: \.cr$
        传递文件名: true

GitHub Actions 集成

基本 GitHub Actions 工作流

创建 .github/workflows/ameba.yml

名称: Ameba
用户可调用: false

触发:
  推送:
    分支: [ main, develop ]
  拉取请求:
    分支: [ main, develop ]

任务:
  代码检查:
    运行在: ubuntu-latest

    步骤:
      - 名称: 检出代码
        使用: actions/checkout@v4

      - 名称: 安装 Crystal
        使用: crystal-lang/install-crystal@v1
        带:
          crystal: latest

      - 名称: 安装依赖
        运行: shards install

      - 名称: 运行 Ameba
        使用: crystal-ameba/github-action@v0.12.0
        环境:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

高级 GitHub Actions 配置

名称: 代码质量
用户可调用: false

触发:
  推送:
    分支: [ main ]
  拉取请求:
    类型: [ opened, synchronize, reopened ]

任务:
  ameba:
    名称: Ameba 代码检查
    运行在: ubuntu-latest

    步骤:
      - 名称: 检出代码
        使用: actions/checkout@v4
        带:
          获取深度: 0  # 完整历史以进行更好分析

      - 名称: 安装 Crystal
        使用: crystal-lang/install-crystal@v1
        带:
          crystal: 1.11.0  # 固定版本以保持一致性

      - 名称: 缓存 shards
        使用: actions/cache@v3
        带:
          路径: lib
          键: ${{ runner.os }}-shards-${{ hashFiles('shard.lock') }}
          恢复键: |
            ${{ runner.os }}-shards-

      - 名称: 安装依赖
        运行: shards install

      - 名称: 运行 Ameba
        使用: crystal-ameba/github-action@v0.12.0
        环境:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - 名称: 上传 Ameba 结果
        如果: always()
        使用: actions/upload-artifact@v3
        带:
          名称: ameba-results
          路径: ameba-results.json

跨 Crystal 版本的矩阵测试

名称: 跨版本质量
用户可调用: false

触发: [推送, 拉取请求]

任务:
  ameba:
    策略:
      矩阵:
        crystal: [1.10.0, 1.11.0, latest]
        os: [ubuntu-latest, macos-latest]

    运行在: ${{ matrix.os }}

    步骤:
      - 使用: actions/checkout@v4

      - 名称: 安装 Crystal ${{ matrix.crystal }}
        使用: crystal-lang/install-crystal@v1
        带:
          crystal: ${{ matrix.crystal }}

      - 名称: 安装依赖
        运行: shards install

      - 名称: 运行 Ameba
        运行: |
          crystal run bin/ameba.cr -- --format json > ameba-results.json

      - 名称: 检查结果
        运行: |
          if [ $(jq '.summary.issues_count' ameba-results.json) -gt 0 ]; then
            echo "❌ 发现问题"
            jq '.summary' ameba-results.json
            exit 1
          fi

拉取请求审查集成

名称: PR 代码审查
用户可调用: false

触发:
  拉取请求:
    类型: [ opened, synchronize ]

任务:
  审查:
    运行在: ubuntu-latest

    权限:
      内容: 读取
      拉取请求: 写入

    步骤:
      - 使用: actions/checkout@v4
        带:
          获取深度: 0

      - 名称: 安装 Crystal
        使用: crystal-lang/install-crystal@v1

      - 名称: 安装依赖
        运行: shards install

      - 名称: 获取更改文件
        id: changed-files
        使用: tj-actions/changed-files@v40
        带:
          文件: |
            **/*.cr

      - 名称: 在更改文件上运行 Ameba
        如果: steps.changed-files.outputs.any_changed == 'true'
        运行: |
          echo "${{ steps.changed-files.outputs.all_changed_files }}" | \
            xargs ameba --format json > ameba-results.json

      - 名称: 评论 PR
        如果: steps.changed-files.outputs.any_changed == 'true'
        使用: actions/github-script@v7
        带:
          脚本: |
            const fs = require('fs');
            const results = JSON.parse(fs.readFileSync('ameba-results.json', 'utf8'));

            if (results.summary.issues_count > 0) {
              const body = `## Ameba 报告

              发现 ${results.summary.issues_count} 个问题:

              ${results.sources.flatMap(s =>
                s.issues.map(i =>
                  \`- \${s.path}:\${i.location.line}:\${i.location.column} - \${i.rule.name}: \${i.message}\`
                )
              ).join('\
')}`;

              await github.rest.issues.createComment({
                所有者: context.repo.owner,
                仓库: context.repo.repo,
                问题编号: context.issue.number,
                正文: body
              });
            }

CI/CD 管道集成

GitLab CI/CD

# .gitlab-ci.yml
阶段:
  - 质量
  - 测试
  - 构建

ameba:
  阶段: 质量
  镜像: crystallang/crystal:latest

  前脚本:
    - shards install

  脚本:
    - crystal run bin/ameba.cr -- --format junit > ameba-results.xml

  制品:
    报告:
      junit: ameba-results.xml
    路径:
      - ameba-results.xml
    当: always
    过期于: 1 周

  规则:
    - 如果: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    - 如果: '$CI_COMMIT_BRANCH == "main"'

ameba-strict:
  扩展: ameba
  脚本:
    - crystal run bin/ameba.cr -- --fail-level convention
  仅:
    - main

CircleCI

# .circleci/config.yml
版本: 2.1

球:
  crystal: manastech/crystal@1.0

任务:
  ameba:
    执行器:
      名称: crystal/default
      标签: "1.11"

    步骤:
      - 检出

      - 恢复缓存:
          键:
            - shards-v1-{{ checksum "shard.lock" }}
            - shards-v1-

      - 运行:
          名称: 安装依赖
          命令: shards install

      - 保存缓存:
          键: shards-v1-{{ checksum "shard.lock" }}
          路径:
            - lib

      - 运行:
          名称: 运行 Ameba
          命令: |
            crystal run bin/ameba.cr -- --format junit > ameba-results.xml

      - 存储测试结果:
          路径: ameba-results.xml

      - 存储制品:
          路径: ameba-results.xml

工作流:
  版本: 2
  质量:
    任务:
      - ameba

Jenkins 管道

// Jenkinsfile
管道 {
    代理 {
        码头 {
            镜像 'crystallang/crystal:latest'
        }
    }

    阶段 {
        阶段('设置') {
            步骤 {
                sh 'shards install'
            }
        }

        阶段('Ameba') {
            步骤 {
                sh '''
                    crystal run bin/ameba.cr -- --format junit > ameba-results.xml || true
                '''
            }
            后 {
                总是 {
                    junit 'ameba-results.xml'
                }
            }
        }

        阶段('Ameba 严格') {
            当 {
                分支 'main'
            }
            步骤 {
                sh 'crystal run bin/ameba.cr -- --fail-level error'
            }
        }
    }

    后 {
        失败 {
            emailext(
                主题: "${env.JOB_NAME} 中的 Ameba 失败",
                正文: "检查控制台输出在 ${env.BUILD_URL}",
                到: "${env.CHANGE_AUTHOR_EMAIL}"
            )
        }
    }
}

Travis CI

# .travis.yml
语言: crystal

crystal:
  - latest
  - 1.11.0

安装:
  - shards install

脚本:
  - crystal spec
  - crystal run bin/ameba.cr -- --fail-level warning

缓存:
  目录:
    - lib

通知:
  电子邮件:
    成功时: never
    失败时: change

编辑器集成

VS Code

安装 Crystal 语言扩展并配置:

// .vscode/settings.json
{
  "crystal-lang.server": "crystalline",
  "crystal-lang.problems": "build",

  // 保存时运行 Ameba
  "emeraldwalk.runonsave": {
    "命令": [
      {
        "匹配": "\\.cr$",
        "命令": "ameba ${file}"
      }
    ]
  },

  // 保存时格式化
  "editor.formatOnSave": true,
  "[crystal]": {
    "editor.defaultFormatter": "crystal-lang-tools.crystal-lang"
  }
}

创建 .vscode/tasks.json

{
  "版本": "2.0.0",
  "任务": [
    {
      "标签": "Ameba",
      "类型": "shell",
      "命令": "ameba",
      "问题匹配器": {
        "所有者": "crystal",
        "文件位置": ["relative", "${workspaceFolder}"],
        "模式": {
          "正则表达式": "^(.+):(\\d+):(\\d+):\\s+(.+):\\s+(.+)$",
          "文件": 1,
          "行": 2,
          "列": 3,
          "严重性": 4,
          "消息": 5
        }
      },
      "组": {
        "种类": "build",
        "isDefault": true
      }
    },
    {
      "标签": "Ameba 修复",
      "类型": "shell",
      "命令": "ameba --fix",
      "组": "build"
    }
  ]
}

Vim/Neovim

使用 ALE(异步检查引擎):

" .vimrc 或 init.vim
让 g:ale_linters = {
\   'crystal': ['ameba', 'crystal'],
\}

让 g:ale_fixers = {
\   'crystal': ['ameba'],
\}

" 启用保存时自动修复
让 g:ale_fix_on_save = 1

" Ameba 选项
让 g:ale_crystal_ameba_executable = 'ameba'

Emacs

;; .emacs 或 init.el
(require 'flycheck)

(flycheck-define-checker crystal-ameba
  "使用 Ameba 的 Crystal 检查器。"
  :command ("ameba" "--format" "flycheck" source)
  :error-patterns
  ((错误 行开始 (文件名称) ":" 行 ":" 列 ": E: " (消息) 行结束)
   (警告 行开始 (文件名称) ":" 行 ":" 列 ": W: " (消息) 行结束)
   (信息 行开始 (文件名称) ":" 行 ":" 列 ": I: " (消息) 行结束))
  :modes crystal-mode)

(添加-到-列表 'flycheck-checkers 'crystal-ameba)

质量门和策略

快速失败策略

#!/bin/bash
# scripts/quality-gate.sh

echo "运行质量门..."

# 门 1: 仅关键错误
echo "门 1: 关键错误"
ameba --only Lint/Syntax,Lint/UnreachableCode --fail-level error
if [ $? -ne 0 ]; then
  echo "❌ 发现关键错误"
  exit 1
fi

# 门 2: 所有错误
echo "门 2: 所有错误"
ameba --fail-level error
if [ $? -ne 0 ]; then
  echo "❌ 发现错误"
  exit 1
fi

# 门 3: 警告(当前非阻塞)
echo "门 3: 警告(信息性)"
ameba --fail-level warning || echo "⚠️  发现警告(非阻塞)"

echo "✅ 所有质量门通过"

渐进严格性

# .github/workflows/quality-gates.yml
名称: 质量门
用户可调用: false

触发: [推送, 拉取请求]

任务:
  关键:
    名称: 关键问题
    运行在: ubuntu-latest
    步骤:
      - 使用: actions/checkout@v4
      - 使用: crystal-lang/install-crystal@v1
      - 运行: shards install
      - 名称: 检查关键
        运行: ameba --only Lint/Syntax --fail-level error

  错误:
    名称: 所有错误
    需要: 关键
    运行在: ubuntu-latest
    步骤:
      - 使用: actions/checkout@v4
      - 使用: crystal-lang/install-crystal@v1
      - 运行: shards install
      - 名称: 检查错误
        运行: ameba --fail-level error

  警告:
    名称: 警告(仅主分支)
    需要: 错误
    如果: github.ref == 'refs/heads/main'
    运行在: ubuntu-latest
    步骤:
      - 使用: actions/checkout@v4
      - 使用: crystal-lang/install-crystal@v1
      - 运行: shards install
      - 名称: 检查警告
        运行: ameba --fail-level warning

渐进改进(防止新问题)

#!/bin/bash
# scripts/ameba-ratchet.sh
# 仅在新问题上失败,不是现有问题

# 获取基线问题计数(从主分支)
git fetch origin main
BASELINE=$(git show origin/main:.ameba-baseline.json 2>/dev/null || echo '{"count": 0}')
BASELINE_COUNT=$(echo "$BASELINE" | jq '.count')

# 运行 Ameba 并计数当前问题
ameba --format json > current-results.json
CURRENT_COUNT=$(jq '.summary.issues_count' current-results.json)

echo "基线问题: $BASELINE_COUNT"
echo "当前问题: $CURRENT_COUNT"

if [ "$CURRENT_COUNT" -gt "$BASELINE_COUNT" ]; then
  echo "❌ 引入新问题($((CURRENT_COUNT - BASELINE_COUNT)) 个新问题)"
  exit 1
fi

if [ "$CURRENT_COUNT" -lt "$BASELINE_COUNT" ]; then
  echo "✅ 问题减少!($((BASELINE_COUNT - CURRENT_COUNT)) 个更少问题)"
fi

echo "✅ 无新问题"

报告和监控

生成 HTML 报告

#!/bin/bash
# scripts/generate-report.sh

ameba --format json > ameba-results.json

# 使用 jq 和模板转换为 HTML
cat > ameba-report.html <<'EOF'
<!DOCTYPE html>
<html>
<head>
  <title>Ameba 报告</title>
  <style>
    body { font-family: Arial, sans-serif; margin: 20px; }
    .summary { background: #f0f0f0; padding: 20px; margin-bottom: 20px; }
    .issue { border-left: 3px solid red; padding: 10px; margin: 10px 0; }
    .error { border-color: #d32f2f; }
    .warning { border-color: #f57c00; }
    .convention { border-color: #fbc02d; }
  </style>
</head>
<body>
  <h1>Ameba 代码质量报告</h1>
  <div class="summary">
EOF

jq -r '.summary | "
    <h2>摘要</h2>
    <p>总问题数: \(.issues_count)</p>
    <p>分析文件数: \(.target_sources_count)</p>
"' ameba-results.json >> ameba-report.html

echo '<h2>问题</h2>' >> ameba-report.html

jq -r '.sources[] | select(.issues | length > 0) | .path as $path | .issues[] | "
  <div class=\"issue \(.rule.severity | ascii_downcase)\">
    <strong>\($path):\(.location.line):\(.location.column)</strong><br>
    \(.rule.name): \(.message)
  </div>
"' ameba-results.json >> ameba-report.html

echo '</body></html>' >> ameba-report.html

echo "报告生成: ameba-report.html"

指标跟踪

#!/bin/bash
# scripts/track-metrics.sh
# 随时间跟踪 Ameba 指标

TIMESTAMP=$(date +%Y-%m-%d)
ameba --format json > "metrics/ameba-$TIMESTAMP.json"

# 提取关键指标
jq '{
  日期: "'$TIMESTAMP'",
  问题: .summary.issues_count,
  文件: .summary.target_sources_count,
  错误: [.sources[].issues[] | select(.rule.severity == "Error")] | length,
  警告: [.sources[].issues[] | select(.rule.severity == "Warning")] | length
}' "metrics/ameba-$TIMESTAMP.json" >> metrics/history.jsonl

# 生成趋势图(需要 gnuplot 或类似)
echo "指标已跟踪于 $TIMESTAMP"

何时使用此技能

在以下情况下使用 ameba-integration 技能:

  • 为 Crystal 项目设置 CI/CD 管道
  • 实现自动化代码审查过程
  • 为部署建立质量门
  • 为团队开发配置预提交钩子
  • 将静态分析集成到 GitHub Actions
  • 创建自动化 PR 审查工作流
  • 设置编辑器集成以获取实时反馈
  • 实现渐进质量改进(渐进改进)
  • 为利益相关者生成代码质量报告
  • 从手动代码审查迁移到自动化检查
  • 建立编码标准执行
  • 为新团队成员提供自动化反馈

最佳实践

  1. 从 CI/CD 开始 - 首先在 CI 管道中实施,然后再本地钩子
  2. 使用缓存 - 缓存依赖和 Ameba 结果以加快构建
  3. 适当失败 - 使用 --fail-level 匹配管道需求
  4. 提供反馈 - 在 PR 上生成报告和评论
  5. 使其快速 - 在预提交钩子中仅检查更改文件
  6. 允许绕过 - 提供 --no-verify 选项用于紧急情况
  7. 渐进执行 - 开始时宽松,随时间增加严格性
  8. 监控指标 - 跟踪问题以衡量改进
  9. 分离关注点 - 不同环境使用不同规则/严重性
  10. 记录过程 - 为团队提供清晰的本场运行说明
  11. 使用制品 - 存储结果用于后期分析和趋势
  12. 尽可能自动修复 - 在交互式环境中提供自动修复
  13. 固定版本 - 在 CI 中使用特定 Ameba 版本以保持一致性
  14. 优雅处理失败 - 提供有帮助的错误消息
  15. 保持维护 - 定期更新集成和配置

常见陷阱

  1. 阻塞所有提交 - 过于严格的预提交钩子让开发人员沮丧
  2. 无缓存 - 每次重新下载依赖导致 CI 构建缓慢
  3. 分析生成文件 - 浪费时间在自动生成的代码上
  4. 未固定版本 - 不同 Ameba 版本产生不同结果
  5. 缺少更改文件检测 - 在每个 PR 中运行整个代码库
  6. 无失败上下文 - 没有指导的模糊错误消息
  7. 不一致配置 - 本地与 CI 设置不同
  8. 长反馈循环 - 开发人员发现问题太晚
  9. 无自动修复选项 - 可纠正问题需要手动修复
  10. 静默失败 - CI 通过但 Ameba 未实际运行
  11. 过多通知 - 用每个小问题骚扰团队
  12. 无绕过机制 - 需要时无法提交紧急修复
  13. 忽略性能 - 缓慢分析导致 CI 超时
  14. 未使用并行任务 - 顺序执行减慢管道
  15. 缺少测试覆盖 - 未验证集成实际工作

资源