Skip to content

Commit da7a617

Browse files
committed
add server
1 parent 065e68d commit da7a617

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1332
-45
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
version: "3.9"
2+
3+
services:
4+
backend:
5+
image: "{{ cookiecutter.project_slug }}-backend:latest"
6+
7+
frontend:
8+
image: "{{ cookiecutter.project_slug }}-frontend:latest"
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# We specify volumes in override.yml, because volumes don't work well in a
2+
# docker-in-docker setup (the paths of parent host rarely match the nested containers)
3+
version: "3.9"
4+
5+
services:
6+
postgres:
7+
ports:
8+
- "5432:5432"
9+
volumes:
10+
- app-db-data:/var/lib/postgresql/data:cached
11+
12+
backend:
13+
command: uvicorn --port {{ cookiecutter.backend_port }} --host 0.0.0.0 --reload main:app
14+
volumes:
15+
- ./backend:/app:delegated
16+
- root-home:/root:delegated
17+
depends_on:
18+
postgres:
19+
condition: service_healthy
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
version: "3.9"
2+
3+
services:
4+
postgres:
5+
image: postgres:12
6+
restart: always
7+
env_file:
8+
- .env
9+
healthcheck:
10+
test: pg_isready -U postgres
11+
interval: 3s
12+
timeout: 2s
13+
retries: 3
14+
15+
backend:
16+
build:
17+
context: backend
18+
ports:
19+
- "{{ cookiecutter.backend_port }}:{{ cookiecutter.backend_port }}"
20+
env_file: .env
21+
depends_on:
22+
postgres:
23+
condition: service_healthy
24+
25+
frontend:
26+
build:
27+
context: frontend
28+
ports:
29+
- "{{ cookiecutter.frontend_port }}:80"
30+
volumes:
31+
- ./frontend:/app:delegated
32+
environment:
33+
- NODE_ENV=production
34+
35+
volumes:
36+
app-db-data:
37+
root-home:

{{ cookiecutter.project_slug }}/pyproject.toml

