Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install dependencies
run: pip install ruff
- name: Lint with Ruff
run: ruff check .

test:
name: Run Tests
Expand All @@ -27,6 +35,22 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run tests with coverage
run: pytest --cov=app --cov-report=term-missing --cov-report=xml
- name: Check coverage threshold
run: |
COVERAGE=$(python -c "import xml.etree.ElementTree as ET; tree = ET.parse('coverage.xml'); root = tree.getroot(); print(f\"{float(root.get('line-rate')) * 100:.2f}\")")
echo "Coverage: $COVERAGE%"
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
echo "Coverage is below 80% threshold"
exit 1
fi

build:
name: Build Docker Image
Expand All @@ -40,3 +64,29 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract version and tags
id: meta
run: |
if [[ "${{ github.event_name }}" == "release" ]]; then
VERSION=${{ github.ref_name }}
TAGS="ghcr.io/${{ github.repository }}:${VERSION},ghcr.io/${{ github.repository }}:latest"
else
TAGS="ghcr.io/${{ github.repository }}:${{ github.sha }}"
fi
echo "tags=${TAGS}" >> $GITHUB_OUTPUT
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max
30 changes: 30 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,33 @@ repos:
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: check-added-large-files
args: ['--maxkb=1000']
- id: check-yaml
exclude: helm/
- id: check-merge-conflict
- id: detect-private-key
- repo: https://github.com/PyCQA/isort
rev: 5.13.2
hooks:
- id: isort
name: isort (sort imports)
- repo: https://github.com/PyCQA/bandit
rev: 1.7.5
hooks:
- id: bandit
name: bandit (security checks)
args: ['-c', '.bandit']
exclude: ^tests/
- repo: https://github.com/PyCQA/pylint
rev: pylint-3.0.3
hooks:
- id: pylint
name: pylint (code style)
additional_dependencies: ['pylint']
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
name: detect-secrets
args: ['--baseline', '.secrets.baseline']
File renamed without changes.
11 changes: 11 additions & 0 deletions app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,16 @@ async def get_item(item_id: int):
}


@app.post("/api/items")
async def create_item(name: str, description: str):
"""Create a new item."""
return {
"id": 999,
"name": name,
"description": description,
"created": True
}


if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
11 changes: 11 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,14 @@ def test_get_item():
assert data["id"] == 5
assert data["name"] == "Item 5"
assert "item number 5" in data["description"]


def test_create_item():
"""Test the create item endpoint."""
response = client.post("/api/items?name=New Item&description=A brand new item")
assert response.status_code == 200
data = response.json()
assert data["id"] == 999
assert data["name"] == "New Item"
assert data["description"] == "A brand new item"
assert data["created"] is True