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
43 changes: 43 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Ruff lint
run: ruff check app/ tests/

test:
name: Run Tests
Expand All @@ -27,6 +37,16 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run tests with coverage
run: pytest --cov=app --cov-report=term-missing --cov-fail-under=80

build:
name: Build Docker Image
Expand All @@ -40,3 +60,26 @@ 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: Build image (push)
if: github.event_name == 'push'
run: |
IMAGE=ghcr.io/${{ github.repository }}
TAG=${{ github.sha }}
docker build -f docker/Dockerfile -t $IMAGE:$TAG .
docker push $IMAGE:$TAG
- name: Build image (release)
if: github.event_name == 'release'
run: |
IMAGE=ghcr.io/${{ github.repository }}
VERSION=${{ github.ref_name }}
docker build -f docker/Dockerfile -t $IMAGE:$VERSION -t $IMAGE:latest .
docker push $IMAGE:$VERSION
docker push $IMAGE:latest
32 changes: 32 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,35 @@ repos:
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-added-large-files
args: ["--maxkb=500"]
- id: check-yaml
exclude: ^helm/fastapi-gitops-starter/templates/

- repo: https://github.com/PyCQA/isort
rev: 5.13.2
hooks:
- id: isort

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.4
hooks:
- id: ruff
args: ["--fix"]

- repo: https://github.com/psf/black
rev: 24.10.0
hooks:
- id: black

- repo: https://github.com/PyCQA/bandit
rev: 1.7.10
hooks:
- id: bandit
args: ["-q", "-r", "app", "tests"]

- repo: https://github.com/Yelp/detect-secrets
rev: v1.5.0
hooks:
- id: detect-secrets
25 changes: 25 additions & 0 deletions app/main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
from datetime import datetime, timezone

import uvicorn
from fastapi import FastAPI
Expand All @@ -11,6 +12,8 @@
root_path=os.getenv("ROOT_PATH", "/GitOps-Starter"),
)

STARTED_AT = datetime.now(timezone.utc)


@app.get("/")
async def root():
Expand All @@ -27,6 +30,17 @@ async def health_check():
)


@app.get("/info")
async def service_info():
"""Service metadata endpoint."""
return {
"service": "fastapi-gitops-starter",
"version": app.version,
"started_at": STARTED_AT.isoformat(),
"root_path": app.root_path,
}


@app.get("/api/items")
async def list_items():
"""Example endpoint to list items."""
Expand All @@ -39,6 +53,17 @@ async def list_items():
}


@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,
}


@app.get("/api/items/{item_id}")
async def get_item(item_id: int):
"""Example endpoint to get a specific item by ID."""
Expand Down
24 changes: 24 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,27 @@ 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",
params={"name": "New Item", "description": "Created item"},
)
assert response.status_code == 200
data = response.json()
assert data["id"] == 999
assert data["name"] == "New Item"
assert data["description"] == "Created item"
assert data["created"] is True

def test_service_info():
"""Test the service info endpoint."""
response = client.get("/info")
assert response.status_code == 200
data = response.json()
assert data["service"] == "fastapi-gitops-starter"
assert data["version"] == "1.0.0"
assert data["root_path"] == "/GitOps-Starter"
assert "T" in data["started_at"]