Skip to content

Commit 0d8007a

Browse files
feat: add CI/CD pipeline and update module imports
- Introduced a comprehensive CI/CD pipeline in `.github/workflows/ci.yml` for testing, linting, type checking, documentation building, and security scanning. - Updated import statements in `risk_control/decision/__init__.py` to use relative imports. - Removed obsolete test file `tests/test_ex.py` and added a new import validation test suite in `tests/test_imports.py`.
1 parent a05a754 commit 0d8007a

4 files changed

Lines changed: 288 additions & 13 deletions

File tree

.github/workflows/ci.yml

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
name: CI/CD Pipeline
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
release:
9+
types: [published]
10+
release:
11+
types: [published]
12+
13+
env:
14+
UV_VERSION: "0.8.13"
15+
16+
jobs:
17+
lint:
18+
name: Lint and Format
19+
runs-on: ubuntu-latest
20+
21+
steps:
22+
- name: Checkout code
23+
uses: actions/checkout@v4
24+
25+
- name: Set up Python 3.13
26+
uses: actions/setup-python@v5
27+
with:
28+
python-version: "3.13"
29+
30+
- name: Install uv
31+
uses: astral-sh/setup-uv@v6
32+
with:
33+
version: ${{ env.UV_VERSION }}
34+
35+
- name: Cache dependencies
36+
uses: actions/cache@v4
37+
with:
38+
path: .venv
39+
key: ${{ runner.os }}-venv-${{ hashFiles('**/pyproject.toml') }}
40+
restore-keys: |
41+
${{ runner.os }}-venv-
42+
43+
- name: Install dependencies
44+
run: |
45+
uv sync --group dev
46+
47+
- name: Run linting
48+
run: |
49+
uv run make lint
50+
51+
- name: Check code formatting
52+
run: |
53+
uv run make format
54+
55+
- name: Run pre-commit hooks
56+
run: |
57+
uv run make pre-commit
58+
59+
type-check:
60+
name: Type Checking
61+
runs-on: ubuntu-latest
62+
63+
steps:
64+
- name: Checkout code
65+
uses: actions/checkout@v4
66+
67+
- name: Set up Python 3.13
68+
uses: actions/setup-python@v5
69+
with:
70+
python-version: "3.13"
71+
72+
- name: Install uv
73+
uses: astral-sh/setup-uv@v6
74+
with:
75+
version: ${{ env.UV_VERSION }}
76+
77+
- name: Cache dependencies
78+
uses: actions/cache@v4
79+
with:
80+
path: .venv
81+
key: ${{ runner.os }}-venv-${{ hashFiles('**/pyproject.toml') }}
82+
restore-keys: |
83+
${{ runner.os }}-venv-
84+
85+
- name: Install dependencies
86+
run: |
87+
uv sync --group dev
88+
89+
- name: Run type checking
90+
run: |
91+
uv run make type-check
92+
93+
test:
94+
name: Tests
95+
runs-on: ${{ matrix.os }}
96+
needs: [lint, type-check]
97+
strategy:
98+
matrix:
99+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
100+
os: [ubuntu-latest, macos-latest]
101+
102+
steps:
103+
- name: Checkout code
104+
uses: actions/checkout@v4
105+
106+
- name: Set up Python ${{ matrix.python-version }}
107+
uses: actions/setup-python@v5
108+
with:
109+
python-version: ${{ matrix.python-version }}
110+
python-version: ${{ matrix.python-version }}
111+
112+
- name: Install uv
113+
uses: astral-sh/setup-uv@v6
114+
with:
115+
version: ${{ env.UV_VERSION }}
116+
117+
- name: Cache dependencies
118+
uses: actions/cache@v4
119+
with:
120+
path: .venv
121+
key: ${{ runner.os }}-${{ matrix.python-version }}-venv-${{ hashFiles('**/pyproject.toml') }}
122+
key: ${{ runner.os }}-${{ matrix.python-version }}-venv-${{ hashFiles('**/pyproject.toml') }}
123+
restore-keys: |
124+
${{ runner.os }}-${{ matrix.python-version }}-venv-
125+
${{ runner.os }}-${{ matrix.python-version }}-venv-
126+
127+
- name: Install dependencies
128+
run: |
129+
uv sync --group dev
130+
131+
- name: Run tests with coverage
132+
run: |
133+
uv run make tests
134+
uv sync --group dev
135+
136+
- name: Run tests with coverage
137+
run: |
138+
uv run make tests
139+
140+
- name: Generate coverage report
141+
- name: Generate coverage report
142+
run: |
143+
uv run make report-tests
144+
uv run make report-tests
145+
146+
- name: Upload coverage to Codecov
147+
uses: codecov/codecov-action@v3
148+
- name: Upload coverage to Codecov
149+
uses: codecov/codecov-action@v3
150+
with:
151+
file: ./coverage.xml
152+
flags: unittests
153+
name: codecov-umbrella
154+
fail_ci_if_error: false
155+
file: ./coverage.xml
156+
flags: unittests
157+
name: codecov-umbrella
158+
fail_ci_if_error: false
159+
160+
security:
161+
name: Security Scan
162+
runs-on: ubuntu-latest
163+
needs: test
164+
165+
steps:
166+
- name: Checkout code
167+
uses: actions/checkout@v4
168+
169+
- name: Set up Python 3.13
170+
uses: actions/setup-python@v5
171+
with:
172+
python-version: "3.13"
173+
174+
- name: Install uv
175+
uses: astral-sh/setup-uv@v6
176+
with:
177+
version: ${{ env.UV_VERSION }}
178+
179+
- name: Cache dependencies
180+
uses: actions/cache@v4
181+
with:
182+
path: .venv
183+
key: ${{ runner.os }}-venv-${{ hashFiles('**/pyproject.toml') }}
184+
restore-keys: |
185+
${{ runner.os }}-venv-
186+
187+
- name: Install dependencies
188+
run: |
189+
uv sync --group dev
190+
191+
- name: Run security scan with bandit
192+
run: |
193+
uv run pip install bandit
194+
uv run bandit -r risk_control/ -f json -o bandit-report.json || true
195+
196+
- name: Upload security scan results
197+
uses: actions/upload-artifact@v4
198+
with:
199+
name: security-scan-results
200+
path: bandit-report.json
201+
202+
docs:
203+
name: Build Documentation
204+
runs-on: ubuntu-latest
205+
needs: [test, security]
206+
if: github.event_name == 'release'
207+
208+
steps:
209+
- name: Checkout code
210+
uses: actions/checkout@v4
211+
212+
- name: Set up Python 3.13
213+
uses: actions/setup-python@v5
214+
with:
215+
python-version: "3.13"
216+
217+
- name: Install uv
218+
uses: astral-sh/setup-uv@v6
219+
with:
220+
version: ${{ env.UV_VERSION }}
221+
222+
- name: Cache dependencies
223+
uses: actions/cache@v4
224+
with:
225+
path: .venv
226+
key: ${{ runner.os }}-venv-${{ hashFiles('**/pyproject.toml') }}
227+
restore-keys: |
228+
${{ runner.os }}-venv-
229+
230+
- name: Install dependencies
231+
run: |
232+
uv sync --group dev --group docs
233+
234+
- name: Build documentation
235+
run: |
236+
uv run make docs
237+
238+
- name: Deploy to GitHub Pages
239+
uses: peaceiris/actions-gh-pages@v3
240+
with:
241+
github_token: ${{ secrets.GITHUB_TOKEN }}
242+
publish_dir: ./site

