Skip to content
Merged
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
54 changes: 54 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
name: CI/CD Pipeline

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

on:
release:
types: [ published ]
Expand All @@ -19,6 +23,20 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4

- &install-python
name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.13'

- &install-packages
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
runs-on: ubuntu-latest
Expand All @@ -28,6 +46,12 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4

- *install-python
- *install-packages

- name: Execute tests
run: pytest --cov=app --cov-report=html --cov-fail-under=80

build:
name: Build Docker Image
runs-on: ubuntu-latest
Expand All @@ -40,3 +64,33 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Docker build
if: github.event_name == 'push'
run: docker build -t fastapi-gitops-starter .

# Documentation: https://docs.github.com/en/actions/tutorials/publish-packages/publish-docker-images#publishing-images-to-github-packages
- name: Log in to the Container registry
if: github.event_name == 'release'
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
if: github.event_name == 'release'
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

- name: Build and push Docker image
if: github.event_name == 'release'
id: push
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
38 changes: 38 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,43 @@
# Used https://pre-commit.com/hooks.html
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
# To prevent committing large files
- id: check-added-large-files

# To check YAML files for syntax errors (excluding Helm charts)
- id: check-yaml
exclude: ^helm/

# To check code style
- id: trailing-whitespace
- id: end-of-file-fixer

# To check for security issues
- id: detect-private-key

# To sort imports in Python files
- repo: https://github.com/pycqa/isort
rev: 8.0.0
hooks:
- id: isort

# To check for security issues
- repo: https://github.com/PyCQA/bandit
rev: 1.9.3
hooks:
- id: bandit
exclude: ^tests/

# To check code style
- repo: https://github.com/psf/black
rev: 26.1.0
hooks:
- id: black

# To make sure we do not commit secrets
- repo: https://github.com/Yelp/detect-secrets
rev: v1.5.0
hooks:
- id: detect-secrets
8 changes: 7 additions & 1 deletion app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,11 @@ 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)
uvicorn.run(app, host="127.0.0.1", port=8000)
16 changes: 16 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,19 @@ 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."""
name = "Basketball"
description = "A round object"

response = client.post(
"/api/items", params={"name": name, "description": description}
)
assert response.status_code == 200
data = response.json()
assert data["id"] == 999
assert data["name"] == name
assert data["description"] == description
assert data["created"]
Loading