Skip to content

Commit

Permalink
feat: replace backend with pluggable (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
franTarkenton authored Dec 8, 2023
1 parent a820d7d commit 68edbce
Show file tree
Hide file tree
Showing 78 changed files with 3,332 additions and 12,666 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/.tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ on:

jobs:
integration-tests:
if: github.repository == 'disabling_integration_tests_for_now'
name: Integration Tests
runs-on: ubuntu-22.04
timeout-minutes: 1
Expand All @@ -36,6 +37,7 @@ jobs:
node src/main.js
cypress-e2e:
if: github.repository == 'disabling_integration_tests_for_now'
name: E2E Tests
runs-on: ubuntu-22.04
defaults:
Expand Down
91 changes: 54 additions & 37 deletions .github/workflows/analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,54 @@ name: Analysis
on:
push:
branches: [main]
merge_group:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
schedule:
- cron: "0 11 * * 0" # 3 AM PST = 12 PM UDT, runs sundays
- cron: "0 12 * * 0" # 4 AM PST = 12 PM UDT, runs sundays
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
codeql:
CodeQL:
name: CodeQL
if: github.event_name != 'pull_request' || !github.event.pull_request.draft
runs-on: ubuntu-22.04
timeout-minutes: 5
strategy:
matrix:
language: [python]
include:
- language: "python"
steps:
- uses: actions/checkout@v4
- uses: github/codeql-action/init@v2
with:
languages: javascript
languages: ${{ matrix.language }}

- name: Autobuild
if: ${{ ! matrix.build }}
uses: github/codeql-action/autobuild@v2

- name: Build
if: ${{ matrix.build }}
run: ${{ matrix.build }}
working-directory: ${{ matrix.working-directory }}

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:javascript"
category: "/language:${{matrix.language}}"

# https://github.com/marketplace/actions/aqua-security-trivy
trivy:
name: Trivy Security Scan
if: github.event_name != 'pull_request' || !github.event.pull_request.draft
runs-on: ubuntu-22.04
timeout-minutes: 1
steps:
- uses: actions/checkout@v4

- name: Run Trivy vulnerability scanner in repo mode
uses: aquasecurity/trivy-action@0.14.0
with:
Expand All @@ -54,15 +66,20 @@ jobs:
with:
sarif_file: "trivy-results.sarif"

tests:
name: Tests

python:
name: Python
if: github.event_name != 'pull_request' || !github.event.pull_request.draft
runs-on: ubuntu-22.04
timeout-minutes: 5
defaults:
run:
working-directory: backend
services:
postgres:
image: postgres
env:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
Expand All @@ -71,32 +88,32 @@ jobs:
--health-retries 5
ports:
- 5432:5432
strategy:
matrix:
dir: [backend, frontend]
include:
- dir: backend
sonar_projectKey: quickstart-openshift_backend
token: SONAR_TOKEN_BACKEND
triggers: ('backend/')
- dir: frontend
sonar_projectKey: quickstart-openshift_frontend
token: SONAR_TOKEN_FRONTEND
triggers: ('frontend/')
steps:
- uses: bcgov-nr/action-test-and-analyse@v1.1.0
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: "3.11"

- name: cache poetry install
uses: actions/cache@v3
with:
path: ~/.local
key: poetry-${{ hashFiles('**/pyproject.toml') }}

- uses: snok/install-poetry@v1.3.4
with:
commands: |
npm ci
npm run test:cov
dir: ${{ matrix.dir }}
node_version: "20"
sonar_args: >
-Dsonar.exclusions=**/coverage/**,**/node_modules/**,**/*spec.ts
-Dsonar.organization=bcgov-sonarcloud
-Dsonar.projectKey=${{ matrix.sonar_projectKey }}
-Dsonar.sources=src
-Dsonar.tests.inclusions=**/*spec.ts
-Dsonar.javascript.lcov.reportPaths=./coverage/lcov.info
sonar_token: ${{ secrets[matrix.token] }}
triggers: ${{ matrix.triggers }}
version: 1.2.2
virtualenvs-create: true
virtualenvs-in-project: true
installer-parallel: true

- id: cache-deps
uses: actions/cache@v3
with:
path: .venv
key: pydeps-${{ hashFiles('**/poetry.lock') }}

- run: poetry install --no-interaction --no-root
if: steps.cache-deps.outputs.cache-hit != 'true'

- run: poetry run pytest
23 changes: 21 additions & 2 deletions .github/workflows/pr-open.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,17 +91,36 @@ jobs:
packages: write
strategy:
matrix:
package: [migrations, backend, frontend]
package: [backend, frontend]
timeout-minutes: 10
steps:
- uses: bcgov-nr/action-builder-ghcr@v2.0.0
- uses: bcgov-nr/action-builder-ghcr@v2.0.1
with:
keep_versions: 50
package: ${{ matrix.package }}
tag: ${{ needs.vars.outputs.tag }}
tag_fallback: latest
triggers: ('${{ matrix.package }}/')

build-custom:
name: Build Migrations
needs: [vars]
runs-on: ubuntu-22.04
permissions:
packages: write
timeout-minutes: 10
steps:
- uses: bcgov-nr/action-builder-ghcr@v2.0.1
with:
keep_versions: 10
package: alembicmigrations
tag: ${{ needs.vars.outputs.tag }}
tag_fallback: latest
triggers: ('backend/alembic/versions')
build_file: migrations/Dockerfile
build_context: .


# https://github.com/bcgov-nr/action-deployer-openshift
deploys:
name: Deploys
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/scheduled.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
env:
FLYWAY_VALIDATE_MIGRATION_NAMING: true
FLYWAY_LOCATIONS: filesystem:./migrations
FLYWAY_DEFAULT_SCHEMA: "users"
FLYWAY_DEFAULT_SCHEMA: "py_api"

- name: Create Output Folder
run: |
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,8 @@ test-report.xml

# VSCode
.vscode/
junk.txt


__pycache__/
charts/quickstart-openshift/charts/component/
35 changes: 35 additions & 0 deletions backend/.prospector.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
output-format: json

strictness: veryhigh
test-warnings: true
doc-warnings: false

ignore-paths:
- docs

ignore-patterns:
- (^|/)skip(this)?(/|$)

pycodestyle:
disable:
- W602
- W603
enable:
- W601
options:
max-line-length: 120
pylint:
disable:
- bad-builtin
- too-few-public-methods
options:
max-locals: 15
max-returns: 6
max-branches: 15
max-statements: 60
max-parents: 7
max-attributes: 7
min-public-methods: 1
max-public-methods: 20
max-module-lines: 1000
max-line-length: 120
51 changes: 29 additions & 22 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
# Build static files
# Node Bullseye has npm
FROM node:20.10.0-bullseye-slim AS build
FROM python:bullseye AS build

# Install packages, build and keep only prod packages
# Disable cache dir, disable upgrade message, create .venv in project dir
ARG PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=on \
POETRY_VIRTUALENVS_IN_PROJECT=1

# Install poetry, then dependencies
WORKDIR /app
COPY *.json ./
COPY ./src ./src
RUN npm ci --ignore-scripts --no-update-notifier --omit=dev && \
npm run build
COPY pyproject.toml poetry.lock ./
RUN pip install poetry==1.6.1 && \
poetry install --no-root -vvv --without dev --sync

# Deploy container
# Distroless has node, but not npm
FROM gcr.io/distroless/nodejs20-debian11:nonroot
ENV NODE_ENV production
# Deploy
FROM python:slim-bullseye AS deploy

# Copy over app
WORKDIR /app
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
# Output to stdout/stderr, don't create .pyc files, etc.
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PATH="/app/.venv/bin:$PATH" \
PORT=3000

# Ports, health check and non-root user
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s CMD curl -f http://localhost/:3000/api || exit 1
USER app
# Packages
RUN apt update && \
apt install -y --no-install-recommends curl libpq-dev

# Dependencies, config and app
COPY --from=build /app/.venv /app/.venv
COPY logger.conf ./
COPY ./src ./src

# Start up command with 50MB of heap size, each application needs to determine what is the best value. DONT use default as it is 4GB.
CMD ["--max-old-space-size=50", "/app/dist/main"]
# Start with non-privileged user
HEALTHCHECK --interval=300s --timeout=10s CMD curl -f http://localhost:${PORT}
USER 1001
CMD uvicorn src.main:app --host 0.0.0.0 --port ${PORT} --workers 1 --server-header --date-header --limit-concurrency 1000 --log-config ./logger.conf
38 changes: 38 additions & 0 deletions backend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Python FastAPI Backend
### Features
- [x] FastAPI
- [x] SQLAlchemy
- [x] Poetry
- [x] Prospector
- [x] Flyway
- [x] Docker
- [x] Docker Compose
- [x] GitHub Actions

## Getting Started

### Prerequisites
- [Docker](https://docs.docker.com/get-docker/)
- [Docker Compose](https://docs.docker.com/compose/install/)

### Local Development

#### Local Dev with Docker

- Run the `docker compose -f .\docker-compose.py.yml up` command to start the entire stack.
- The database changes are applied automatically by alembic
- The models are generated into `backend-py/src/v1/models/model.py` .
- The API is Documentation available at http://localhost:3003/docs

#### Local Dev - poetry

* create the env `cd backend; poetry install`
* activate the env `source $(poetry env info --path)/bin/activate`
* start uvicorn

```uvicorn src.main:app --host 0.0.0.0 --port 3000 --workers 1 --server-header --date-header --limit-concurrency 100 --reload --log-config ./logger.conf```

### Unit Testing
- Run `docker-compose up -d backend-py-test` command to run the unit tests from the root directory.
- The folder is volume mounted , so any changes to the code will be reflected in the container and run the unit tests again.

Loading

0 comments on commit 68edbce

Please sign in to comment.