Skip to content
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

feat: replace backend with pluggable #1

Merged
merged 18 commits into from
Dec 8, 2023
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
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/[email protected]
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/[email protected]
- 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/[email protected]
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/[email protected].0
- uses: bcgov-nr/[email protected].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/[email protected]
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
Loading