frappe-testing-cicd について
Frappe アプリ開発者向けの CI/CD スキルです。GitHub Actions、コード検査、テスト、リリースの設定に加え、パイプラインの一般的な障害への対処方法を扱います。
主な機能
- 01GitHub Actions のテストワークフロー設定
- 02pre-commit と Ruff による検査
- 03ESLint の設定ガイダンス
- 04テストカバレッジとレポート生成
- 05Semgrep のセキュリティルール例
- 06CI 障害のトラブルシューティング
活用シーン
- 01Frappe アプリの GitHub Actions CI 構築
- 02Python と JavaScript の検査設定
- 03CI でのテスト実行とカバレッジ生成
- 04データベース、Redis、テストサイトのエラー調査
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ impertio-studio/ frappe_claude_skill_package --skill frappe-testing-cicdインストール後、Claude Code で/frappe-testing-cicdを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/.gitkeepanti-patterns.mdexamples.mdgithub-actions.mdlinting.md詳細
CI/CD パイプライン
クイックリファレンス
| タスク | ツール/ファイル |
|---|---|
| pre-commit フックをインストールする | pre-commit install --hook-type pre-commit --hook-type commit-msg |
| すべての pre-commit チェックを実行する | pre-commit run --all-files |
| リンターを実行する | ruff check . |
| フォーマッターを実行する | ruff format . |
| ESLint を実行する | npx eslint "**/*.js" --quiet |
| CI でテストを実行する | bench --site test_site run-tests --app myapp |
| 並列テストを実行する | bench --site test_site run-parallel-tests --total-builds 2 --build-number 0 |
| カバレッジを生成する | coverage run -m pytest && coverage xml |
| JUnit XML を生成する | bench --site test_site run-tests --junit-xml-output report.xml |
意思決定ツリー:CI/CD のセットアップ
Setting up CI for a Frappe app?
├─ Start with GitHub Actions workflow
│ ├─ ALWAYS include MariaDB + Redis services
│ ├─ ALWAYS use test matrix for Python versions
│ └─ Optionally add PostgreSQL for dual-DB support
├─ Add pre-commit hooks
│ ├─ ALWAYS include ruff (Python linting + formatting)
│ ├─ ALWAYS include eslint + prettier (JS/Vue)
│ └─ Add commitlint for conventional commits
├─ Add security scanning?
│ └─ YES → Add semgrep with Frappe-specific rules
└─ Need release automation?
└─ YES → Add tag-based release workflow
Frappe アプリ向け GitHub Actions ワークフロー
標準サーバーテストワークフロー
name: Server Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
concurrency:
group: server-tests-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12"]
db: ["mariadb"]
services:
mariadb:
image: mariadb:11.4
ports:
- 3306:3306
env:
MARIADB_ROOT_PASSWORD: db_root
options: >-
--health-cmd="healthcheck.sh --connect --innodb_initialized"
--health-interval=5s
--health-timeout=5s
--health-retries=10
redis-cache:
image: redis:alpine
ports:
- 13000:6379
redis-queue:
image: redis:alpine
ports:
- 11000:6379
steps:
- name: Checkout frappe
uses: actions/checkout@v4
with:
repository: frappe/frappe
path: frappe-bench/apps/frappe
- name: Checkout app
uses: actions/checkout@v4
with:
path: frappe-bench/apps/myapp
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install bench
run: pip install frappe-bench
- name: Init bench
working-directory: frappe-bench
run: |
bench init --skip-assets --skip-redis-config-generation .
bench set-config -g db_root_password db_root
bench set-config -g redis_cache redis://localhost:13000
bench set-config -g redis_queue redis://localhost:11000
- name: Install app
working-directory: frappe-bench
run: |
bench get-app --skip-assets myapp ./apps/myapp
bench setup requirements --dev
bench new-site test_site \
--db-root-password db_root \
--admin-password admin \
--no-mariadb-socket
bench --site test_site install-app myapp
bench build --apps myapp
- name: Run tests
working-directory: frappe-bench
run: bench --site test_site run-tests --app myapp --failfast
- name: Upload coverage
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-${{ matrix.python-version }}-${{ matrix.db }}
path: frappe-bench/sites/coverage.xml
PostgreSQL のサポート(追加のマトリックスエントリー)
strategy:
matrix:
include:
- python-version: "3.12"
db: "postgres"
services:
postgres:
image: postgres:16
ports:
- 5432:5432
env:
POSTGRES_PASSWORD: db_root
options: >-
--health-cmd pg_isready
--health-interval=10s
--health-timeout=5s
--health-retries=5
PostgreSQL を使用する場合は、bench new-site コマンドを変更します:
bench new-site test_site \
--db-type postgres \
--db-root-password db_root \
--admin-password admin
Pre-Commit の設定
Frappe アプリ向けの最小限の .pre-commit-config.yaml
exclude: "node_modules|.git"
default_stages: [pre-commit]
fail_fast: false
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: trailing-whitespace
files: "myapp.*"
exclude: ".*json$|.*txt$|.*csv$|.*md$|.*svg$"
- id: check-merge-conflict
- id: check-ast
- id: check-json
- id: check-toml
- id: check-yaml
- id: debug-statements
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.0
hooks:
- id: ruff
args: [--select=I, --fix]
name: ruff (import sorter)
- id: ruff
name: ruff (linter)
- id: ruff-format
name: ruff (formatter)
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.7.1
hooks:
- id: prettier
types_or: [javascript, vue, scss]
exclude: ".*dist.*|node_modules"
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v8.44.0
hooks:
- id: eslint
types: [javascript]
args: [--quiet]
exclude: ".*dist.*|node_modules"
- repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
rev: v9.16.0
hooks:
- id: commitlint
stages: [commit-msg]
additional_dependencies:
- conventional-changelog-conventionalcommits
クローンした後は、必ず pre-commit install --hook-type pre-commit --hook-type commit-msg を実行してください。
Ruff の設定(pyproject.toml)
[tool.ruff]
line-length = 110
target-version = "py311"
[tool.ruff.lint]
select = [
"F", # Pyflakes
"E", # pycodestyle errors
"W", # pycodestyle warnings
"I", # isort
"UP", # pyupgrade
"B", # flake8-bugbear
"RUF", # Ruff-specific rules
]
ignore = [
"E501", # line too long (handled by formatter)
"F401", # unused import (common in __init__.py)
"F403", # wildcard import (Frappe convention)
"F405", # undefined from wildcard (Frappe convention)
"E402", # module-level import order (Frappe convention)
]
[tool.ruff.format]
quote-style = "double"
indent-style = "tab"
docstring-code-format = true
[tool.ruff.lint.per-file-ignores]
# Ignore in auto-generated boilerplate
"**/doctype/**/boilerplate/**" = ["ALL"]
ルール:
- Frappe プロジェクトでは、必ず
indent-style = "tab"を使用してください。これはフレームワークの規約です。 - 必ず F401/F403/F405 を無視してください。Frappe では規約としてワイルドカードインポートを使用します。
line-lengthは絶対に 110 未満に設定しないでください。Frappe の標準は 110 文字です。
ESLint の設定
{
"env": {
"browser": true,
"node": true,
"es2021": true
},
"extends": "eslint:recommended",
"globals": {
"frappe": "readonly",
"cur_frm": "readonly",
"__": "readonly",
"cur_dialog": "readonly",
"cur_page": "readonly",
"cur_list": "readonly"
},
"rules": {
"no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
"no-console": "warn"
}
}
Frappe のグローバル変数(frappe、cur_frm、__ など)は必ず宣言してください。宣言しないと、ESLint が誤検出を報告します。
Semgrep セキュリティルール
# .semgrep/frappe-security.yml
rules:
- id: frappe-sql-injection
pattern: frappe.db.sql($X.format(...))
message: "NEVER use .format() in SQL — use parameterized queries"
severity: ERROR
languages: [python]
- id: frappe-raw-sql-concat
pattern: frappe.db.sql($X + ...)
message: "NEVER concatenate strings in SQL — use parameterized queries"
severity: ERROR
languages: [python]
- id: frappe-eval-usage
pattern: eval(...)
message: "NEVER use eval() — use frappe.safe_eval() instead"
severity: ERROR
languages: [python]
CI に追加します:
- name: Run Semgrep
uses: returntocorp/semgrep-action@v1
with:
config: .semgrep/
テストカバレッジ
coverage.py のセットアップ
# .coveragerc
[run]
source = myapp
omit =
*/test_*.py
*/tests/*
*/setup.py
[report]
exclude_lines =
pragma: no cover
if frappe.flags.in_test:
if TYPE_CHECKING:
CI のカバレッジステップ
- name: Run tests with coverage
working-directory: frappe-bench
run: |
cd apps/myapp
coverage run -m pytest
coverage xml -o ../../sites/coverage.xml
- name: Upload to Codecov
uses: codecov/codecov-action@v4
with:
file: frappe-bench/sites/coverage.xml
token: ${{ secrets.CODECOV_TOKEN }}
リリースワークフロー
name: Release
on:
push:
tags:
- "v*"
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate changelog
id: changelog
uses: mikepenz/release-changelog-builder-action@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
body: ${{ steps.changelog.outputs.changelog }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ブランチ保護ルール
main と develop には、必ず次のブランチ保護ルールを設定してください:
- ステータスチェックを必須にする:マージ前にサーバーテストが成功していること
- プルリクエストレビューを必須にする:少なくとも 1 件の承認を得ること
- ブランチを最新の状態に保つことを必須にする:マージ前にリベースを強制すること
- 直線的な履歴を必須にする:スカッシュまたはリベースによるマージを強制すること
GitHub CLI で設定します:
gh api repos/{owner}/{repo}/branches/main/protection -X PUT \
-f "required_status_checks[strict]=true" \
-f "required_status_checks[contexts][]=Server Tests" \
-f "required_pull_request_reviews[required_approving_review_count]=1"
よくある CI の失敗と修正方法
| 失敗 | 原因 | 修正方法 |
|---|---|---|
MariaDB not ready | ヘルスチェックの時間が短すぎる | --health-retries を 10 以上に増やす |
Redis connection refused | ポートマッピングが正しくない | ポートマッピングが bench set-config と一致していることを確認する |
ModuleNotFoundError | アプリがインストールされていない | bench get-app と bench install-app の両方が実行されることを確認する |
Site not found | bench new-site が実行されていない | テスト実行前に必ずサイトを作成する |
Permission denied on bench | pip のインストール先 | sudo を使わずに pip install frappe-bench を使用する |
Assets build failed | Node のバージョンが一致していない | Node 18 または 20 を使用する(Node 16 は絶対に使用しない) |
frappe.exceptions.DoesNotExistError | テストフィクスチャが不足している | 依存する DocType 用の test_records.json が存在することを確認する |
Timeout in parallel tests | 並列ビルドが多すぎる | --total-builds を減らすか、timeout-minutes を増やす |
関連項目
- references/examples.md — ワークフローの完全な例
- references/anti-patterns.md — 避けるべき CI/CD の誤り
- references/github-actions.md — GitHub Actions の完全なリファレンス
- references/linting.md — リンティングとフォーマットの詳細
- frappe-testing-unit — ユニットテストと統合テスト
コメント
Markdown 対応