-
Notifications
You must be signed in to change notification settings - Fork 0
151 lines (142 loc) · 4.71 KB
/
ci.yml
File metadata and controls
151 lines (142 loc) · 4.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
packages: write
pull-requests: read
jobs:
# Detect whether the change touches any code-relevant path.
# Docs-only changes (README, *.md, *.csv, docs/**) skip heavy work
# while every required check name still reports success — this avoids
# the paths-ignore + required-status-checks deadlock that previously
# blocked docs-only PRs.
changes:
runs-on: ubuntu-latest
outputs:
code: ${{ steps.filter.outputs.code }}
steps:
- uses: actions/checkout@v6
- uses: dorny/paths-filter@v4
id: filter
with:
filters: |
code:
- 'app/**'
- 'tests/**'
- 'scripts/**'
- 'requirements*.txt'
- 'requirements.lock'
- 'pyproject.toml'
- 'Dockerfile'
- 'Makefile'
- '.github/workflows/**'
lint:
needs: changes
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- if: needs.changes.outputs.code == 'true'
uses: actions/setup-python@v6
with:
python-version: "3.12"
- if: needs.changes.outputs.code == 'true'
run: pip install ruff
- if: needs.changes.outputs.code == 'true'
run: ruff check app/ scripts/
- if: needs.changes.outputs.code == 'true'
run: ruff format --check app/ scripts/
- if: needs.changes.outputs.code != 'true'
run: echo "Docs-only change — skipping lint."
import-check:
needs: changes
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- if: needs.changes.outputs.code == 'true'
uses: actions/setup-python@v6
with:
python-version: "3.12"
- if: needs.changes.outputs.code == 'true'
run: pip install -r requirements.txt
- if: needs.changes.outputs.code == 'true'
run: python -c "from app.main import app; print('imports OK')"
- if: needs.changes.outputs.code != 'true'
run: echo "Docs-only change — skipping import-check."
security:
needs: changes
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- if: needs.changes.outputs.code == 'true'
uses: actions/setup-python@v6
with:
python-version: "3.12"
- if: needs.changes.outputs.code == 'true'
run: pip install -r requirements.txt
- if: needs.changes.outputs.code == 'true'
name: Dependency audit
run: pip install pip-audit && pip-audit -r requirements.lock
- if: needs.changes.outputs.code == 'true'
name: Static security analysis
run: pip install bandit && bandit -r app/ -c pyproject.toml
- if: needs.changes.outputs.code != 'true'
run: echo "Docs-only change — skipping security."
test:
needs: changes
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- if: needs.changes.outputs.code == 'true'
uses: actions/setup-python@v6
with:
python-version: "3.12"
- if: needs.changes.outputs.code == 'true'
run: pip install -r requirements-dev.txt
- if: needs.changes.outputs.code == 'true'
run: pytest tests/ -v
- if: needs.changes.outputs.code != 'true'
run: echo "Docs-only change — skipping tests."
docker:
needs: changes
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- if: needs.changes.outputs.code == 'true'
name: Build image
run: docker build -t postalcode2nuts .
- if: needs.changes.outputs.code == 'true'
name: Verify non-root user
run: |
user=$(docker run --rm postalcode2nuts whoami)
echo "Container user: $user"
[ "$user" = "appuser" ] || exit 1
- if: needs.changes.outputs.code != 'true'
run: echo "Docs-only change — skipping docker build."
publish:
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.changes.outputs.code == 'true'
needs: [changes, lint, import-check, test, security, docker]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/metadata-action@v6
id: meta
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=raw,value=latest
type=sha
- uses: docker/build-push-action@v7
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}