Skip to content

Infrastructure setup: CI/CD Integration, CLI tools, containerization, and more. #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Apr 23, 2024
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
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# byte-compiled / optimized / DLL files
__pycache__/

67 changes: 67 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: CI

on:
push:
branches: [ main ]
paths-ignore:
- '.github/**'

jobs:
build-push:
runs-on: ubuntu-latest
environment: production
permissions:
contents: read
steps:
- name: Checkout code.
uses: actions/checkout@v4

- name: Setup QEMU.
uses: docker/setup-qemu-action@v3

- name: Setup docker buildx.
uses: docker/setup-buildx-action@v3

- name: Login to container registry.
uses: docker/login-action@v3
with:
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}

- name: Build and push docker image.
uses: docker/build-push-action@v5
with:
push: true
tags: mangohabanero/be:latest, mangohabanero/be:${{ github.sha }}


release:
runs-on: ubuntu-latest
needs: build-push
environment: production
permissions:
contents: write
id-token: write
steps:
- name: Checkout code.
uses: actions/checkout@v4

- name: Set up python.
uses: actions/setup-python@v5
with:
python-version: '3.12.3'

- name: Install poetry.
run: |
curl -sSL https://install.python-poetry.org | python3 -
echo 'export PATH="$HOME/.local/bin:$PATH"' >> $GITHUB_ENV

- name: Install dependencies.
run: |
poetry config virtualenvs.create false
poetry install

- name: Python semantic release.
uses: python-semantic-release/python-semantic-release@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
15 changes: 15 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: check-toml
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.1
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix, --show-fixes]
- id: ruff-format
45 changes: 45 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
FROM python:3.12.3-slim AS base

# set the working directory.
WORKDIR /usr/src/

# add image metadata.
LABEL maintainer="Mango Habanero <main@mango-habanero.dev>"
LABEL description="Base image for portfolio backend."
LABEL repository="https://github.com/PhilipWafula/mango-habanero-be"
LABEL homepage="https://mango-habanero.dev"
ARG SOURCE_COMMIT
LABEL revision=${SOURCE_COMMIT:-unknown}

# create a group and user.
RUN addgroup --system app && adduser --system --group app

# set environment variables.
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
POETRY_VIRTUALENVS_CREATE=false \
PATH="/root/.local/bin:$PATH"

# install system dependencies.
RUN apt-get update && apt-get install -y --no-install-recommends curl \
&& apt clean

# install poetry.
RUN curl -sSL https://install.python-poetry.org | python3 -

# copy dependecy files.
COPY pyproject.toml poetry.lock ./

# copy the project (done before install to ensure console scripts are available).
COPY ./app /usr/src/app

RUN poetry install --no-ansi --no-dev --no-interaction

# grant permissions.
RUN chown -R app:app /usr/src/

# set the entrypoint.
EXPOSE 8000

# run the application.
CMD ["mhcli", "server", "start", "app.main:app", "--host=0.0.0.0", "--port=8000"]
1 change: 1 addition & 0 deletions app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = "0.0.1"
42 changes: 42 additions & 0 deletions app/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import click
import uvicorn


@click.group()
def mh_cli():
"""MangoHabanero CLI."""
pass


@mh_cli.group("server")
def mh_server():
"""Commands for managing the server."""
pass


@mh_server.command("develop")
@click.option(
"--log-level",
type=click.Choice(["debug", "info", "warning", "error", "critical"]),
default="debug",
help="Set the log level.",
)
def run_server(log_level: str):
"""Start the development server."""
uvicorn.run("app.main:app", reload=True, log_level=log_level)


mh_server.add_command(uvicorn.main, name="start")


def entrypoint():
from app.exceptions import MangoHabaneroException

try:
mh_cli()
except MangoHabaneroException as e:
click.secho(f"ERROR: {e}", bold=True, fg="red")


if __name__ == "__main__":
entrypoint()
2 changes: 2 additions & 0 deletions app/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class MangoHabaneroException(Exception):
pass
File renamed without changes.
9 changes: 9 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
version: "3.8"

services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "127.0.0.1:8000:8000"
Loading