チュートリアル: CI/CD 連携¶
自動コードレビュー、ドキュメント生成、AI 支援テストのために clinvoker を CI/CD パイプラインへ統合する方法を説明します。このチュートリアルでは GitHub Actions / GitLab CI / Jenkins の設定例を扱います。
CI/CD に clinvoker を統合する理由¶
AI を使った CI/CD のメリット¶
| メリット | 説明 |
|---|---|
| 自動コードレビュー | 人がレビューする前に問題を検出 |
| 品質の一貫性 | すべての PR に同じ基準を適用 |
| ドキュメント | 変更コードのドキュメントを自動生成 |
| セキュリティスキャン | 脆弱性を早期に発見 |
| コスト削減 | 手動レビュー時間を削減 |
連携アーキテクチャ¶
flowchart LR
PR["Pull Request"] -->|トリガ| ACTION["CI/CD パイプライン"]
ACTION -->|API 呼び出し| CLINVK["clinvoker サーバー"]
CLINVK -->|アーキテクチャ| CLAUDE["Claude バックエンド"]
CLINVK -->|性能| CODEX["Codex バックエンド"]
CLINVK -->|セキュリティ| GEMINI["Gemini バックエンド"]
CLAUDE --> RESULT["レビュー結果"]
CODEX --> RESULT
GEMINI --> RESULT
前提条件¶
CI/CD に統合する前に、次を準備してください。
- ローカル検証のために clinvoker がインストール済み
- CI/CD プラットフォーム(GitHub Actions / GitLab CI / Jenkins)へのアクセス
- AI バックエンド用の API キー設定
- YAML とシェルスクリプトの基本理解
clinvoker サーバーのセットアップ¶
CI/CD では永続的な clinvoker サーバーを用意すると運用しやすくなります。
# docker-compose.ci.yml
services:
clinvk:
image: signalridge/clinvoker:latest
command: serve --port 8080
environment:
- CLINVK_API_KEYS=${CLINVK_API_KEYS}
- CLINVK_BACKEND=claude
ports:
- "8080:8080"
volumes:
- ./config.yaml:/root/.clinvk/config.yaml
サーバーをデプロイします。
export CLINVK_API_KEYS="your-api-key-1,your-api-key-2"
docker-compose -f docker-compose.ci.yml up -d
GitHub Actions 連携¶
ワークフロー例(完全版)¶
.github/workflows/ai-code-review.yml を作成します。
name: AI Code Review
on:
pull_request:
types: [opened, synchronize]
paths:
- "**.go"
- "**.py"
- "**.js"
- "**.ts"
- "**.rs"
env:
CLINVK_SERVER: ${{ secrets.CLINVK_SERVER_URL }}
CLINVK_API_KEY: ${{ secrets.CLINVK_API_KEY }}
jobs:
# Job 1: Architecture Review with Claude
architecture-review:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install clinvoker CLI
run: |
curl -sSL https://raw.githubusercontent.com/signalridge/clinvoker/main/install.sh | bash
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Get PR diff
id: diff
run: |
git diff origin/${{ github.base_ref }}...HEAD > pr.diff
echo "size=$(wc -c < pr.diff)" >> $GITHUB_OUTPUT
- name: Skip if diff too large
if: steps.diff.outputs.size > 50000
run: |
echo "Diff too large for AI review (>50KB)"
exit 0
- name: Run architecture review
id: review
run: |
DIFF=$(cat pr.diff | jq -Rs '.')
curl -X POST "${CLINVK_SERVER}/api/v1/prompt" \
-H "Authorization: Bearer ${CLINVK_API_KEY}" \
-H "Content-Type: application/json" \
-d "{
\"backend\": \"claude\",
\"prompt\": \"Review this PR diff for architecture and design patterns. Focus on: 1) SOLID principles, 2) Design patterns, 3) Code organization. DIFF: ${DIFF}\",
\"output_format\": \"json\"
}" > architecture-review.json
echo "result=$(cat architecture-review.json | jq -c .)" >> $GITHUB_OUTPUT
- name: Upload review artifact
uses: actions/upload-artifact@v4
with:
name: architecture-review
path: architecture-review.json
# Job 2: Performance Review with Codex
performance-review:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install clinvoker CLI
run: |
curl -sSL https://raw.githubusercontent.com/signalridge/clinvoker/main/install.sh | bash
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Get PR diff
run: git diff origin/${{ github.base_ref }}...HEAD > pr.diff
- name: Run performance review
run: |
DIFF=$(cat pr.diff | jq -Rs '.')
curl -X POST "${CLINVK_SERVER}/api/v1/prompt" \
-H "Authorization: Bearer ${CLINVK_API_KEY}" \
-H "Content-Type: application/json" \
-d "{
\"backend\": \"codex\",
\"prompt\": \"Review this PR diff for performance implications. Focus on: 1) Algorithmic complexity, 2) Resource usage, 3) Optimization opportunities. DIFF: ${DIFF}\",
\"output_format\": \"json\"
}" > performance-review.json
- name: Upload review artifact
uses: actions/upload-artifact@v4
with:
name: performance-review
path: performance-review.json
# Job 3: Security Review with Gemini
security-review:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install clinvoker CLI
run: |
curl -sSL https://raw.githubusercontent.com/signalridge/clinvoker/main/install.sh | bash
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Get PR diff
run: git diff origin/${{ github.base_ref }}...HEAD > pr.diff
- name: Run security review
run: |
DIFF=$(cat pr.diff | jq -Rs '.')
curl -X POST "${CLINVK_SERVER}/api/v1/prompt" \
-H "Authorization: Bearer ${CLINVK_API_KEY}" \
-H "Content-Type: application/json" \
-d "{
\"backend\": \"gemini\",
\"prompt\": \"Security audit of this PR diff. Focus on: 1) SQL injection, 2) XSS vulnerabilities, 3) Authentication issues, 4) OWASP risks. DIFF: ${DIFF}\",
\"output_format\": \"json\"
}" > security-review.json
- name: Upload review artifact
uses: actions/upload-artifact@v4
with:
name: security-review
path: security-review.json
# Job 4: Aggregate and Post Results
post-review:
needs: [architecture-review, performance-review, security-review]
runs-on: ubuntu-latest
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
- name: Aggregate reviews
id: aggregate
run: |
# Create combined report
cat > review-report.md << 'EOF'
## AI Code Review Results
### Summary
This PR has been reviewed by three AI backends for comprehensive feedback.
EOF
# Add architecture review
echo "#### Architecture Review (Claude)" >> review-report.md
jq -r '.output' architecture-review/architecture-review.json >> review-report.md
echo "" >> review-report.md
# Add performance review
echo "#### Performance Review (Codex)" >> review-report.md
jq -r '.output' performance-review/performance-review.json >> review-report.md
echo "" >> review-report.md
# Add security review
echo "#### Security Review (Gemini)" >> review-report.md
jq -r '.output' security-review/security-review.json >> review-report.md
# Check for critical issues
CRITICAL=$(cat architecture-review/architecture-review.json performance-review/performance-review.json security-review/security-review.json | grep -i "critical" || true)
if [ -n "$CRITICAL" ]; then
echo "has_critical=true" >> $GITHUB_OUTPUT
else
echo "has_critical=false" >> $GITHUB_OUTPUT
fi
- name: Post review comment
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const body = fs.readFileSync('review-report.md', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body.substring(0, 65536)
});
- name: Fail on critical issues
if: steps.aggregate.outputs.has_critical == 'true'
run: |
echo "::error::Critical issues found in AI review"
exit 1
PR コメントの自動投稿¶
ワークフローは PR にコメントを自動投稿できます。

