Skip to content

Commit d989c27

Browse files
thompsonsonclaude
andcommitted
feat: add comprehensive CI/CD automation and modern Python tooling
- Add pre-commit configuration with ruff (replaces black/isort/flake8), mypy, and bandit - Add GitHub Actions workflows for CI testing and automated HF Spaces deployment - Add pyproject.toml with modern Python packaging and centralized tool configuration - Update requirements.txt with development dependencies including ruff and pytest plugins - Add comprehensive ruff rule set: pycodestyle, pyflakes, bugbear, comprehensions, pyupgrade - Configure multi-Python version testing (3.10, 3.11, 3.12) with parallel execution - Add security scanning with bandit and Trivy vulnerability scanner - Update README with development workflow and CI/CD pipeline documentation Performance improvements: - Ruff provides 10-100x faster linting compared to traditional tools - pytest-xdist enables parallel test execution - Single tool replaces multiple separate linters 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent a6994a0 commit d989c27

File tree

6 files changed

+344
-1
lines changed

6 files changed

+344
-1
lines changed

.github/workflows/ci.yml

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
python-version: [3.10.x, 3.11.x, 3.12.x]
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- name: Set up Python ${{ matrix.python-version }}
20+
uses: actions/setup-python@v4
21+
with:
22+
python-version: ${{ matrix.python-version }}
23+
24+
- name: Cache pip packages
25+
uses: actions/cache@v3
26+
with:
27+
path: ~/.cache/pip
28+
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
29+
restore-keys: |
30+
${{ runner.os }}-pip-
31+
32+
- name: Install dependencies
33+
run: |
34+
python -m pip install --upgrade pip
35+
pip install -r requirements.txt
36+
pip install pytest-cov pytest-xdist
37+
38+
- name: Run tests with coverage
39+
run: |
40+
python -m pytest tests/ -v --cov=domains --cov=ui --cov-report=xml --cov-report=html -n auto
41+
42+
- name: Upload coverage to Codecov
43+
uses: codecov/codecov-action@v3
44+
with:
45+
file: ./coverage.xml
46+
flags: unittests
47+
name: codecov-umbrella
48+
49+
lint:
50+
runs-on: ubuntu-latest
51+
52+
steps:
53+
- uses: actions/checkout@v4
54+
55+
- name: Set up Python
56+
uses: actions/setup-python@v4
57+
with:
58+
python-version: 3.11.x
59+
60+
- name: Install dependencies
61+
run: |
62+
python -m pip install --upgrade pip
63+
pip install ruff mypy bandit
64+
65+
- name: Run Ruff linter
66+
run: ruff check .
67+
68+
- name: Run Ruff formatter
69+
run: ruff format --check .
70+
71+
- name: Run mypy
72+
run: mypy . --ignore-missing-imports
73+
74+
- name: Run bandit
75+
run: bandit -r . -f json -o bandit-report.json || true
76+
77+
pre-commit:
78+
runs-on: ubuntu-latest
79+
80+
steps:
81+
- uses: actions/checkout@v4
82+
83+
- name: Set up Python
84+
uses: actions/setup-python@v4
85+
with:
86+
python-version: 3.11.x
87+
88+
- name: Install pre-commit
89+
run: pip install pre-commit
90+
91+
- name: Run pre-commit
92+
run: pre-commit run --all-files
93+
94+
security:
95+
runs-on: ubuntu-latest
96+
97+
steps:
98+
- uses: actions/checkout@v4
99+
100+
- name: Run Trivy vulnerability scanner
101+
uses: aquasecurity/trivy-action@master
102+
with:
103+
scan-type: 'fs'
104+
scan-ref: '.'
105+
format: 'sarif'
106+
output: 'trivy-results.sarif'
107+
108+
- name: Upload Trivy scan results to GitHub Security tab
109+
uses: github/codeql-action/upload-sarif@v2
110+
if: always()
111+
with:
112+
sarif_file: 'trivy-results.sarif'

