Skip to content

Commit

Permalink
Init project
Browse files Browse the repository at this point in the history
  • Loading branch information
thyb-zytek committed Sep 15, 2024
1 parent f6472c7 commit 127bb6d
Show file tree
Hide file tree
Showing 38 changed files with 2,614 additions and 3 deletions.
17 changes: 17 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
PROJECT_NAME=Budgly
DESCRIPTION='Server API to track expenses and do some KPI'
VERSION=0.1.0
ENV=development

POSTGRES_HOST=db
POSTGRES_PASSWORD=root
POSTGRES_USER=budgly-db
POSTGRES_DB=core

ALLOWED_HOSTS="http://localhost http://localhost:8000"

FIREBASE_SA_KEYS_FILE=firebase_sa_keys.json
FIREBASE_APIKEY=API_KEY

GOOGLE_OAUTH_SECRET_FILE=google_oauth_secret.json
LOGFIRE_TOKEN=token
38 changes: 38 additions & 0 deletions .github/workflows/smokeshow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Smokeshow

on:
workflow_run:
workflows:
- Run Tests
types:
- completed

jobs:
smokeshow:
if: ${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
permissions:
actions: read
statuses: write

steps:
- uses: actions/setup-python@v5
with:
python-version: '3.9'

- run: pip install smokeshow

- uses: dawidd6/[email protected]
with:
workflow: tests.yml
commit: ${{ github.event.workflow_run.head_sha }}
github_token: ${{ secrets.GITHUB_TOKEN }}

- run: smokeshow upload coverage-html
env:
SMOKESHOW_GITHUB_STATUS_DESCRIPTION: Coverage {coverage-percentage}
SMOKESHOW_GITHUB_COVERAGE_THRESHOLD: 90
SMOKESHOW_GITHUB_CONTEXT: coverage
SMOKESHOW_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SMOKESHOW_GITHUB_PR_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
SMOKESHOW_AUTH_KEY: ${{ secrets.SMOKESHOW_AUTH_KEY }}
41 changes: 41 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Run Tests

on:
push:
branches:
- "master"
pull_request:
branches:
- "master"

jobs:
tests:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup env
run: |
docker compose build api db
docker compose up -d
- name: Run lints
run: ./scripts/lint.sh

- name: Run tests
run: |
docker compose exec api poetry run pytest --cov=.
docker compose exec api poetry run coverage report --show-missing --format=markdown >> $GITHUB_STEP_SUMMARY
docker compose exec api poetry run coverage html
docker compose exec api poetry run coverage report --fail-under=100
- name: Clean
run: docker compose down -v --remove-orphans

- name: Store coverage files
uses: actions/upload-artifact@v4
with:
name: coverage-html
path: app/htmlcov
retention-days: 5
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down Expand Up @@ -122,6 +123,7 @@ celerybeat.pid
# Environments
.env
.venv
.env.prod
env/
venv/
ENV/
Expand Down Expand Up @@ -157,4 +159,6 @@ cython_debug/
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
.idea/

app/firebase/
33 changes: 33 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: check-added-large-files
- id: check-toml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.9.0
hooks:
- id: mypy
exclude: "app/tests/factories|app/alembic"
args:
- --ignore-missing-imports
additional_dependencies:
- pydantic
- types-requests
- sqlmodel
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.2.2
hooks:
- id: ruff
args:
- --fix
- id: ruff-format


ci:
autofix_commit_msg: 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
autoupdate_commit_msg: ⬆ [pre-commit.ci] pre-commit autoupdate
67 changes: 65 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,65 @@
# budgly-api
Backend server for Budgly app
# Budgly

[![Tests](https://github.com/thyb-zytek/budgly-api/workflows/Run%20Tests/badge.svg)](https://github.com/thyb-zytek/budgly-api/actions/workflows/tests.yml)
[![Coverage](https://coverage-badge.samuelcolvin.workers.dev/thyb-zytek/budgly-api.svg)](https://coverage-badge.samuelcolvin.workers.dev/redirct/thyb-zytek/budgly-api)


## Technology Stack and Features

-[**FastAPI**](https://fastapi.tiangolo.com) for the Python backend API.
- 🧰 [SQLModel](https://sqlmodel.tiangolo.com) for the Python SQL database interactions (ORM).
- 🔍 [Pydantic](https://docs.pydantic.dev), used by FastAPI, for the data validation and settings management.
- 💾 [PostgreSQL](https://www.postgresql.org) as the SQL database.
- 🐋 [Docker Compose](https://www.docker.com) for development and production.
- ✅ Tests with [Pytest](https://pytest.org).
- 🚢 Deployment instructions using Docker Compose
- 🏭 CI/CD based on GitHub Actions.

## How To Use It

To use this project, you need to clone it and launch it.

Follow the next steps:

- Clone this repository:

```bash
git clone [email protected]:thyb-zytek/budgly-api.git
```

- Enter into the new directory:

```bash
cd budgly-api
```

- Create .env file from .env.sample and change values with your own:

```bash
mv .env.sample .env
```

- Launch your stack:

```bash
docker compose up -d
```

- Verify API server is up, if it displays `OK`, it means that the server is up:
```bash
curl -X 'GET' 'http://localhost:8000/healthcheck' -H 'accept: application/json'
```

Now you can use the APIs.

## Available URLs

🌐 Interactive Docs (Swagger UI): http://localhost:8000/docs

🌐 Alternative Docs (ReDoc): http://localhost:8000/redoc

🌐 APIs: http://localhost:8000/api/v1/

## License

The Budgly project is licensed under the terms of the GPL-3.0 license.
27 changes: 27 additions & 0 deletions app/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
FROM python:3.12

WORKDIR /app/

ARG ENV

# Env setup
ENV LANG C.UTF-8
ENV LC_ALL C.UTF-8
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONFAULTHANDLER 1
ENV PYTHONPATH=/app

# Update and install usefull package
RUN pip install --no-cache-dir poetry
RUN poetry config virtualenvs.create false # Needed to Github Actions

# Setup app environment
COPY . .
RUN if [ "$ENV" = "production" ]; then \
poetry install --no-root --without dev ;\
else \
poetry install --no-root --with dev; \
fi

# Launch app
CMD ["./scripts/start.sh"]
40 changes: 40 additions & 0 deletions app/alembic.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
[alembic]
script_location = alembic
prepend_sys_path = .
version_path_separator = os
sqlalchemy.url =

# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console
qualname =

[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers =
qualname = alembic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S
1 change: 1 addition & 0 deletions app/alembic/README
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Generic single-database configuration.
86 changes: 86 additions & 0 deletions app/alembic/env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import os
from logging.config import fileConfig

from sqlalchemy import engine_from_config, pool

from alembic import context

# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config

# Interpret the config file for Python logging.
# This line sets up loggers basically.
if config.config_file_name is not None:
fileConfig(config.config_file_name)

from models import * # noqa

target_metadata = SQLModel.metadata


# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.

def get_url():
user = os.getenv("POSTGRES_USER", "postgres")
password = os.getenv("POSTGRES_PASSWORD", "")
server = os.getenv("POSTGRES_SERVER", "db")
port = os.getenv("POSTGRES_PORT", "5432")
db = os.getenv("POSTGRES_DB", "app")
return f"postgresql+psycopg://{user}:{password}@{server}:{port}/{db}"


def run_migrations_offline() -> None:
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = get_url()
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True, compare_type=True
)

with context.begin_transaction():
context.run_migrations()


def run_migrations_online() -> None:
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
configuration = config.get_section(config.config_ini_section)
configuration["sqlalchemy.url"] = get_url()
connectable = engine_from_config(
configuration,
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)

with connectable.connect() as connection:
context.configure(
connection=connection, target_metadata=target_metadata, compare_type=True
)

with context.begin_transaction():
context.run_migrations()


if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
Loading

0 comments on commit 127bb6d

Please sign in to comment.