| name | ameba-integration |
| description | Use when integrating Ameba into development workflows including CI/CD pipelines, pre-commit hooks, GitHub Actions, and automated code review processes. |
| allowed-tools | ["Bash","Read"] |
Ameba Integration
Integrate Ameba into your development workflow for automated Crystal code quality checks in CI/CD pipelines, pre-commit hooks, and code review processes.
Integration Overview
Ameba can be integrated at multiple points in your development workflow:
- Pre-commit hooks - Catch issues before they're committed
- CI/CD pipelines - Enforce quality gates in automated builds
- GitHub Actions - Automated PR reviews and status checks
- Editor integration - Real-time feedback while coding
- Code review - Automated comments on pull requests
- Pre-push hooks - Final check before pushing to remote
Command-Line Usage
Basic Commands
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
Output Formats
ameba
ameba --format json
ameba --format junit > ameba-results.xml
ameba --format flycheck
Advanced Usage
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'
Pre-Commit Hooks
Git Hook Setup
Create .git/hooks/pre-commit:
#!/bin/sh
echo "Running Ameba on staged files..."
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.cr$')
if [ -z "$STAGED_FILES" ]; then
echo "No Crystal files staged, skipping Ameba"
exit 0
fi
echo "$STAGED_FILES" | xargs ameba
AMEBA_EXIT=$?
if [ $AMEBA_EXIT -ne 0 ]; then
echo "❌ Ameba found issues. Please fix them before committing."
echo "Run 'ameba --fix' to auto-correct some issues."
exit 1
fi
echo "✅ Ameba checks passed"
exit 0
Make it executable:
chmod +x .git/hooks/pre-commit
Advanced Pre-Commit Hook
#!/bin/sh
echo "Running Ameba on staged files..."
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.cr$')
if [ -z "$STAGED_FILES" ]; then
exit 0
fi
echo "$STAGED_FILES" | xargs ameba
AMEBA_EXIT=$?
if [ $AMEBA_EXIT -ne 0 ]; then
echo ""
echo "❌ Ameba found issues."
echo ""
read -p "Would you like to auto-fix correctable issues? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "Running ameba --fix..."
echo "$STAGED_FILES" | xargs ameba --fix
echo "$STAGED_FILES" | xargs git add
echo "✅ Auto-fixed issues and re-staged files"
echo "⚠️ Please review the changes before committing again"
exit 1
else
echo "Please fix issues manually before committing"
1
0
Pre-Commit Framework Integration
Using the pre-commit framework:
Create .pre-commit-config.yaml:
repos:
- repo: local
hooks:
- id: ameba
name: Ameba (Crystal Linter)
entry: ameba
language: system
files: \.cr$
pass_filenames: true
- repo: local
hooks:
- id: crystal-format
name: Crystal Format
entry: crystal tool format
language: system
files: \.cr$
pass_filenames: true
Install and use:
pip install pre-commit
pre-commit install
pre-commit run --all-files
pre-commit run --files src/user.cr
Pre-Commit Configuration Options
repos:
- repo: local
hooks:
- id: ameba
name: Ameba
entry: ameba
language: system
files: \.cr$
pass_filenames: true
- id: ameba-strict
name: Ameba (Strict)
entry: ameba --fail-level convention
language: system
files: ^src/.*\.cr$
pass_filenames: true
- id: ameba-autofix
name: Ameba Auto-fix
entry: ameba --fix
language: system
files: \.cr$
pass_filenames: true
GitHub Actions Integration
Basic GitHub Actions Workflow
Create .github/workflows/ameba.yml:
name: Ameba
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Crystal
uses: crystal-lang/install-crystal@v1
with:
crystal: latest
- name: Install dependencies
run: shards install
- name: Run Ameba
uses: crystal-ameba/github-action@v0.12.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Advanced GitHub Actions Configuration
name: Code Quality
on:
push:
branches: [ main ]
pull_request:
types: [ opened, synchronize, reopened ]
jobs:
ameba:
name: Ameba Linting
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Crystal
uses: crystal-lang/install-crystal@v1
with:
crystal: 1.11.0
- name: Cache shards
uses: actions/cache@v3
with:
path: lib
key: ${{ runner.os }}-shards-${{ hashFiles('shard.lock')
Matrix Testing Across Crystal Versions
name: Quality Across Versions
on: [push, pull_request]
jobs:
ameba:
strategy:
matrix:
crystal: [1.10.0, 1.11.0, latest]
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Install Crystal ${{ matrix.crystal }}
uses: crystal-lang/install-crystal@v1
with:
crystal: ${{ matrix.crystal }}
- name: Install dependencies
run: shards install
- name: Run Ameba
run: |
crystal run bin/ameba.cr -- --format json > ameba-results.json
Pull Request Review Integration
name: PR Code Review
on:
pull_request:
types: [ opened, synchronize ]
jobs:
review:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Crystal
uses: crystal-lang/install-crystal@v1
- name: Install dependencies
run: shards install
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v40
with:
files: |
**/*.cr
- name: Run Ameba on changed
{
{}
{
{}{}{} {} {}
}
{
,
,
,
}
}
CI/CD Pipeline Integration
GitLab CI/CD
stages:
- quality
- test
- build
ameba:
stage: quality
image: crystallang/crystal:latest
before_script:
- shards install
script:
- crystal run bin/ameba.cr -- --format junit > ameba-results.xml
artifacts:
reports:
junit: ameba-results.xml
paths:
- ameba-results.xml
when: always
expire_in: 1 week
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH == "main"'
ameba-strict:
extends: ameba
script:
- crystal run bin/ameba.cr -- --fail-level
CircleCI
version: 2.1
orbs:
crystal: manastech/crystal@1.0
jobs:
ameba:
executor:
name: crystal/default
tag: "1.11"
steps:
- checkout
- restore_cache:
keys:
- shards-v1-{{ checksum "shard.lock" }}
- shards-v1-
- run:
name: Install dependencies
command: shards install
- save_cache:
key: shards-v1-{{ checksum "shard.lock" }}
paths:
- lib
- run:
name: Run Ameba
command: |
crystal run bin/ameba.cr -- --format junit > ameba-results.xml
- store_test_results:
path:
Jenkins Pipeline
// Jenkinsfile
pipeline {
agent {
docker {
image 'crystallang/crystal:latest'
}
}
stages {
stage('Setup') {
steps {
sh 'shards install'
}
}
stage('Ameba') {
steps {
sh '''
crystal run bin/ameba.cr -- --format junit > ameba-results.xml || true
'''
}
post {
always {
junit 'ameba-results.xml'
}
}
}
stage('Ameba Strict') {
when {
branch 'main'
}
steps {
sh 'crystal run bin/ameba.cr -- --fail-level error'
}
}
}
post {
failure {
emailext(
subject: "Ameba Failures in ${env.JOB_NAME}",
body: "Check console output at ${env.BUILD_URL}",
to: "${env.CHANGE_AUTHOR_EMAIL}"
)
}
}
}
Travis CI
language: crystal
crystal:
- latest
- 1.11.0
install:
- shards install
script:
- crystal spec
- crystal run bin/ameba.cr -- --fail-level warning
cache:
directories:
- lib
notifications:
email:
on_success: never
on_failure: change
Editor Integration
VS Code
Install the Crystal Language extension and configure:
{
"crystal-lang.server": "crystalline",
"crystal-lang.problems": "build",
"emeraldwalk.runonsave": {
"commands": [
{
"match": "\\.cr$",
"cmd": "ameba ${file}"
}
]
},
"editor.formatOnSave": true,
"[crystal]": {
"editor.defaultFormatter": "crystal-lang-tools.crystal-lang"
}
}
Create .vscode/tasks.json:
{
"version": "2.0.0",
"tasks": [
{
"label": "Ameba",
"type": "shell",
"command": "ameba",
"problemMatcher": {
"owner": "crystal",
"fileLocation": ["relative", "${workspaceFolder}"],
"pattern": {
"regexp": "^(.+):(\\d+):(\\d+):\\s+(.+):\\s+(.+)$",
"file": 1,
"line": 2,
"column": 3,
"severity":
Vim/Neovim
Using ALE (Asynchronous Lint Engine):
" .vimrc or init.vim
let g:ale_linters = {
\ 'crystal': ['ameba', 'crystal'],
\}
let g:ale_fixers = {
\ 'crystal': ['ameba'],
\}
" Enable auto-fixing on save
let g:ale_fix_on_save = 1
" Ameba options
let g:ale_crystal_ameba_executable = 'ameba'
Emacs
;; .emacs or init.el
(require 'flycheck)
(flycheck-define-checker crystal-ameba
"Crystal linter using Ameba."
:command ("ameba" "--format" "flycheck" source)
:error-patterns
((error line-start (file-name) ":" line ":" column ": E: " (message) line-end)
(warning line-start (file-name) ":" line ":" column ": W: " (message) line-end)
(info line-start (file-name) ":" line ":" column ": I: " (message) line-end))
:modes crystal-mode)
(add-to-list 'flycheck-checkers 'crystal-ameba)
Quality Gates and Policies
Fail-Fast Strategy
#!/bin/bash
echo "Running quality gates..."
echo "Gate 1: Critical errors"
ameba --only Lint/Syntax,Lint/UnreachableCode --fail-level error
if [ $? -ne 0 ]; then
echo "❌ Critical errors found"
exit 1
fi
echo "Gate 2: All errors"
ameba --fail-level error
if [ $? -ne 0 ]; then
echo "❌ Errors found"
exit 1
fi
echo "Gate 3: Warnings (informational)"
ameba --fail-level warning || echo "⚠️ Warnings found (not blocking)"
echo "✅ All quality gates passed"
Progressive Strictness
name: Quality Gates
on: [push, pull_request]
jobs:
critical:
name: Critical Issues
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: crystal-lang/install-crystal@v1
- run: shards install
- name: Check critical
run: ameba --only Lint/Syntax --fail-level error
errors:
name: All Errors
needs: critical
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: crystal-lang/install-crystal@v1
- run: shards install
- name:
Ratcheting (Prevent New Issues)
#!/bin/bash
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 --format json > current-results.json
CURRENT_COUNT=$(jq '.summary.issues_count' current-results.json)
echo "Baseline issues: $BASELINE_COUNT"
echo "Current issues: $CURRENT_COUNT"
if [ "$CURRENT_COUNT" -gt "$BASELINE_COUNT" ]; then
echo "❌ New issues introduced ($((CURRENT_COUNT - BASELINE_COUNT)) new issues)"
exit 1
fi
if [ "$CURRENT_COUNT" -lt "$BASELINE_COUNT" ]; then
echo "✅ Issues reduced! ($((BASELINE_COUNT - CURRENT_COUNT)) fewer issues)"
fi
echo "✅ No new issues"
Reporting and Monitoring
Generate HTML Reports
#!/bin/bash
ameba --format json > ameba-results.json
cat > ameba-report.html <<'EOF'
<!DOCTYPE html>
<html>
<head>
<title>Ameba Report</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.summary { background:
.issue { border-left: 3px solid red; padding: 10px; margin: 10px 0; }
.error { border-color:
.warning { border-color:
.convention { border-color:
</style>
</head>
<body>
<h1>Ameba Code Quality Report</h1>
<div class="summary">
EOF
jq -r '.summary | "
<h2>Summary</h2>
<p>Total Issues: \(.issues_count)</p>
<p>Files Analyzed: \(.target_sources_count)</p>
"' ameba-results.json >> ameba-report.html
echo '<h2>Issues</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 "Report generated: ameba-report.html"
Metrics Tracking
#!/bin/bash
TIMESTAMP=$(date +%Y-%m-%d)
ameba --format json > "metrics/ameba-$TIMESTAMP.json"
jq '{
date: "'$TIMESTAMP'",
issues: .summary.issues_count,
files: .summary.target_sources_count,
errors: [.sources[].issues[] | select(.rule.severity == "Error")] | length,
warnings: [.sources[].issues[] | select(.rule.severity == "Warning")] | length
}' "metrics/ameba-$TIMESTAMP.json" >> metrics/history.jsonl
echo "Metrics tracked for $TIMESTAMP"
When to Use This Skill
Use the ameba-integration skill when:
- Setting up CI/CD pipelines for Crystal projects
- Implementing automated code review processes
- Establishing quality gates for deployments
- Configuring pre-commit hooks for team development
- Integrating static analysis into GitHub Actions
- Creating automated PR review workflows
- Setting up editor integrations for real-time feedback
- Implementing progressive quality improvements (ratcheting)
- Generating code quality reports for stakeholders
- Migrating from manual code review to automated checks
- Establishing coding standards enforcement
- Onboarding new team members with automated feedback
Best Practices
- Start with CI/CD - Implement in CI pipeline first before local hooks
- Use caching - Cache dependencies and Ameba results for faster builds
- Fail appropriately - Use
--fail-level to match pipeline requirements
- Provide feedback - Generate reports and comments on PRs
- Make it fast - Only check changed files in pre-commit hooks
- Allow bypass - Provide
--no-verify option for emergencies
- Progressive enforcement - Start permissive, increase strictness over time
- Monitor metrics - Track issues over time to measure improvement
- Separate concerns - Different rules/severity for different environments
- Document process - Clear instructions for team on running locally
- Use artifacts - Store results for later analysis and trending
- Auto-fix when possible - Offer automatic fixes in interactive environments
- Pin versions - Use specific Ameba versions in CI for consistency
- Handle failures gracefully - Provide helpful error messages
- Keep it maintained - Regularly update integrations and configurations
Common Pitfalls
- Blocking all commits - Too strict pre-commit hooks frustrate developers
- No caching - Slow CI builds from re-downloading dependencies every time
- Analyzing generated files - Wasting time on auto-generated code
- Not pinning versions - Different Ameba versions produce different results
- Missing changed files detection - Running on entire codebase in every PR
- No failure context - Cryptic error messages without guidance
- Inconsistent configuration - Different settings locally vs CI
- Long feedback loops - Developers find out about issues too late
- No auto-fix option - Manual fixes for correctable issues
- Silent failures - CI passes but Ameba didn't actually run
- Excessive notifications - Spamming team with every minor issue
- No bypass mechanism - Can't commit urgent fixes when needed
- Ignoring performance - CI timeout from slow analysis
- Not using parallel jobs - Sequential execution slows down pipeline
- Missing test coverage - Not verifying integration actually works
Resources