Skip to content

Commit 30b0321

Browse files
authored
Merge pull request #21 from PacktPublishing/pipeline-checks
setup pipeline checks
2 parents 22d9e7d + a543de9 commit 30b0321

12 files changed

Lines changed: 135 additions & 15 deletions

File tree

.github/workflows/ci.yaml

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
name: CI Pipeline
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
detect-projects:
11+
runs-on: ubuntu-latest
12+
outputs:
13+
matrix: ${{ steps.set-matrix.outputs.matrix }}
14+
steps:
15+
- uses: actions/checkout@v4
16+
17+
- name: Find Python projects
18+
id: set-matrix
19+
run: |
20+
# Find all directories containing both pyproject.toml and uv.lock
21+
projects=$(find . -name "pyproject.toml" -exec dirname {} \; | while read dir; do
22+
if [ -f "$dir/uv.lock" ]; then
23+
echo "$dir"
24+
fi
25+
done | sed 's|^\./||' | sed 's/.*/"&"/' | paste -sd, - | sed 's/^/[/;s/$/]/')
26+
echo "matrix={\"project\":$projects}" >> $GITHUB_OUTPUT
27+
echo "Found projects: $projects"
28+
echo "Full matrix output: {\"project\":$projects}"
29+
30+
lint-and-test:
31+
needs: detect-projects
32+
if: ${{ needs.detect-projects.outputs.matrix != '{"project":[]}' }}
33+
runs-on: ubuntu-latest
34+
strategy:
35+
fail-fast: false
36+
matrix: ${{ fromJson(needs.detect-projects.outputs.matrix) }}
37+
38+
defaults:
39+
run:
40+
working-directory: ${{ matrix.project }}
41+
42+
steps:
43+
- uses: actions/checkout@v4
44+
45+
- name: Extract Python version from pyproject.toml
46+
id: python-version
47+
run: |
48+
# Extract minimum Python version from requires-python
49+
version=$(grep -oP 'requires-python\s*=\s*">=\K[0-9]+\.[0-9]+' pyproject.toml || echo "3.12")
50+
echo "version=$version" >> $GITHUB_OUTPUT
51+
echo "Using Python $version for ${{ matrix.project }}"
52+
53+
- name: Install uv
54+
uses: astral-sh/setup-uv@v7
55+
56+
- name: Set up Python
57+
run: uv python install ${{ steps.python-version.outputs.version }}
58+
59+
- name: Install dependencies
60+
run: uv sync --frozen
61+
62+
- name: Install pre-commit
63+
run: uv tool install pre-commit
64+
65+
- name: Run pre-commit hooks
66+
env:
67+
SKIP: ruff,ty
68+
run: |
69+
# Run pre-commit hooks only on files in this project (skip ruff/ty, we run them separately)
70+
find . -type f \( -name "*.py" -o -name "*.toml" -o -name "*.yaml" -o -name "*.yml" -o -name "*.json" -o -name "*.md" \) -not -path "./.venv/*" | xargs uv tool run pre-commit run --config ${{ github.workspace }}/.pre-commit-config.yaml --files || true
71+
72+
- name: Run ruff linter
73+
run: uv run ruff check . --select "I,E,F,Q,UP,FAST" --line-length 120
74+
75+
- name: Run type checker
76+
run: uv run ty check || true
77+
78+
- name: Run pytest
79+
run: |
80+
# Check if tests directory or test files exist
81+
if [ -d "tests" ] || find . -name "test_*.py" -o -name "*_test.py" | grep -q .; then
82+
uv run pytest -v
83+
else
84+
echo "No tests found in ${{ matrix.project }}"
85+
fi

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,4 +213,4 @@ marimo/_lsp/
213213
__marimo__/
214214

215215
# Streamlit
216-
.streamlit/secrets.toml
216+
.streamlit/secrets.toml

