Skip to content

Commit 72d0bb4

Browse files
committed
Add Playwright integration with Docker setup and initial API routes
1 parent e2fb31f commit 72d0bb4

21 files changed

Lines changed: 878 additions & 0 deletions

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ Plotly Dash
5959
### Grafana
6060
Grafana OSS
6161

62+
### Playwright
63+
Microsoft Playwright
64+
6265

6366
# TOOLS
6467

docker-compose.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,23 @@ services:
9090
command: ionic serve --external
9191
# tty: true
9292

93+
94+
playwright:
95+
container_name: playwright_container
96+
build:
97+
context: ./services/_templates/playwright
98+
dockerfile: playwright.dockerfile
99+
network: host
100+
args:
101+
- ENVIRONMENT=${ENVIRONMENT-dev}
102+
environment:
103+
- GOOGLE_APPLICATION_CREDENTIALS=/tmp/keys/application_default_credentials.json
104+
- GOOGLE_CLOUD_PROJECT=gcp-proj-playwright
105+
ports:
106+
- 8000:8000
107+
volumes:
108+
- ./services/_templates/playwright/screens:/tmp/screens
109+
- ./services/_templates/playwright/src/app:/app
110+
- ~/.config/gcloud/application_default_credentials.json:/tmp/keys/application_default_credentials.json
111+
command: uvicorn main:app --reload --workers 1 --host 0.0.0.0 --port ${PORT-8000} --log-level info
112+
# tty: true
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# pull python image
2+
FROM python:3.12-slim as base-stage
3+
4+
# set working directory
5+
WORKDIR /app
6+
7+
# set python environment
8+
ENV PYTHONDONTWRITEBYTECODE=1 \
9+
PYTHONUNBUFFERED=1 \
10+
PYTHONPATH=/
11+
12+
# set environment variables
13+
ARG ENVIRONMENT=prod
14+
ENV ENVIRONMENT=${ENVIRONMENT}
15+
16+
# set virtual environment
17+
ENV VIRTUAL_ENV=/venv
18+
RUN python3 -m venv ${VIRTUAL_ENV}
19+
ENV PATH="${VIRTUAL_ENV}/bin:$PATH"
20+
21+
# specify location out of app dir so no override on copy
22+
ENV PLAYWRIGHT_BROWSERS_PATH=/temp/ms-playwright
23+
24+
# install system dependencies
25+
RUN apt-get -y update \
26+
&& apt-get -y upgrade \
27+
# && apt-get -y install netcat gcc postgresql \
28+
# && apt-get -y install gcc \
29+
&& apt-get clean
30+
31+
# use base-stage for build
32+
FROM base-stage as builder-stage
33+
34+
# prevent poetry virtual environment
35+
ENV POETRY_VIRTUALENVS_CREATE false
36+
37+
# # copy in local packages for installation
38+
# COPY ./local_package /app/local_package
39+
40+
# install python dependencies
41+
RUN pip install --upgrade pip \
42+
&& pip install --no-cache-dir poetry
43+
COPY ./src/pyproject.toml ./src/poetry.lock ./
44+
RUN bash -c "if [ ${ENVIRONMENT} == 'dev' ] || [ ${ENVIRONMENT} == 'proxy' ] ; \
45+
then . /venv/bin/activate && poetry install --no-root --no-interaction; \
46+
else . /venv/bin/activate && poetry install --no-root --no-interaction --no-ansi --only main; fi"
47+
48+
# lint and stop build if fail for CI/CD
49+
# COPY . .
50+
# RUN pip install black flake8 isort
51+
# RUN flake8 .
52+
# RUN black .
53+
# RUN isort .
54+
55+
# use base-stage for final-stage image
56+
FROM base-stage as final-stage
57+
58+
# copy built venv folder
59+
COPY --from=builder-stage /venv /venv
60+
61+
# copy src to app folder
62+
COPY ./src/app .
63+
64+
# Install playwrite dependencies
65+
RUN playwright install --with-deps chromium
66+
67+
# use a non-root user
68+
RUN addgroup --system school && adduser --system --ingroup school fish
69+
RUN chown -R fish:school /app
70+
USER fish
71+
72+
# start the worker
73+
CMD uvicorn main:app --workers 1 --host 0.0.0.0 --port ${PORT-8080} --log-level info
74+
75+
# keep container alive for inspection
76+
# CMD sh -c "while true; do sleep 1; done"
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#! /usr/bin/env sh
2+
3+
set -e
4+
5+
# # DEPLOY TO PRODUCTION # #
6+
7+
# # set the environment
8+
export ENVIRONMENT=prod
9+
export GOOGLE_CLOUD_PROJECT=your_gcp_project_prod
10+
gcloud config set project your_gcp_project_prod
11+
12+
docker compose down
13+
14+
# # build the images
15+
docker compose -f docker-compose.yml build api --no-cache
16+
17+
# # upload image to artifact registry
18+
docker tag fast-stack-api europe-west1-docker.pkg.dev/your_gcp_project_prod/your-gcp-artifacts/api:latest
19+
docker push europe-west1-docker.pkg.dev/your_gcp_project_prod/service_account-artifacts-prod/api:latest
20+
21+
# # deploy cloud run revision with latest image
22+
gcloud run deploy api --image europe-west1-docker.pkg.dev/your_gcp_project_prod/your-gcp-artifacts/api:latest
23+
24+
# # webhook alert
25+
curl -X POST -H "Content-Type: application/json" -d '{"content": "'${USER}' deployed API to PROD 🚢"}' https://discord.com/api/webhooks/
26+
27+
echo '🚢'
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#! /usr/bin/env sh
2+
set -e
3+
4+
## START SCRIPT FOR DEVELOPMENT ##
5+
## start the local development environment with this script
6+
7+
## set environment variables
8+
gcloud config set project your_gcp_project_prod
9+
export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)
10+
export ENVIRONMENT=dev
11+
12+
docker compose up temp_api -d --build
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
**.pyc
2+
**.pyo
3+
**.pyd
4+
__pycache__
5+
.pytest_cache
6+
7+
.env
8+
9+
.dockerignore
10+
Dockerfile
11+
.dockerfile
12+
13+
.coverage
14+
htmlcov/

