From d64adbd3fdbb45fad01f6aa2127324d25061c448 Mon Sep 17 00:00:00 2001 From: Noah G Date: Thu, 5 Mar 2026 19:40:04 +0100 Subject: [PATCH 1/4] Add amazing feature --- docker/Dockerfile => Dockerfile | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docker/Dockerfile => Dockerfile (100%) diff --git a/docker/Dockerfile b/Dockerfile similarity index 100% rename from docker/Dockerfile rename to Dockerfile From d7e7d1c0171a47d17cf32973f57cabff7db9da8b Mon Sep 17 00:00:00 2001 From: Noah G Date: Thu, 5 Mar 2026 19:44:23 +0100 Subject: [PATCH 2/4] testing pre-commit --- .pre-commit-config.yaml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d337d10..792b9fd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -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'] From cedd022f4e9c0a587d444e69346e8f1b4691084a Mon Sep 17 00:00:00 2001 From: Noah G Date: Thu, 5 Mar 2026 19:49:26 +0100 Subject: [PATCH 3/4] added new endpoint with test --- app/main.py | 11 +++++++++++ tests/test_main.py | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/app/main.py b/app/main.py index ae8adc6..364bed9 100644 --- a/app/main.py +++ b/app/main.py @@ -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) diff --git a/tests/test_main.py b/tests/test_main.py index db89e2f..331eba3 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -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 From a383580a4ab3e47e80a1a2b760f40e048966093b Mon Sep 17 00:00:00 2001 From: Noah G Date: Thu, 5 Mar 2026 19:50:15 +0100 Subject: [PATCH 4/4] added ci pipeline --- .github/workflows/ci-cd.yml | 50 +++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index a98b15e..4943665 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -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 @@ -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 @@ -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