swadhinbiswas

[email protected]
2026-07-28 14:23:03 +0600 committed NaN years ago
d3841fa
commit d3841fa
2 files changed
+265 -114
▼.github/workflows/ci.yml
+199-36
2
2
3
3
on:
4
4
push:
5
- branches: [main]
5
+ branches: [main, initial-setup]
6
6
tags: ["v*"]
7
7
pull_request:
8
8
branches: [main]
12
12
RUSTFLAGS: "-D warnings"
13
13
14
14
jobs:
15
+ # ============================================================
16
+ # Stage 1: Code Quality & Build
17
+ # ============================================================
18
+
15
19
check:
16
20
name: Build & Lint
17
21
runs-on: ubuntu-latest
51
55
- name: Test
52
56
run: cargo test --workspace --all-features
53
57
58
+ # ============================================================
59
+ # Stage 2: Memory Safety & Security
60
+ # ============================================================
61
+
54
62
miri:
55
- name: Miri (justapi-core)
63
+ name: Miri (Memory Safety)
56
64
runs-on: ubuntu-latest
57
65
steps:
58
66
- uses: actions/checkout@v4
77
85
run: cargo +nightly miri test -p justapi-core
78
86
env:
79
87
MIRIFLAGS: "-Zmiri-disable-isolation"
88
+
89
+ audit:
90
+ name: Security Audit
91
+ runs-on: ubuntu-latest
92
+ steps:
93
+ - uses: actions/checkout@v4
94
+
95
+ - name: Install cargo-audit
96
+ run: cargo install cargo-audit --locked
97
+
98
+ - name: Cache cargo registry
99
+ uses: actions/cache@v4
100
+ with:
101
+ path: |
102
+ ~/.cargo/registry
103
+ ~/.cargo/git
104
+ key: ${{ runner.os }}-audit-${{ hashFiles('**/Cargo.lock') }}
105
+
106
+ - name: Run audit
107
+ run: cargo audit
108
+
109
+ deny:
110
+ name: License & Dependency Check
111
+ runs-on: ubuntu-latest
112
+ steps:
113
+ - uses: actions/checkout@v4
114
+
115
+ - name: Install cargo-deny
116
+ uses: EmbarkStudios/cargo-deny-action@v2
117
+ with:
118
+ command: check
119
+ arguments: --all-features
120
+
121
+ # ============================================================
122
+ # Stage 3: Python Integration Tests
123
+ # ============================================================
124
+
80
125
pytest:
81
- name: Pytest (justapi-py)
126
+ name: Pytest (Python Integration)
82
127
runs-on: ubuntu-latest
83
128
steps:
84
129
- uses: actions/checkout@v4
97
142
98
143
- name: Run pytest
99
144
run: |
100
- uv run -- PYTHONPATH=./crates/justapi-py/python pytest
145
+ uv run -- PYTHONPATH=./crates/justapi-py/python pytest -v
101
146
102
147
pytest-freethreaded:
103
- name: Pytest (free-threaded / no GIL)
148
+ name: Pytest (Free-threaded Python)
104
149
runs-on: ubuntu-latest
105
150
steps:
106
151
- uses: actions/checkout@v4
124
169
- name: Run pytest with the GIL disabled
125
170
run: |
126
171
. .venv-ft/bin/activate
127
- PYTHON_GIL=0 PYTHONPATH=./crates/justapi-py/python pytest
172
+ PYTHON_GIL=0 PYTHONPATH=./crates/justapi-py/python pytest -v
173
+
174
+ # ============================================================
175
+ # Stage 4: Integration Tests
176
+ # ============================================================
177
+
178
+ integration-tests:
179
+ name: Integration Tests
180
+ runs-on: ubuntu-latest
181
+ needs: [check, pytest]
182
+ steps:
183
+ - uses: actions/checkout@v4
184
+
185
+ - name: Install Rust toolchain
186
+ uses: dtolnay/rust-toolchain@stable
187
+
188
+ - name: Install Python (for PyO3)
189
+ uses: actions/setup-python@v5
190
+ with:
191
+ python-version: "3.12"
192
+
193
+ - name: Install uv
194
+ uses: astral-sh/setup-uv@v5
195
+
196
+ - name: Cache cargo registry
197
+ uses: actions/cache@v4
198
+ with:
199
+ path: |
200
+ ~/.cargo/registry
201
+ ~/.cargo/git
202
+ target
203
+ key: ${{ runner.os }}-integration-${{ hashFiles('**/Cargo.lock') }}
204
+ restore-keys: |
205
+ ${{ runner.os }}-integration-
206
+
207
+ - name: Build justapi
208
+ run: cargo build --release -p justapi-cli --features tls,compression
209
+
210
+ - name: Build Python wheel
211
+ run: maturin build -m crates/justapi-py/Cargo.toml --release -o wheels/
212
+
213
+ - name: Install wheel
214
+ run: pip install wheels/*.whl --break-system-packages
215
+
216
+ - name: Start server
217
+ run: |
218
+ justapi serve --addr 127.0.0.1:8080 &
219
+ sleep 3
220
+
221
+ - name: Health check
222
+ run: |
223
+ curl -f http://127.0.0.1:8080/health || exit 1
224
+ curl -f http://127.0.0.1:8080/live || exit 1
225
+ curl -f http://127.0.0.1:8080/ready || exit 1
226
+
227
+ - name: Test endpoints
228
+ run: |
229
+ # Hello world
230
+ curl -f http://127.0.0.1:8080/ || exit 1
231
+
232
+ # Metrics
233
+ curl -f http://127.0.0.1:8080/metrics || exit 1
234
+
235
+ # OpenAPI
236
+ curl -f http://127.0.0.1:8080/openapi.json || exit 1
237
+
238
+ - name: Test WebSocket
239
+ run: |
240
+ # Install websocat
241
+ cargo install websocat
242
+
243
+ # Test WebSocket echo
244
+ echo "hello" | websocat -t ws://127.0.0.1:8080/ws || true
245
+
246
+ - name: Stop server
247
+ if: always()
248
+ run: pkill -f "justapi serve" || true
249
+
250
+ # ============================================================
251
+ # Stage 5: Code Quality Gates
252
+ # ============================================================
128
253
129
254
verify-rust-first:
130
- name: Verify Rust-first mandate (AGENTS.md §2)
255
+ name: Verify Rust-first Mandate
131
256
runs-on: ubuntu-latest
132
257
steps:
133
258
- uses: actions/checkout@v4
146
271
fi
147
272
echo "OK: no Python-side scheduling/thread-pool classes found."
148
273
149
- audit:
150
- name: Security Audit (cargo-audit)
151
- runs-on: ubuntu-latest
152
- steps:
153
- - uses: actions/checkout@v4
154
-
155
- - name: Install cargo-audit
156
- run: cargo install cargo-audit --locked
157
-
158
- - name: Cache cargo registry
159
- uses: actions/cache@v4
160
- with:
161
- path: |
162
- ~/.cargo/registry
163
- ~/.cargo/git
164
- key: ${{ runner.os }}-audit-${{ hashFiles('**/Cargo.lock') }}
165
-
166
- - name: Run audit
167
- run: cargo audit
168
-
169
- deny:
170
- name: License & Dependency Check (cargo-deny)
274
+ verify-no-unwrap-on-hot-path:
275
+ name: Verify No unwrap() on Hot Paths
171
276
runs-on: ubuntu-latest
172
277
steps:
173
278
- uses: actions/checkout@v4
279
+ - name: Check for unwrap() on hot paths
280
+ run: |
281
+ echo "Checking for unwrap() on request hot paths..."
282
+ # Check for unwrap() in handler dispatch code (excluding tests and init)
283
+ matches=$(grep -rn "\.unwrap()" crates/justapi-core/src/server/ \
284
+ --include="*.rs" \
285
+ | grep -v "test" \
286
+ | grep -v "expect" \
287
+ | grep -v "LazyLock" \
288
+ | grep -v "unwrap_or" \
289
+ | grep -v "unwrap_or_else" \
290
+ | grep -v "unwrap_or_default" \
291
+ || true)
292
+ if [ -n "$matches" ]; then
293
+ echo "::warning::Potential unwrap() on hot path:"
294
+ echo "$matches"
295
+ fi
296
+ echo "Check complete."
174
297
175
- - name: Install cargo-deny
176
- uses: EmbarkStudios/cargo-deny-action@v2
177
- with:
178
- command: check
179
- arguments: --all-features
298
+ # ============================================================
299
+ # Stage 6: Benchmark
300
+ # ============================================================
180
301
181
302
benchmark:
182
303
name: Benchmark Regression Gate
239
360
240
361
echo "Benchmark check passed"
241
362
363
+ # ============================================================
364
+ # Stage 7: Docker Build
365
+ # ============================================================
366
+
242
367
docker:
243
- name: Build & Push Docker Image
368
+ name: Build Docker Image
244
369
runs-on: ubuntu-latest
245
- needs: [check]
370
+ needs: [check, pytest, integration-tests]
246
371
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
247
372
steps:
248
373
- uses: actions/checkout@v4
277
402
labels: ${{ steps.meta.outputs.labels }}
278
403
cache-from: type=gha
279
404
cache-to: type=gha,mode=max
405
+
406
+ # ============================================================
407
+ # Stage 8: PyPI Publish (on release)
408
+ # ============================================================
409
+
410
+ pypi-publish:
411
+ name: Publish to PyPI
412
+ runs-on: ubuntu-latest
413
+ needs: [check, pytest, integration-tests, docker]
414
+ if: startsWith(github.ref, 'refs/tags/v')
415
+ environment: pypi
416
+ permissions:
417
+ id-token: write
418
+ steps:
419
+ - uses: actions/checkout@v4
420
+
421
+ - name: Install Rust toolchain
422
+ uses: dtolnay/rust-toolchain@stable
423
+
424
+ - name: Install Python (for PyO3)
425
+ uses: actions/setup-python@v5
426
+ with:
427
+ python-version: "3.12"
428
+
429
+ - name: Build wheel
430
+ run: |
431
+ pip install maturin
432
+ maturin build --release -m crates/justapi-py/Cargo.toml -o wheels/
433
+
434
+ - name: Verify wheel
435
+ run: |
436
+ pip install wheels/*.whl --break-system-packages
437
+ python -c "import justapi; print(f'JustAPI {justapi.__version__} installed successfully')"
438
+
439
+ - name: Publish to PyPI
440
+ uses: pypa/gh-action-pypi-publish@release/v1
441
+ with:
442
+ packages-dir: wheels/
280
443
▼.github/workflows/publish.yml
+66-78
4
4
release:
5
5
types: [published]
6
6
workflow_dispatch:
7
-
8
-permissions:
9
- contents: read
10
- id-token: write
7
+ inputs:
8
+ version:
9
+ description: 'Version to publish (e.g., 2.0.8)'
10
+ required: true
11
11
12
12
jobs:
13
- check-version:
14
- name: Check Version
13
+ build:
14
+ name: Build Wheel
15
15
runs-on: ubuntu-latest
16
- outputs:
17
- version: ${{ steps.version.outputs.version }}
18
16
steps:
19
17
- uses: actions/checkout@v4
20
- - id: version
21
- run: echo "version=$(grep '^version = ' crates/justapi-py/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')" >> "$GITHUB_OUTPUT"
22
18
23
- test-rust:
24
- name: Cargo Test & Lint
25
- runs-on: ubuntu-latest
26
- needs: check-version
27
- steps:
28
- - uses: actions/checkout@v4
29
- - uses: dtolnay/rust-toolchain@stable
30
- with:
31
- components: clippy, rustfmt
32
- - name: Install cargo-deny
33
- uses: taiki-e/install-action@v2
34
- with:
35
- tool: cargo-deny
36
- - name: Security & License Check
37
- run: cargo deny check
38
- - name: Run Tests
39
- run: cargo test --workspace
40
- - name: Clippy & Formatting
41
- run: |
42
- cargo clippy --workspace --tests -- -D warnings
43
- cargo fmt --check
19
+ - name: Install Rust toolchain
20
+ uses: dtolnay/rust-toolchain@stable
44
21
45
- build-wheels:
46
- name: Build (${{ matrix.target }})
47
- runs-on: ${{ matrix.os }}
48
- needs: test-rust
49
- strategy:
50
- fail-fast: false
51
- matrix:
52
- include:
53
- - os: ubuntu-latest
54
- target: x86_64
55
- args: --manylinux 2_28
56
- - os: ubuntu-latest
57
- target: aarch64
58
- args: --manylinux 2_28
59
- - os: macos-latest
60
- target: x86_64
61
- - os: macos-latest
62
- target: aarch64
63
- - os: windows-latest
64
- target: x64
65
- steps:
66
- - uses: actions/checkout@v4
67
- - uses: astral-sh/setup-uv@v5
22
+ - name: Install Python (for PyO3)
23
+ uses: actions/setup-python@v5
68
24
with:
69
- python-version: '3.12'
70
- enable-cache: true
71
- cache-dependency-glob: crates/justapi-py/pyproject.toml
72
- - uses: PyO3/maturin-action@v1
25
+ python-version: "3.12"
26
+
27
+ - name: Cache cargo registry
28
+ uses: actions/cache@v4
73
29
with:
74
- target: ${{ matrix.target }}
75
- args: --release --out dist ${{ matrix.args }}
76
- manifest-path: crates/justapi-py/Cargo.toml
77
- - name: Smoke test
78
- shell: bash
30
+ path: |
31
+ ~/.cargo/registry
32
+ ~/.cargo/git
33
+ target
34
+ key: ${{ runner.os }}-publish-${{ hashFiles('**/Cargo.lock') }}
35
+ restore-keys: |
36
+ ${{ runner.os }}-publish-
37
+
38
+ - name: Install maturin
39
+ run: pip install maturin
40
+
41
+ - name: Build wheel
42
+ run: maturin build --release -m crates/justapi-py/Cargo.toml -o wheels/
43
+
44
+ - name: Verify wheel
79
45
run: |
80
- uv pip install dist/*.whl
81
- python -c "import justapi; print(justapi.__version__)"
82
- - uses: actions/upload-artifact@v4
46
+ pip install wheels/*.whl --break-system-packages
47
+ python -c "import justapi; print(f'JustAPI installed successfully')"
48
+
49
+ - name: Upload wheel artifact
50
+ uses: actions/upload-artifact@v4
83
51
with:
84
- name: wheels-${{ matrix.target }}
85
- path: dist/*.whl
52
+ name: wheels
53
+ path: wheels/*.whl
86
54
87
- publish:
55
+ publish-pypi:
88
56
name: Publish to PyPI
89
57
runs-on: ubuntu-latest
90
- needs: build-wheels
58
+ needs: [build]
91
59
environment: pypi
92
60
permissions:
93
61
id-token: write
62
+ steps:
63
+ - name: Download wheel artifact
64
+ uses: actions/download-artifact@v4
65
+ with:
66
+ name: wheels
67
+ path: wheels/
68
+
69
+ - name: Publish to PyPI
70
+ uses: pypa/gh-action-pypi-publish@release/v1
71
+ with:
72
+ packages-dir: wheels/
73
+
74
+ create-github-release:
75
+ name: Create GitHub Release
76
+ runs-on: ubuntu-latest
77
+ needs: [publish-pypi]
78
+ permissions:
79
+ contents: write
94
80
steps:
95
81
- uses: actions/checkout@v4
96
- - uses: astral-sh/setup-uv@v5
82
+
83
+ - name: Download wheel artifact
84
+ uses: actions/download-artifact@v4
97
85
with:
98
- python-version: '3.12'
99
- - uses: actions/download-artifact@v4
86
+ name: wheels
87
+ path: wheels/
88
+
89
+ - name: Create GitHub Release
90
+ uses: softprops/action-gh-release@v2
100
91
with:
101
- pattern: wheels-*
102
- merge-multiple: true
103
- path: dist
104
- - name: Publish
105
- run: uv publish --package-dir crates/justapi-py --trusted-publishing always --verbose
92
+ files: wheels/*.whl
93
+ generate_release_notes: true
106
94