Lines changed: 21 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -30,23 +30,37 @@ packages = [
3030
{% endif %}
3131

3232
[tool.poetry.dependencies]
33-
python = "^{{ cookiecutter.minimal_python_version }}"
33+
python = "^{{ cookiecutter.minimal_python_version }},<4.0"
3434
{% if cookiecutter.create_example_template == 'cli' %}
3535
typer = "^0.7.0"
3636
tqdm="^4.64.1"
3737
{% endif %}
38+
{% if cookiecutter.create_example_template == 'server' %}
39+
fastapi = "^0.98.0"
40+
uvicorn = "^0.23.2"
41+
requests = "^2.31.0"
42+
alembic = "^1.11.3"
43+
psycopg2-binary = "^2.9.7"
44+
asyncpg = "^0.28.0"
45+
SQLAlchemy = "^2.0.20"
46+
gunicorn = "^21.2.0"
47+
{% endif %}
3848

39-
[tool.poetry.dev-dependencies]
49+
[tool.poetry.group.dev.dependencies]
50+
black = "^23.10.1"
4051
pytest = "^7.1.2"
4152
allure-pytest = "^2.10.0"
4253
pre-commit = "^2.21.0"
43-
isort = {extras = ["colors"], version = "^5.11.4"}
4454
darglint = "^1.8.1"
4555
pytest-html = "^3.2.0"
4656
coverage = "^7.0.5"
4757
coverage-badge = "^1.1.0"
4858
black = "^22.12.0"
4959
pytest-cov = "^4.0.0"
60+
ipython = "^8.16.1"
61+
pytest-cov = "^4.1.0"
62+
httpx = "^0.24.1"
63+
pytest-asyncio = "^0.21.1"
5064

5165
[tool.black]
5266
# https://github.com/psf/black
@@ -70,55 +84,17 @@ exclude = '''
7084
)/
7185
'''
7286

73-
[tool.isort]
74-
# https://github.com/timothycrosley/isort/
75-
py_version = {{ cookiecutter.minimal_python_version.replace('.', '') }}
76-
line_length = {{ cookiecutter.line_length }}
77-
known_typing = ["typing", "types", "typing_extensions", "mypy", "mypy_extensions"]
78-
sections = ["FUTURE", "TYPING", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"]
79-
include_trailing_comma = true
80-
profile = "black"
81-
multi_line_output = 3
82-
indent = 4
83-
color_output = true
84-
force_single_line = true
85-
combine_as_imports = true
86-
lines_between_types = 1
87-
lines_after_imports = 2
88-
src_paths = ["src", "tests"]
89-
extend_skip = ["setup.py"]
90-
91-
[tool.mypy]
92-
# https://mypy.readthedocs.io/en/latest/config_file.html#using-a-pyproject-toml-file
93-
python_version = {{ cookiecutter.minimal_python_version }}
94-
pretty = true
95-
show_traceback = true
96-
color_output = true
97-
allow_redefinition = false
98-
check_untyped_defs = true
99-
disallow_any_generics = true
100-
disallow_incomplete_defs = true
101-
ignore_missing_imports = true
102-
implicit_reexport = false
103-
no_implicit_optional = true
104-
show_column_numbers = true
105-
show_error_codes = true
106-
show_error_context = true
107-
strict_equality = true
108-
strict_optional = true
109-
warn_no_return = true
110-
warn_redundant_casts = true
111-
warn_return_any = true
112-
warn_unreachable = true
113-
warn_unused_configs = true
114-
warn_unused_ignores = true
11587

11688

89+
[tool.cruft]
90+
skip = [".env"]
91+
11792
[tool.pytest.ini_options]
11893
# https://docs.pytest.org/en/6.2.x/customize.html#pyproject-toml
11994
# Directories that are not visited by pytest collector:
12095
norecursedirs =["hooks", "*.egg", ".eggs", "dist", "build", "docs", ".tox", ".git", "__pycache__"]
12196
doctest_optionflags = ["NUMBER", "NORMALIZE_WHITESPACE", "IGNORE_EXCEPTION_DETAIL"]
97+
asyncio_mode = 'auto'
12298

12399
# Extra options:
124100
addopts = [
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/bin/bash
2+
3+
cookiecutter --no-input . -f project_slug="demo-project-fastapi-starter" project_name="Demo project FastAPI starter"
4+
5+
cp scripts/fly.toml ./demo-project-fastapi-starter/
6+
7+
cd demo-project-fastapi-starter/
8+
9+
flyctl deploy --remote-only
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# fly.toml file generated for demo-project-fastapi-starter on 2022-05-26T14:02:13+02:00
2+
3+
app = "demo-project-fastapi-starter"
4+
5+
kill_signal = "SIGINT"
6+
kill_timeout = 5
7+
processes = []
8+
9+
[env]
10+
11+
[experimental]
12+
allowed_public_ports = []
13+
auto_rollback = true
14+
15+
[deploy]
16+
release_command = "alembic upgrade head"
17+
18+
[[services]]
19+
http_checks = []
20+
internal_port = 8000
21+
processes = ["app"]
22+
protocol = "tcp"
23+
script_checks = []
24+
25+
[services.concurrency]
26+
hard_limit = 25
27+
soft_limit = 20
28+
type = "connections"
29+
30+
[[services.ports]]
31+
force_https = true
32+
handlers = ["http"]
33+
port = 80
34+
35+
[[services.ports]]
36+
handlers = ["tls", "http"]
37+
port = 443
38+
39+
[[services.tcp_checks]]
40+
grace_period = "1s"
41+
interval = "15s"
42+
restart_limit = 0
43+
timeout = "2s"
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#! /usr/bin/env bash
2+
3+
set -eou pipefail
4+
5+
# Stop containers from previous run, if any
6+
(cd ./test-project && docker-compose -f docker-compose.yml down --rmi local -v && cd ..) || true
7+
8+
# Run this from the root of the project
9+
rm -rf ./test-project
10+
11+
cookiecutter --no-input -f ./ project_slug="test-project" project_name="Test project"
12+
13+
cd ./test-project/
14+
15+
# Start docker containers
16+
docker-compose -f docker-compose.yml up -d --build
17+
18+
19+
# Run backend tests
20+
docker-compose exec -T postgres createdb -U postgres apptest
21+
22+
docker-compose exec -T backend pytest -v --cov --cov-report term-missing
23+
24+
# Run cypress tests
25+
docker-compose exec -T backend alembic upgrade head
26+
27+
docker-compose exec -T backend alembic check
28+
29+
docker build --target build -t frontend-build:latest frontend
30+
31+
mv $(pwd)/frontend/src/generated /tmp/src-generated
32+
33+
PACKAGE_LIST="xvfb libnss3 libatk1.0 libatk-bridge2.0 libgtk-3.0 libgbm1 libasound2 default-jre"
34+
# If GITHUB_REPOSITORY is not set, then we can just run it in docker
35+
# We need to have two paths here because Github CI works weirdly with bind mounts that we can use to run the tests locally in Docker
36+
if [ -z "${GITHUB_REPOSITORY-}" ]
37+
then
38+
docker run \
39+
-v $(pwd)/frontend/src/generated/:/app/src/generated \
40+
-v $(pwd)/frontend/cypress:/app/cypress \
41+
--network="host" \
42+
frontend-build \
43+
bash -xc "apt-get update -qq &&
44+
apt-get install -qq $PACKAGE_LIST &&
45+
yarn run-e2e-tests &&
46+
yarn config set script-shell /bin/bash &&
47+
yarn genapi"
48+
else
49+
cd frontend
50+
npm config set script-shell /bin/bash
51+
sudo apt-get update -qq && sudo apt-get install -qq $PACKAGE_LIST
52+
yarn install --frozen-lockfile
53+
yarn run-e2e-tests
54+
yarn genapi
55+
cd ..
56+
fi
57+
#
58+
# This is to ensure that the generated API client is always in sync with FastAPI code
59+
diff -r /tmp/src-generated $(pwd)/frontend/src/generated || (echo "Generated files changed. Please make sure they are in sync" && exit 1)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
ARG PYTHON_VER=3.11
2+
3+
FROM python:${PYTHON_VER} AS base
4+
5+
WORKDIR /app
6+
7+
ENV PYTHONUNBUFFERED=1
8+
9+
# Install Poetry
10+
RUN curl -sSL https://install.python-poetry.org | POETRY_HOME=/opt/poetry python && \
11+
cd /usr/local/bin && \
12+
ln -s /opt/poetry/bin/poetry && \
13+
poetry config virtualenvs.create false
14+
15+
COPY ./pyproject.toml ./poetry.lock* /app/
16+
17+
RUN poetry install --no-root
18+
19+
COPY . /app
20+
21+
FROM python:3.11-slim
22+
23+
WORKDIR /app
24+
25+
COPY --from=base /app /app
26+
COPY --from=base /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
27+
COPY --from=base /usr/local/bin /usr/local/bin
28+
29+
CMD uvicorn --host 0.0.0.0 --port 8000 main:app

0 commit comments

Comments
 (0)