Skip to content
This repository was archived by the owner on Jan 1, 2026. It is now read-only.

Commit e0c86f9

Browse files
authored
Add unit tests and optimize workflows (#4)
* Remove draft release workflow and enhance Python package workflow with version extraction and release creation steps * Add test suites for `/orders` and `/products` endpoints and utility functions for versioned API requests * Remove obsolete GitHub workflows for Docker image verification, Python package building, and unit testing; introduce new workflows for packaging Docker images, building Python packages, and running unit tests. * Add missing YAML document separator to Docker image verification workflow * Fix YAML syntax by moving cron schedule under the correct key in Docker image verification workflow * Refactor version extraction and draft release creation in Python package workflow to use consistent version output * No code changes detected in the workflow for building the Python package. * Fix YAML formatting by removing extra space in cron schedule
1 parent 4ed03fb commit e0c86f9

9 files changed

Lines changed: 157 additions & 86 deletions

File tree

.github/workflows/docker-image.yml renamed to .github/workflows/package-docker-image.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
name: Build Docker Image
2+
name: Package Docker Image
33

44
permissions:
55
packages: write
Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
name: Create a Draft Release
2+
name: Build Python Package
33

44
permissions:
55
contents: write
@@ -15,7 +15,7 @@ env:
1515
FILE_FILTER_PATTERN: '^(?!tests/).*\.py$'
1616

1717
jobs:
18-
create-release-draft:
18+
release:
1919
runs-on: ubuntu-latest
2020

2121
steps:
@@ -55,22 +55,32 @@ jobs:
5555
echo "Failed to extract version from app/version.py"
5656
exit 1
5757
fi
58-
TAG="v$VERSION"
59-
echo "Version extracted: $TAG"
60-
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
58+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
59+
echo "tag=v$VERSION" >> "$GITHUB_OUTPUT"
6160
62-
- name: Create draft release
61+
- name: Set up Python
62+
uses: actions/setup-python@v5
63+
with:
64+
python-version: '3.12.10'
65+
66+
- name: Install build dependencies
67+
run: pip install --user build
68+
69+
- name: Set PYTHONPATH so setuptools can find version.py
70+
run: echo "PYTHONPATH=${{ github.workspace }}/app" >> "$GITHUB_ENV"
71+
72+
- name: Build the binary wheel and source tarball
73+
run: python -m build
74+
working-directory: ${{ github.workspace }}
75+
76+
- name: Create draft release and upload package
6377
if: steps.check_changes.outputs.should_trigger == 'true'
64-
run: |
65-
curl -X POST \
66-
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
67-
-H "Accept: application/vnd.github+json" \
68-
https://api.github.com/repos/${{ github.repository }}/releases \
69-
-d '{
70-
"tag_name": "${{ steps.version.outputs.tag }}",
71-
"target_commitish": "'"$TRIGGER_BRANCH"'",
72-
"name": "${{ steps.version.outputs.tag }}",
73-
"draft": true,
74-
"prerelease": false,
75-
"generate_release_notes": true
76-
}'
78+
uses: softprops/action-gh-release@v2
79+
with:
80+
tag_name: ${{ steps.version.outputs.tag }}
81+
draft: true
82+
generate_release_notes: true
83+
name: Version ${{ steps.version.outputs.version }}
84+
files: |
85+
dist/*.tar.gz
86+
dist/*.whl

.github/workflows/python-package.yml

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

.github/workflows/devcontainer-verification.yml renamed to .github/workflows/verify-docker-image.yml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
---
12
name: Scan Images
23

34
permissions:
@@ -9,22 +10,26 @@ on:
910
push:
1011
branches:
1112
- main
13+
schedule:
14+
- cron: '0 4 * * 1' # Every monday at 4:00 UTC
1215
pull_request: null
1316

1417
jobs:
1518
scan-images:
1619
name: Scan ${{ matrix.image_name }} Image
1720
uses: Vianpyro/Template/.github/workflows/docker-image-verification.yml@main
21+
1822
strategy:
1923
matrix:
2024
include:
21-
- image_name: devcontainer
25+
- image_name: DevContainer
2226
dockerfile_path: ./Dockerfile
2327
context: .devcontainer
2428

25-
- image_name: production
29+
- image_name: Production
2630
dockerfile_path: ./Dockerfile
2731
context: .
32+
2833
with:
2934
image_name: ${{ matrix.image_name }}
3035
dockerfile_path: ${{ matrix.dockerfile_path }}

.vscode/tasks.json

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,31 @@
11
{
22
"version": "2.0.0",
33
"tasks": [
4+
{
5+
"label": "Delete old Git branches",
6+
"type": "shell",
7+
"command": "git fetch --prune && git fetch -p ; git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -D",
8+
"problemMatcher": [],
9+
"presentation": {
10+
"showReuseMessage": false
11+
}
12+
},
13+
{
14+
"label": "Package app",
15+
"type": "shell",
16+
"command": "rm -rf build dist *.egg-info && python -m build",
17+
"problemMatcher": [],
18+
"runOptions": {
19+
"runOn": "default"
20+
},
21+
"presentation": {
22+
"panel": "dedicated"
23+
},
24+
"group": {
25+
"kind": "build",
26+
"isDefault": true
27+
}
28+
},
429
{
530
"label": "Run all tests",
631
"type": "shell",
@@ -35,22 +60,6 @@
3560
"panel": "dedicated",
3661
"close": true
3762
}
38-
},
39-
{
40-
"label": "Package app",
41-
"type": "shell",
42-
"command": "rm -rf build dist *.egg-info && python -m build",
43-
"problemMatcher": [],
44-
"runOptions": {
45-
"runOn": "default"
46-
},
47-
"presentation": {
48-
"panel": "dedicated"
49-
},
50-
"group": {
51-
"kind": "build",
52-
"isDefault": true
53-
}
5463
}
5564
]
5665
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"""
2+
Test suite for the v1 `/orders` endpoint of the ChocoMax API.
3+
4+
This module uses the `v1_get` utility to avoid repeating the API version path.
5+
"""
6+
7+
from fastapi.testclient import TestClient
8+
9+
from app.main import app
10+
from tests.utils.request import v1_get
11+
12+
client = TestClient(app)
13+
14+
15+
def test_orders():
16+
"""
17+
Test that the `/api/v1/orders` endpoint returns a 200 status
18+
and responds with a JSON list.
19+
"""
20+
response = v1_get(client, "/orders")
21+
assert response.status_code == 200
22+
assert isinstance(response.json(), list)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"""
2+
Test suite for the v1 `/products` endpoint of the ChocoMax API.
3+
4+
This module uses the `v1_get` utility to avoid repeating the API version path.
5+
"""
6+
7+
from fastapi.testclient import TestClient
8+
9+
from app.main import app
10+
from tests.utils.request import v1_get
11+
12+
client = TestClient(app)
13+
14+
15+
def test_products():
16+
"""
17+
Test that the `/api/v1/products` endpoint returns a 200 status
18+
and responds with a JSON list.
19+
"""
20+
response = v1_get(client, "/products")
21+
assert response.status_code == 200
22+
assert isinstance(response.json(), list)

tests/utils/request.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
"""
2+
Utility functions to simplify versioned API requests in tests.
3+
4+
These helpers reduce duplication of versioned API paths like `/api/v1/...`,
5+
improving readability and consistency in test files.
6+
"""
7+
8+
from fastapi.testclient import TestClient
9+
10+
11+
def api_get(client: TestClient, version: str, path: str) -> TestClient:
12+
"""
13+
Perform a GET request to a versioned API path.
14+
15+
Args:
16+
client (TestClient): FastAPI test client.
17+
version (str): API version, e.g., 'v1' or 'v2'.
18+
path (str): Path to append after the version, e.g., '/orders'.
19+
20+
Returns:
21+
Response: FastAPI test client response.
22+
"""
23+
return client.get(f"/api/{version}{path}")
24+
25+
26+
def v1_get(client: TestClient, path: str) -> TestClient:
27+
"""
28+
Perform a GET request to a v1 API endpoint.
29+
30+
Args:
31+
client (TestClient): FastAPI test client.
32+
path (str): Path to append after `/api/v1`.
33+
34+
Returns:
35+
Response: FastAPI test client response.
36+
"""
37+
return api_get(client, "v1", path)
38+
39+
40+
def v2_get(client: TestClient, path: str) -> TestClient:
41+
"""
42+
Perform a GET request to a v2 API endpoint.
43+
44+
Args:
45+
client (TestClient): FastAPI test client.
46+
path (str): Path to append after `/api/v2`.
47+
48+
Returns:
49+
Response: FastAPI test client response.
50+
"""
51+
return api_get(client, "v2", path)

0 commit comments

Comments
 (0)