risk_control/decision/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
from risk_control.decision.base import BaseDecision
2-
from risk_control.decision.classification import BaseClassificationDecision
3-
from risk_control.decision.decision import (
1+
from .base import BaseDecision
2+
from .classification import BaseClassificationDecision
3+
from .decision import (
44
BestClassDecision,
55
MultiLabelDecision,
66
SelectiveClassification,
77
SelectiveRegression,
88
)
9-
from risk_control.decision.regression import (
9+
from .regression import (
1010
AdvancedRegressionDecision,
1111
BaseRegressionDecision,
1212
)

tests/test_ex.py

Lines changed: 0 additions & 9 deletions
This file was deleted.

tests/test_imports.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import os
2+
import sys
3+
import unittest
4+
5+
# Add the project root to the path to allow direct imports
6+
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
7+
8+
9+
class TestModuleImports(unittest.TestCase):
10+
"""Test cases for importing risk_control modules."""
11+
12+
def test_parameter_module(self) -> None:
13+
"""Test the parameter module directly."""
14+
# Let's check what's available in parameter module
15+
import risk_control.parameter
16+
17+
self.assertIsNotNone(risk_control.parameter)
18+
19+
def test_abstention_module(self) -> None:
20+
"""Test the abstention module directly."""
21+
# Let's check what's available in abstention module
22+
import risk_control.abstention
23+
24+
self.assertIsNotNone(risk_control.abstention)
25+
26+
def test_plot_module(self) -> None:
27+
"""Test the plot module directly."""
28+
# Let's check what's available in plot module
29+
import risk_control.plot
30+
31+
self.assertIsNotNone(risk_control.plot)
32+
33+
def test_risk_module(self) -> None:
34+
"""Test the risk module directly."""
35+
# Let's check what's available in risk module
36+
import risk_control.risk
37+
38+
self.assertIsNotNone(risk_control.risk)
39+
40+
41+
if __name__ == "__main__":
42+
unittest.main()

0 commit comments

Comments
 (0)