services/_templates/playwright/src/app/__init__.py

Whitespace-only changes.

services/_templates/playwright/src/app/api/__init__.py

Whitespace-only changes.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
""""Central place to store Depends functions for use in path operator functions or path decorators
2+
"""
3+
from typing import Generator
4+
5+
# from app import crud, schemas, models
6+
from app.core.config import secrets
7+
from app.core.security.auth0 import Auth0, Auth0User
8+
from fastapi import Depends, HTTPException, Security, status
9+
from fastapi.security import HTTPBearer, OAuth2PasswordBearer
10+
from loguru import logger
11+
from pydantic import ValidationError
12+
13+
14+
auth0 = Auth0(
15+
domain=secrets.AUTH0_DOMAIN,
16+
api_audience=secrets.AUTH0_API_AUDIENCE,
17+
# These scopes are selectable in the interactive docs
18+
scopes={
19+
"read:users": "required role: ADMIN",
20+
"read:all": "required role: SUPPORT",
21+
"write:all": "required role: SUPPORT",
22+
},
23+
)
24+
25+
26+
def get_auth0_user(
27+
auth0_user: Auth0User = Security(auth0.get_user, scopes=[]),
28+
) -> Auth0User:
29+
30+
return auth0_user
31+
32+
33+
def get_auth0_user_be_admin(
34+
auth0_user: Auth0User = Security(auth0.get_user, scopes=["read:users"]),
35+
) -> Auth0User:
36+
37+
return auth0_user
38+
39+
40+
def get_auth0_user_be_support(
41+
auth0_user: Auth0User = Security(auth0.get_user, scopes=["read:all", "write:all"]),
42+
) -> Auth0User:
43+
44+
return auth0_user
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"""Routes for the V1 API"""
2+
3+
from fastapi import APIRouter
4+
5+
from app.api.v0 import ping, report
6+
7+
v0_router = APIRouter(prefix="/v0")
8+
9+
v0_router.include_router(report.router, tags=["report"])
10+

0 commit comments

Comments
 (0)