.pre-commit-config.yaml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
repos:
2+
- repo: https://github.com/pre-commit/pre-commit-hooks
3+
rev: v4.4.0
4+
hooks:
5+
- id: check-added-large-files
6+
args: ['--maxkb=600']
7+
- id: check-docstring-first
8+
- id: check-merge-conflict
9+
- id: check-symlinks
10+
- id: check-toml
11+
- id: check-yaml
12+
args: [ --unsafe ]
13+
- id: detect-private-key
14+
- id: end-of-file-fixer
15+
- id: requirements-txt-fixer
16+
17+
- repo: local
18+
hooks:
19+
- id: ruff
20+
name: ruff (local)
21+
entry: uv run ruff check --fix --select "I,E,F,Q,UP,FAST"
22+
language: system
23+
types: [python]
24+
25+
- id: ty
26+
name: ty (local)
27+
entry: uv run ty check
28+
language: system
29+
types: [python]
30+
args: []

Chapter01/platform-home/.pre-commit-config.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ repos:
3232
entry: uv run ruff check --fix
3333
language: system
3434
types: [python]
35-
- id: mypy
36-
name: mypy (local)
37-
entry: uv run mypy
35+
- id: ty
36+
name: ty (local)
37+
entry: uv run ty check
3838
language: system
3939
types: [python]
4040
args: []

Chapter01/platform-home/pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ dev = [
1313
"pre-commit>=4.2.0",
1414
"pytest>=8.4.1",
1515
"ruff>=0.12.8",
16-
"ty>=0.0.8",
16+
"ty>=0.0.8"
1717
]
1818

1919
[tool.ruff]
2020
line-length = 61
2121

2222
[tool.ruff.lint]
23-
select = ["I", "E4", "E7", "F", "Q"]
23+
select = ["I", "E4", "E7", "F", "Q", "UP", "FAST"]

Chapter02/parents-portal/app/home.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
COOKIE_EXPIRATION_TIME = 60
1313

1414

15-
cookies_store = TTLCache( # type: ignore[var-annotated]
15+
cookies_store = TTLCache(
1616
maxsize=100,
1717
ttl=COOKIE_EXPIRATION_TIME,
1818
timer=lambda: time.monotonic(),
@@ -32,7 +32,7 @@ class Lang(StrEnum):
3232
async def home(
3333
request: Request,
3434
lang: Lang,
35-
name: str = Query(default=""),
35+
name: str = Query(default=""), # noqa: FAST002
3636
):
3737
request_cookie = request.cookies.get("TRACKING")
3838
cookie_content = cookies_store.get(request_cookie, "Invalid")

Chapter02/parents-portal/pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ profile = "jinja"
1919
line-length = 66
2020

2121
[tool.ruff.lint]
22-
select = ["I", "E4", "E7", "E9", "F", "Q"]
22+
select = ["I", "E", "F", "Q", "UP", "FAST"]
23+
24+
[tool.ruff.lint.pycodestyle]
25+
max-line-length=120
2326

2427
[dependency-groups]
2528
dev = [

Chapter02/parents-portal/tests/conftest.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
@pytest.fixture(scope="module")
88
def test_client():
9-
"""Create a TestClient for the app, shared across all tests in the module."""
109
return TestClient(app)
1110

1211

Chapter02/parents-portal/tests/test_cookies.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def test_home_with_cookie_expired(test_client):
2828

2929
# Advance time by expiration + 1 second so the cookie expires
3030
with freeze_time(
31-
datetime.datetime.now(datetime.timezone.utc)
31+
datetime.datetime.now(datetime.UTC)
3232
+ datetime.timedelta(seconds=COOKIE_EXPIRATION_TIME + 1)
3333
):
3434
response = test_client.get("/home")

Chapter03/reservation-service/presentation/api/routes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,10 @@ async def create_availability_slot(
9090
)
9191
async def list_available_slots(
9292
request: Request,
93-
week_day: WeekDaySchema | None = Query(
93+
week_day: WeekDaySchema | None = Query( # noqa: FAST002
9494
None, description="Filter by day of the week"
9595
),
96-
time_slot: TimeSlotSchema | None = Query(
96+
time_slot: TimeSlotSchema | None = Query( # noqa: FAST002
9797
None, description="Filter by time slot"
9898
),
9999
) -> list[SlotResponseSchema]:

0 commit comments

Comments
 (0)