1- name : Code Quality CI
1+ name : CI
22
33" on " :
44 push :
55 branches : [main]
66 pull_request :
7- branches : [main ]
7+ branches : ['**' ]
88
99permissions :
1010 contents : read
11+ security-events : write
1112
1213jobs :
14+ # ============================================================================
15+ # LAYER 1: Fast feedback (runs first)
16+ # ============================================================================
17+
1318 pre-commit :
1419 name : Pre-commit hooks
1520 runs-on : ubuntu-latest
@@ -19,19 +24,213 @@ jobs:
1924 - name : Set up Python
2025 uses : actions/setup-python@v6
2126 with :
22- python-version : " 3.13 "
27+ python-version : " 3.12 "
2328
2429 - name : Cache pre-commit
2530 uses : actions/cache@v5
2631 with :
2732 path : ~/.cache/pre-commit
2833 key : pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
2934
30- - name : Install Python dependencies
35+ - name : Install pre-commit
3136 run : |
3237 python -m pip install --upgrade pip
3338 pip install pre-commit
34- pip install -e .[dev]
3539
3640 - name : Run pre-commit
3741 run : pre-commit run --all-files
42+
43+ lint-type-check :
44+ name : Lint & Type Check
45+ runs-on : ubuntu-latest
46+ steps :
47+ - uses : actions/checkout@v6
48+
49+ - name : Set up Python
50+ uses : actions/setup-python@v6
51+ with :
52+ python-version : " 3.12"
53+
54+ - name : Cache pip
55+ uses : actions/cache@v5
56+ with :
57+ path : ~/.cache/pip
58+ key : ${{ runner.os }}-lint-pip-${{ hashFiles('**/pyproject.toml') }}
59+ restore-keys : |
60+ ${{ runner.os }}-lint-pip-
61+
62+ - name : Install dependencies
63+ run : |
64+ python -m pip install --upgrade pip
65+ pip install -e .[dev]
66+
67+ - name : Run ruff
68+ run : ruff check src tests
69+
70+ - name : Run black
71+ run : black --check src tests
72+
73+ - name : Run mypy
74+ run : mypy src
75+
76+ # ============================================================================
77+ # LAYER 2: Tests (depends on Layer 1)
78+ # ============================================================================
79+
80+ test :
81+ name : Test (Python ${{ matrix.python-version }} / ${{ matrix.os }})
82+ needs : [pre-commit, lint-type-check]
83+ runs-on : ${{ matrix.os }}
84+ strategy :
85+ fail-fast : false
86+ matrix :
87+ os : [ubuntu-latest, macos-latest, windows-latest]
88+ python-version : ['3.10', '3.11', '3.12', '3.13']
89+
90+ steps :
91+ - uses : actions/checkout@v6
92+
93+ - name : Set up Python ${{ matrix.python-version }}
94+ uses : actions/setup-python@v6
95+ with :
96+ python-version : ${{ matrix.python-version }}
97+
98+ - name : Cache pip
99+ uses : actions/cache@v5
100+ with :
101+ path : ~/.cache/pip
102+ key : ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('**/pyproject.toml') }}
103+ restore-keys : |
104+ ${{ runner.os }}-pip-${{ matrix.python-version }}-
105+ ${{ runner.os }}-pip-
106+
107+ - name : Install dependencies
108+ run : |
109+ python -m pip install --upgrade pip
110+ pip install -e .[dev]
111+
112+ - name : Run tests with coverage
113+ run : |
114+ pytest tests/ -v \
115+ --cov=src/arbitrium \
116+ --cov-report=xml \
117+ --cov-report=term-missing \
118+ --cov-branch \
119+ --junitxml=test-results.xml
120+ env :
121+ SKIP_DB_INIT : " true"
122+
123+ - name : Enforce coverage threshold
124+ if : runner.os == 'Linux' && matrix.python-version == '3.12'
125+ run : coverage report --fail-under=40
126+
127+ - name : Upload coverage report
128+ if : runner.os == 'Linux' && matrix.python-version == '3.12'
129+ uses : actions/upload-artifact@v4
130+ with :
131+ name : coverage-report
132+ path : |
133+ coverage.xml
134+ test-results.xml
135+ retention-days : 1
136+
137+ # ============================================================================
138+ # LAYER 3: Quality analysis (parallel, non-blocking on main)
139+ # ============================================================================
140+
141+ mutation-testing :
142+ name : Mutation Testing
143+ if : github.event_name == 'push' && github.ref == 'refs/heads/main'
144+ runs-on : ubuntu-latest
145+ continue-on-error : true
146+ steps :
147+ - uses : actions/checkout@v6
148+
149+ - name : Set up Python
150+ uses : actions/setup-python@v6
151+ with :
152+ python-version : " 3.12"
153+
154+ - name : Install dependencies
155+ run : |
156+ python -m pip install --upgrade pip
157+ pip install -e .[dev]
158+
159+ - name : Run mutation testing
160+ run : |
161+ mutmut run . || true
162+ mutmut results || true
163+ env :
164+ SKIP_DB_INIT : " true"
165+
166+ complexity-checks :
167+ name : Complexity Analysis
168+ runs-on : ubuntu-latest
169+ steps :
170+ - uses : actions/checkout@v6
171+
172+ - name : Set up Python
173+ uses : actions/setup-python@v6
174+ with :
175+ python-version : " 3.12"
176+
177+ - name : Install radon
178+ run : pip install radon
179+
180+ - name : Check cyclomatic complexity
181+ run : |
182+ echo "=== Cyclomatic Complexity ==="
183+ radon cc src/arbitrium/ --min B --total-average
184+ radon cc src/arbitrium/ --min C --total-average || \
185+ (echo "::warning::High complexity detected (grade C or worse)" && exit 0)
186+
187+ - name : Check maintainability index
188+ run : |
189+ echo "=== Maintainability Index ==="
190+ radon mi src/arbitrium/ --min B
191+
192+ architecture-checks :
193+ name : Architecture Validation
194+ runs-on : ubuntu-latest
195+ continue-on-error : true
196+ steps :
197+ - uses : actions/checkout@v6
198+
199+ - name : Set up Python
200+ uses : actions/setup-python@v6
201+ with :
202+ python-version : " 3.12"
203+
204+ - name : Install import-linter
205+ run : pip install import-linter
206+
207+ - name : Create import contracts
208+ run : |
209+ cat > .importlinter <<EOF
210+ [importlinter]
211+ root_package = arbitrium
212+
213+ [importlinter:contract:1]
214+ name = CLI should not import core internals directly
215+ type = forbidden
216+ source_modules = arbitrium.cli
217+ forbidden_modules = arbitrium.core.tournament
218+
219+ [importlinter:contract:2]
220+ name = Models should not import CLI
221+ type = forbidden
222+ source_modules = arbitrium.models
223+ forbidden_modules = arbitrium.cli
224+
225+ [importlinter:contract:3]
226+ name = Utils should be independent
227+ type = independence
228+ modules =
229+ arbitrium.utils
230+ EOF
231+
232+ - name : Install package
233+ run : pip install -e .
234+
235+ - name : Validate architecture
236+ run : lint-imports || echo "::warning::Architecture violations detected"
0 commit comments