From 20b53367e407b6e3a4fd93617e6e87b6297a27eb Mon Sep 17 00:00:00 2001 From: Jens Steenmetz Date: Sun, 22 Mar 2026 17:10:44 +0100 Subject: [PATCH 1/4] chore: do tutorial steps --- .github/workflows/markdown2pdf.yml | 2 +- .idea/.gitignore | 10 +++++++ .idea/fastapi-gitops.iml | 18 ++++++++++++ .../inspectionProfiles/profiles_settings.xml | 6 ++++ .idea/misc.xml | 4 +++ .idea/modules.xml | 8 ++++++ .idea/vcs.xml | 6 ++++ README.md | 28 +++++++++---------- 8 files changed, 67 insertions(+), 15 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/fastapi-gitops.iml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml diff --git a/.github/workflows/markdown2pdf.yml b/.github/workflows/markdown2pdf.yml index fcb4671..4177b58 100644 --- a/.github/workflows/markdown2pdf.yml +++ b/.github/workflows/markdown2pdf.yml @@ -19,7 +19,7 @@ jobs: - name: Replace links run: | - cp README.md README_WITH_LINKS.md + cp README.md README_WITH_LINKS.md sed -i -e "s#\(^\!\[[^]]\+\](\)\(images/\)#\1$URL/\2#g" README_WITH_LINKS.md for file in sources/*; do sed -i -e "s#($file)#($URL/$file)#g" README_WITH_LINKS.md ; done diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..ab1f416 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/fastapi-gitops.iml b/.idea/fastapi-gitops.iml new file mode 100644 index 0000000..55a63f1 --- /dev/null +++ b/.idea/fastapi-gitops.iml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..c979cdb --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..f954136 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 79bb814..057f54d 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ GitOps with FastAPI ***University of Amsterdam*** -# 1. Introduction +# 1. Introduction In this tutorial, we use GitOps practices with FastAPI, including CI/CD pipelines, code quality tools, and automated testing. @@ -35,7 +35,7 @@ In this tutorial, we use GitOps practices with FastAPI, including CI/CD pipeline -# 2. Tutorial +# 2. Tutorial The steps of this tutorial are as follows: - [Building REST APIs with FastAPI](#21-setting-up-the-project) @@ -60,17 +60,17 @@ Prerequisites: ``` * Set Up the Python Environmentt: - + ```bash # Create a virtual environment python -m venv venv - + # Activate the virtual environment # On Linux/MacOS: source venv/bin/activate # On Windows: venv\Scripts\activate - + # Install dependencies pip install -r requirements.txt ``` @@ -110,7 +110,7 @@ Prerequisites: ```bash # Check for issues ruff check app/ tests/ - + # Fix auto-fixable issues ruff check app/ tests/ --fix ``` @@ -120,7 +120,7 @@ Prerequisites: ```bash # Check formatting black --check app/ tests/ - + # Format code black app/ tests/ ``` @@ -134,7 +134,7 @@ Pre-commit hooks automatically run checks before each commit to ensure consisten ```bash # Install pre-commit pip install pre-commit - + # Install the git hooks pre-commit install ``` @@ -142,11 +142,11 @@ Pre-commit hooks automatically run checks before each commit to ensure consisten * Using Pre-commit: Pre-commit will now run automatically on `git commit`. You can also run it manually: - + ```bash # Run on all files pre-commit run --all-files - + # Run on staged files pre-commit run ``` @@ -200,14 +200,14 @@ This repository includes a Helm chart for deploying the application to Kubernete - Kubernetes 1.19+ - Helm 3.0+ -* Install the Helm Chart: +* Install the Helm Chart: ```bash helm install my-release ./helm/fastapi-gitops-starter ``` -* Uninstall the Helm Chart: - +* Uninstall the Helm Chart: + ```bash helm uninstall my-release ``` @@ -239,7 +239,7 @@ including host and paths. * To make sure we do not commit secrets * To check code style - + ## 3.2 Add a New Endpoint 1. Open `app/main.py` From 9fea951c99d03dd9510df254e2fe5b4a5f3b295d Mon Sep 17 00:00:00 2001 From: Jens Steenmetz Date: Sun, 22 Mar 2026 17:13:28 +0100 Subject: [PATCH 2/4] feat: add precommit hooks --- .idea/misc.xml | 3 +++ .pre-commit-config.yaml | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/.idea/misc.xml b/.idea/misc.xml index c979cdb..2ecead1 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,7 @@ + + \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d337d10..d9f0989 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,3 +3,28 @@ repos: rev: v5.0.0 hooks: - id: trailing-whitespace + - id: check-added-large-files + - id: check-yaml + exclude: ^helm/ + + - repo: https://github.com/pycqa/isort + rev: 5.13.2 + hooks: + - id: isort + + - repo: https://github.com/PyCQA/bandit + rev: 1.7.8 + hooks: + - id: bandit + args: ["-r", "app"] + + - repo: https://github.com/Yelp/detect-secrets + rev: v1.5.0 + hooks: + - id: detect-secrets + + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.11.0 + hooks: + - id: ruff + - id: ruff-format \ No newline at end of file From 1ff8124cde0c841ffb8d6ebdb7b8605dbcb76ca2 Mon Sep 17 00:00:00 2001 From: Jens Steenmetz Date: Sun, 22 Mar 2026 17:36:08 +0100 Subject: [PATCH 3/4] fix: update bandit pre-commit --- .pre-commit-config.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d9f0989..6753910 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,7 +16,8 @@ repos: rev: 1.7.8 hooks: - id: bandit - args: ["-r", "app"] + pass_filenames: false + args: ["-r", "app", "-x", "tests"] - repo: https://github.com/Yelp/detect-secrets rev: v1.5.0 From b89fb68fefe303b911ef268b5a37a4d5d5133abd Mon Sep 17 00:00:00 2001 From: Jens Steenmetz Date: Sun, 22 Mar 2026 17:38:13 +0100 Subject: [PATCH 4/4] feat: add ci pipeline --- .github/workflows/ci-cd.yml | 31 +++++++++++++++++++++++++++++++ app/main.py | 8 +++++++- tests/test_main.py | 14 ++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index a98b15e..631ba94 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -19,6 +19,12 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Install dependencies + run: pip install -r requirements.txt + + - name: Lint with Ruff + run: ruff check app tests + test: name: Run Tests runs-on: ubuntu-latest @@ -28,6 +34,12 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Install dependencies + run: pip install -r requirements.txt + + - name: Run tests with coverage + run: pytest --cov=app --cov-report=term --cov-fail-under=80 + build: name: Build Docker Image runs-on: ubuntu-latest @@ -40,3 +52,22 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + + - name: Build Docker image + run: docker build -t fastapi-gitops-starter . + + - name: Log in to GitHub Container Registry + if: github.event_name == 'release' + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin + + - name: Tag Docker image + if: github.event_name == 'release' + run: | + docker tag fastapi-gitops-starter ghcr.io/${{ github.repository }}:${{ github.event.release.tag_name }} + docker tag fastapi-gitops-starter ghcr.io/${{ github.repository }}:latest + + - name: Push Docker image + if: github.event_name == 'release' + run: | + docker push ghcr.io/${{ github.repository }}:${{ github.event.release.tag_name }} + docker push ghcr.io/${{ github.repository }}:latest \ No newline at end of file diff --git a/app/main.py b/app/main.py index ae8adc6..de09c12 100644 --- a/app/main.py +++ b/app/main.py @@ -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="0.0.0.0", port=8000) # nosec B104 diff --git a/tests/test_main.py b/tests/test_main.py index db89e2f..c179e26 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -41,3 +41,17 @@ 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": "Test Item", "description": "Created from test"} + ) + + assert response.status_code == 200 + data = response.json() + assert data["id"] == 999 + assert data["name"] == "Test Item" + assert data["description"] == "Created from test" + assert data["created"] is True