.github/workflows/deploy.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Deploy to Hugging Face Spaces
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
workflow_dispatch:
7+
8+
jobs:
9+
deploy:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- uses: actions/checkout@v4
14+
with:
15+
fetch-depth: 0
16+
lfs: true
17+
18+
- name: Push to Hugging Face Spaces
19+
env:
20+
HF_TOKEN: ${{ secrets.HF_TOKEN }}
21+
run: |
22+
git config --global user.email "[email protected]"
23+
git config --global user.name "GitHub Action"
24+
git remote add hf https://thompsonson:[email protected]/spaces/thompsonson/bayesian_game
25+
git push hf main --force

.pre-commit-config.yaml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
repos:
2+
- repo: https://github.com/pre-commit/pre-commit-hooks
3+
rev: v4.4.0
4+
hooks:
5+
- id: trailing-whitespace
6+
- id: end-of-file-fixer
7+
- id: check-yaml
8+
- id: check-added-large-files
9+
- id: check-merge-conflict
10+
- id: debug-statements
11+
12+
- repo: https://github.com/astral-sh/ruff-pre-commit
13+
rev: v0.1.9
14+
hooks:
15+
- id: ruff
16+
args: [--fix, --exit-non-zero-on-fix]
17+
- id: ruff-format
18+
19+
- repo: https://github.com/pre-commit/mirrors-mypy
20+
rev: v1.8.0
21+
hooks:
22+
- id: mypy
23+
additional_dependencies: [types-all]
24+
args: [--ignore-missing-imports]
25+
26+
- repo: https://github.com/pycqa/bandit
27+
rev: 1.7.5
28+
hooks:
29+
- id: bandit
30+
args: [-r, ., -f, json, -o, bandit-report.json]
31+
exclude: ^tests/

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ uv pip install -r requirements.txt
8585
pip install -r requirements.txt
8686
```
8787

88+
4. **Set up pre-commit hooks (optional for development):**
89+
```bash
90+
pre-commit install
91+
```
92+
8893
### Running the Game
8994

9095
**Launch the interactive web interface:**
@@ -210,6 +215,32 @@ This implementation demonstrates:
210215
- `numpy`: Numerical computations for Bayesian inference
211216
- `matplotlib`: Belief distribution visualization
212217
- `pytest`: Testing framework
218+
- `pre-commit`: Code quality automation
219+
- `ruff`: Fast Python linter and formatter (replaces Black, isort, flake8)
220+
221+
### Development Workflow
222+
```bash
223+
# Install pre-commit hooks
224+
pre-commit install
225+
226+
# Run pre-commit manually
227+
pre-commit run --all-files
228+
229+
# Run tests with coverage
230+
python -m pytest tests/ --cov=domains --cov=ui --cov-report=html
231+
232+
# Code formatting and linting (automatic with pre-commit)
233+
ruff check --fix .
234+
ruff format .
235+
mypy .
236+
```
237+
238+
### CI/CD Pipeline
239+
- **GitHub Actions**: Automated testing on Python 3.10, 3.11, 3.12
240+
- **Pre-commit hooks**: Code quality checks (Ruff, mypy, bandit)
241+
- **Test coverage**: Comprehensive coverage reporting
242+
- **Security scanning**: Trivy vulnerability scanner
243+
- **Auto-deployment**: Pushes to Hugging Face Spaces on main branch
213244

214245
### Design Principles
215246
1. **Pure Functions**: Domains contain pure, testable functions

pyproject.toml

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
[build-system]
2+
requires = ["setuptools>=45", "wheel", "setuptools_scm[toml]>=6.2"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "bayesian-game"
7+
description = "Interactive Bayesian inference game with domain-driven design"
8+
readme = "README.md"
9+
license = {text = "MIT"}
10+
authors = [
11+
{name = "Thompson", email = "[email protected]"},
12+
]
13+
classifiers = [
14+
"Development Status :: 4 - Beta",
15+
"Intended Audience :: Education",
16+
"License :: OSI Approved :: MIT License",
17+
"Programming Language :: Python :: 3",
18+
"Programming Language :: Python :: 3.10",
19+
"Programming Language :: Python :: 3.11",
20+
"Programming Language :: Python :: 3.12",
21+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
22+
"Topic :: Education",
23+
]
24+
requires-python = ">=3.10"
25+
dependencies = [
26+
"gradio>=4.0.0",
27+
"numpy>=1.21.0",
28+
"matplotlib>=3.5.0",
29+
]
30+
dynamic = ["version"]
31+
32+
[project.optional-dependencies]
33+
dev = [
34+
"pytest>=7.0.0",
35+
"pytest-cov>=4.0.0",
36+
"pytest-xdist>=3.0.0",
37+
"pre-commit>=3.0.0",
38+
"ruff>=0.1.0",
39+
"mypy>=1.0.0",
40+
"bandit>=1.7.0",
41+
]
42+
43+
[project.urls]
44+
Homepage = "https://github.com/thompsonson/bayesian_game"
45+
Repository = "https://github.com/thompsonson/bayesian_game"
46+
"Bug Tracker" = "https://github.com/thompsonson/bayesian_game/issues"
47+
"Hugging Face Space" = "https://huggingface.co/spaces/thompsonson/bayesian_game"
48+
49+
[tool.setuptools_scm]
50+
51+
[tool.ruff]
52+
target-version = "py310"
53+
line-length = 88
54+
select = [
55+
"E", # pycodestyle errors
56+
"W", # pycodestyle warnings
57+
"F", # pyflakes
58+
"I", # isort
59+
"B", # flake8-bugbear
60+
"C4", # flake8-comprehensions
61+
"UP", # pyupgrade
62+
"ARG", # flake8-unused-arguments
63+
"SIM", # flake8-simplify
64+
"TCH", # flake8-type-checking
65+
"PTH", # flake8-use-pathlib
66+
"ERA", # eradicate
67+
"PL", # pylint
68+
"RUF", # ruff-specific rules
69+
]
70+
ignore = [
71+
"E501", # line too long, handled by formatter
72+
"B008", # do not perform function calls in argument defaults
73+
"C901", # too complex
74+
"PLR0913", # too many arguments
75+
"PLR0915", # too many statements
76+
]
77+
78+
[tool.ruff.per-file-ignores]
79+
"tests/**/*" = ["PLR2004", "S101", "ARG001"]
80+
81+
[tool.ruff.format]
82+
quote-style = "double"
83+
indent-style = "space"
84+
skip-magic-trailing-comma = false
85+
line-ending = "auto"
86+
87+
[tool.mypy]
88+
python_version = "3.10"
89+
check_untyped_defs = true
90+
disallow_any_generics = true
91+
disallow_incomplete_defs = true
92+
disallow_untyped_defs = true
93+
no_implicit_optional = true
94+
warn_redundant_casts = true
95+
warn_unused_ignores = true
96+
warn_return_any = true
97+
strict_equality = true
98+
99+
[[tool.mypy.overrides]]
100+
module = [
101+
"matplotlib.*",
102+
"gradio.*",
103+
]
104+
ignore_missing_imports = true
105+
106+
[tool.pytest.ini_options]
107+
minversion = "7.0"
108+
addopts = "-ra -q --strict-markers --strict-config"
109+
testpaths = ["tests"]
110+
python_files = ["test_*.py"]
111+
python_classes = ["Test*"]
112+
python_functions = ["test_*"]
113+
markers = [
114+
"slow: marks tests as slow",
115+
"integration: marks tests as integration tests",
116+
"unit: marks tests as unit tests",
117+
]
118+
119+
[tool.coverage.run]
120+
source = ["domains", "ui"]
121+
omit = [
122+
"tests/*",
123+
"app.py",
124+
]
125+
126+
[tool.coverage.report]
127+
exclude_lines = [
128+
"pragma: no cover",
129+
"def __repr__",
130+
"raise AssertionError",
131+
"raise NotImplementedError",
132+
"if __name__ == .__main__.:",
133+
"if TYPE_CHECKING:",
134+
]
135+
136+
[tool.bandit]
137+
exclude_dirs = ["tests"]
138+
skips = ["B101", "B601"]

requirements.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
gradio>=4.0.0
22
numpy>=1.21.0
33
matplotlib>=3.5.0
4-
pytest>=7.0.0
4+
pytest>=7.0.0
5+
pytest-cov>=4.0.0
6+
pytest-xdist>=3.0.0
7+
pre-commit>=3.0.0
8+
ruff>=0.1.0
9+
mypy>=1.0.0
10+
bandit>=1.7.0

0 commit comments

Comments
 (0)