失敗条件と終了コード¶
clinvoker は CI/CD で扱いやすい標準的な終了コードを使用します。
| 終了コード | 意味 | CI/CD での扱い |
|---|---|---|
| 0 | 成功 | 継続 |
| 1 | 一般エラー | ビルド失敗 |
| 2 | バックエンドエラー | リトライ or 失敗 |
| 3 | タイムアウト | 長めのタイムアウトでリトライ |
| 4 | 入力不正 | 早期に失敗 |
ワークフロー側で失敗条件を組む例:
- name: Check for critical issues
run: |
# Check if any review found critical issues
if grep -qi "critical\\|severe\\|blocker" review-*.json; then
echo "::error::Critical issues found"
exit 1
fi
GitLab CI 連携¶
設定例(完全版)¶
.gitlab-ci.yml を作成します。
stages:
- review
- report
variables:
CLINVK_SERVER: $CLINVK_SERVER_URL
CLINVK_API_KEY: $CLINVK_API_KEY
# Template for review jobs
.ai_review:
stage: review
image: alpine/curl
before_script:
- apk add --no-cache jq git bash
- curl -sSL https://raw.githubusercontent.com/signalridge/clinvoker/main/install.sh | bash
- export PATH="$PATH:$HOME/.local/bin"
rules:
- if: $CI_MERGE_REQUEST_IID
# Architecture Review
architecture-review:
extends: .ai_review
script:
- git fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
- git diff origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME...HEAD > mr.diff
- |
DIFF=$(cat mr.diff | jq -Rs '.')
curl -X POST "${CLINVK_SERVER}/api/v1/prompt" \
-H "Authorization: Bearer ${CLINVK_API_KEY}" \
-H "Content-Type: application/json" \
-d "{
\"backend\": \"claude\",
\"prompt\": \"Review architecture: ${DIFF}\"
}" > architecture-review.json
- cat architecture-review.json | jq -r '.output'
artifacts:
paths:
- architecture-review.json
expire_in: 1 week
# Performance Review
performance-review:
extends: .ai_review
script:
- git fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
- git diff origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME...HEAD > mr.diff
- |
DIFF=$(cat mr.diff | jq -Rs '.')
curl -X POST "${CLINVK_SERVER}/api/v1/prompt" \
-H "Authorization: Bearer ${CLINVK_API_KEY}" \
-H "Content-Type: application/json" \
-d "{
\"backend\": \"codex\",
\"prompt\": \"Review performance: ${DIFF}\"
}" > performance-review.json
artifacts:
paths:
- performance-review.json
expire_in: 1 week
# Security Review
security-review:
extends: .ai_review
script:
- git fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
- git diff origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME...HEAD > mr.diff
- |
DIFF=$(cat mr.diff | jq -Rs '.')
curl -X POST "${CLINVK_SERVER}/api/v1/prompt" \
-H "Authorization: Bearer ${CLINVK_API_KEY}" \
-H "Content-Type: application/json" \
-d "{
\"backend\": \"gemini\",
\"prompt\": \"Security audit: ${DIFF}\"
}" > security-review.json
artifacts:
paths:
- security-review.json
expire_in: 1 week
# Aggregate and Post Results
post-review:
stage: report
image: alpine/jq
needs: [architecture-review, performance-review, security-review]
script:
- |
echo "## AI Code Review Results" > review-report.md
echo "" >> review-report.md
echo "### Architecture (Claude)" >> review-report.md
jq -r '.output' architecture-review.json >> review-report.md
echo "" >> review-report.md
echo "### Performance (Codex)" >> review-report.md
jq -r '.output' performance-review.json >> review-report.md
echo "" >> review-report.md
echo "### Security (Gemini)" >> review-report.md
jq -r '.output' security-review.json >> review-report.md
- cat review-report.md
artifacts:
paths:
- review-report.md
expire_in: 1 week
rules:
- if: $CI_MERGE_REQUEST_IID
Jenkins パイプライン¶
Pipeline 例(完全版)¶
Jenkinsfile を作成します。
pipeline {
agent any
environment {
CLINVK_SERVER = credentials('clinvk-server-url')
CLINVK_API_KEY = credentials('clinvk-api-key')
}
stages {
stage('Checkout') {
steps {
checkout scm
sh 'git fetch origin'
}
}
stage('Install clinvoker') {
steps {
sh '''
curl -sSL https://raw.githubusercontent.com/signalridge/clinvoker/main/install.sh | bash
export PATH="$PATH:$HOME/.local/bin"
clinvk version
'''
}
}
stage('Get Diff') {
when {
changeRequest()
}
steps {
sh '''
git diff origin/${CHANGE_TARGET}...HEAD > pr.diff || true
if [ -s pr.diff ]; then
echo "Diff size: $(wc -c < pr.diff) bytes"
else
echo "No changes to review"
touch pr.diff
fi
'''
}
}
stage('Parallel AI Review') {
when {
changeRequest()
}
parallel {
stage('Architecture Review') {
steps {
sh '''
export PATH="$PATH:$HOME/.local/bin"
DIFF=$(cat pr.diff | jq -Rs '.')
curl -X POST "${CLINVK_SERVER}/api/v1/prompt" \
-H "Authorization: Bearer ${CLINVK_API_KEY}" \
-H "Content-Type: application/json" \
-d "{
\"backend\": \"claude\",
\"prompt\": \"Architecture review: ${DIFF}\"
}" > architecture-review.json
'''
}
}
stage('Performance Review') {
steps {
sh '''
export PATH="$PATH:$HOME/.local/bin"
DIFF=$(cat pr.diff | jq -Rs '.')
curl -X POST "${CLINVK_SERVER}/api/v1/prompt" \
-H "Authorization: Bearer ${CLINVK_API_KEY}" \
-H "Content-Type: application/json" \
-d "{
\"backend\": \"codex\",
\"prompt\": \"Performance review: ${DIFF}\"
}" > performance-review.json
'''
}
}
stage('Security Review') {
steps {
sh '''
export PATH="$PATH:$HOME/.local/bin"
DIFF=$(cat pr.diff | jq -Rs '.')
curl -X POST "${CLINVK_SERVER}/api/v1/prompt" \
-H "Authorization: Bearer ${CLINVK_API_KEY}" \
-H "Content-Type: application/json" \
-d "{
\"backend\": \"gemini\",
\"prompt\": \"Security audit: ${DIFF}\"
}" > security-review.json
'''
}
}
}
}
stage('Aggregate Results') {
when {
changeRequest()
}
steps {
sh '''
echo "# AI Code Review Report" > review-report.md
echo "" >> review-report.md
if [ -f architecture-review.json ]; then
echo "## Architecture Review" >> review-report.md
jq -r '.output' architecture-review.json >> review-report.md
echo "" >> review-report.md
fi
if [ -f performance-review.json ]; then
echo "## Performance Review" >> review-report.md
jq -r '.output' performance-review.json >> review-report.md
echo "" >> review-report.md
fi
if [ -f security-review.json ]; then
echo "## Security Review" >> review-report.md
jq -r '.output' security-review.json >> review-report.md
fi
cat review-report.md
'''
}
}
stage('Check Critical Issues') {
when {
changeRequest()
}
steps {
script {
def hasCritical = sh(
script: 'grep -qi \"critical\\|severe\" *-review.json && echo \"true\" || echo \"false\"',
returnStdout: true
).trim()
if (hasCritical == \"true\") {
error(\"Critical issues found in AI review\")
}
}
}
}
}
post {
always {
archiveArtifacts artifacts: '*-review.json,review-report.md', allowEmptyArchive: true
}
}
}
レート制限の考慮¶
レート制限を理解する¶
AI バックエンドのレート制限は CI/CD の挙動に影響します。
| バックエンド | レート制限 | バースト |
|---|---|---|
| Claude | 40 requests/min | 60 |
| Codex | 60 requests/min | 100 |
| Gemini | 60 requests/min | 100 |
レート制限への対策¶
1. リクエストのバッチ化¶
複数ファイルを 1 リクエストにまとめます。
- name: Batch review
run: |
# Combine multiple small files
cat file1.go file2.go file3.go > combined.go
clinvk -b claude "Review these files: $(cat combined.go)"
2. 指数バックオフ¶
バックオフ付きでリトライします。
- name: Review with retry
run: |
for i in 1 2 3; do
clinvk -b claude "Review this" && break
sleep $((2 ** i))
done
3. clinvoker サーバー側のレート制限¶
clinvoker サーバー側でレート制限を有効化できます。
Secrets 管理のベストプラクティス¶
1. Secrets をハードコードしない¶
# BAD - Never do this
env:
CLINVK_API_KEY: "sk-12345..."
# GOOD - Use secrets
env:
CLINVK_API_KEY: ${{ secrets.CLINVK_API_KEY }}
2. 環境別の Secrets を使う¶
# Production
- name: Production Review
if: github.ref == 'refs/heads/main'
env:
CLINVK_API_KEY: ${{ secrets.CLINVK_API_KEY_PROD }}
# Development
- name: Development Review
if: github.ref != 'refs/heads/main'
env:
CLINVK_API_KEY: ${{ secrets.CLINVK_API_KEY_DEV }}
3. 定期的にキーをローテーションする¶
4. キーのスコープを絞る¶
CI/CD 専用の API キーを作成します。
| キー | 用途 | 権限 |
|---|---|---|
| ci-readonly | コードレビュー | 読み取り専用 |
| ci-full | フル自動化 | 読み書き |
コスト最適化の戦略¶
1. diff ベースのレビューのみ¶
- name: Check if review needed
run: |
# Only review changed files
CHANGED=$(git diff --name-only origin/main...HEAD | grep -E '\\.(go|py|js)$')
if [ -z "$CHANGED" ]; then
echo "No code changes to review"
exit 0
fi
2. サイズ上限¶
- name: Skip large diffs
run: |
SIZE=$(git diff origin/main...HEAD | wc -c)
if [ $SIZE -gt 50000 ]; then
echo "Diff too large for AI review"
exit 0
fi
3. バックエンドを選択的に使う¶
# Use cheaper backends for simple tasks
- name: Quick check
run: |
clinvk -b codex "Quick review" # Faster, cheaper
- name: Deep review
run: |
clinvk -b claude "Deep analysis" # More expensive
4. 結果のキャッシュ¶
トラブルシューティング¶
問題: バックエンドがタイムアウトする¶
解決策: タイムアウトを増やし、必要ならリトライします。
問題: レート制限超過¶
解決策: リクエスト間にディレイを入れます。
- name: Rate-limited review
run: |
for file in *.go; do
clinvk -b claude "Review $file"
sleep 2 # Rate limit buffer
done
問題: Secrets が使えない¶
解決策: Secrets 設定を確認します。
次のステップ¶
- 高度なパターンは マルチバックエンドのコードレビュー
- デプロイは HTTP サーバー
- カスタム自動化は AI スキルの構築
- オプション一覧は 設定リファレンス
まとめ¶
このチュートリアルで学んだこと:
- CI/CD 連携のための clinvoker サーバーセットアップ
- GitHub Actions での自動コードレビュー設定
- GitLab CI でのマルチバックエンドレビュー設定
- Jenkins パイプラインへの AI 統合
- レート制限とコスト最適化の導入
- 安全な secrets 管理
- よくある CI/CD 統合問題の対処
CI/CD に clinvoker を統合することで、コード品質チェックを自動化し、問題を早期に検出し、手動レビューを減らしつつ高い品質基準を維持できます。