Skip to content
Open
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
23 changes: 23 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1 +1,24 @@
# VCS
.git
.gitignore
.github

# Local pixi environment (built inside the image via `pixi install`)
.pixi

# Local dev / bootstrap artifacts (regenerated in the image)
instance
report.md
docs/_build
GeoHealthCheck/static/lib
!GeoHealthCheck/static/lib/jqueryui
!GeoHealthCheck/static/lib/jspark
GeoHealthCheck/static/docs
**/data.db
*.log
**/*.log

# Tooling / caches
.pytest_cache
**/__pycache__
*.pyc
2 changes: 1 addition & 1 deletion .flake8
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[flake8]
max-line-length = 79
exclude = .git,.cache,docs,docker,build,dist,GeoHealthCheck/migrations
exclude = .git,.cache,docs,docker,build,dist,.pixi,GeoHealthCheck/migrations
# max-complexity = 38
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# SCM syntax highlighting & preventing 3-way merges
pixi.lock merge=binary linguist-language=YAML linguist-generated=true -diff
2 changes: 1 addition & 1 deletion .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ jobs:
org.opencontainers.image.revision=${{ github.sha }}

- name: GHC Unit Tests with Docker Image ⚙️
run: docker run --entrypoint "/run-tests.sh" ${{ steps.prep.outputs.image }}:${{ steps.prep.outputs.version }}
run: docker run --entrypoint "/app/docker/scripts/run-tests.sh" ${{ steps.prep.outputs.image }}:${{ steps.prep.outputs.version }}

- name: Push to Docker repo (on GH Push only) ☁️
if: ${{ github.event_name == 'push' }}
Expand Down
51 changes: 29 additions & 22 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# https://github.com/geopython/pycsw/blob/master/.github/workflows/main.yml
#
# Author: Just van den Broecke - 2021
# Migrated to pixi - 2026 by @francbartoli
#
name: Main GHC CI ⚙️

Expand All @@ -10,44 +11,50 @@ on: [ push, pull_request ]
jobs:
main:
runs-on: ubuntu-24.04
strategy:
matrix:
include:
- python-version: 3.12.3
steps:
- name: Checkout ✅
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Setup Python ${{ matrix.python-version }} 🐍
uses: actions/setup-python@v2
# Installs pixi (pinned) and the `dev` environment from the committed
# pixi.lock (locked: true fails if the lock is out of sync). Python and
# all dependencies come from the lock, so no separate setup-python step.
- name: Setup pixi 🧰
uses: prefix-dev/setup-pixi@v0.10.0
with:
python-version: ${{ matrix.python-version }}

- name: Install Requirements 📦
run: |
python -m pip install --upgrade pip
pip3 install -r requirements.txt
pip3 install -r requirements-dev.txt
pixi-version: v0.72.0
environments: dev
locked: true
cache: true

- name: Setup GHC App and init DB 🗃️
run: |
invoke setup
echo -e "admin\ntest\ntest\nyou@example.com\nyou@example.com" | python3 GeoHealthCheck/models.py create
pixi run -e dev setup
pixi run -e dev create -u admin -p admin -e a@a.com

- name: Flake8 - Verify Coding Conventions ⚙️
run: flake8
run: pixi run -e dev flake8

- name: Load Fixtures Test Data ⚙️
run: python3 GeoHealthCheck/models.py load tests/data/fixtures.json y
run: pixi run -e dev load-data tests/data/fixtures.json

# - name: Test DB downgrade to previous schema (via Alembic) ⚙️
# run: pixi run -e dev db-action downgrade
#
# - name: Test DB upgrade back to current schema (via Alembic) ⚙️
# run: pixi run -e dev db-action upgrade

- name: Run Probes ⚙️
run: python3 GeoHealthCheck/healthcheck.py
run: pixi run -e dev run-healthchecks

- name: Run Unit Tests ⚙️
run: python3 tests/run_tests.py
run: pixi run -e dev test

- name: Publish Test Report 📄
if: always()
run: cat report.md >> "$GITHUB_STEP_SUMMARY" || true

- name: Build Docs 📖
run: cd docs && make html
run: pixi run -e dev docs

- name: Cleanup 💯
run: python3 GeoHealthCheck/models.py drop
run: pixi run -e dev drop-data
10 changes: 9 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,16 @@ instance
tmp/
GeoHealthCheck/static/docs
GeoHealthCheck/static/lib
!GeoHealthCheck/static/lib/jqueryui
!GeoHealthCheck/static/lib/jspark
GeoHealthCheck.wsgi
GeoHealthCheck.conf

# Data
GeoHealthCheck/data.db
data.db
# test report
report.md

# pixi environments
.pixi/*
!.pixi/config.toml
127 changes: 78 additions & 49 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,31 +1,72 @@
FROM ubuntu:noble
FROM ghcr.io/prefix-dev/pixi:0.72.2-noble AS build
# Inspired by https://tech.quantco.com/blog/pixi-production/

# ARGS
ARG LANGUAGE="en_US"
ARG ENCODING="UTF-8"

ENV LOCALE_STR="${LANGUAGE}.${ENCODING} ${ENCODING}" \
DEBIAN_FRONTEND=noninteractive

# Install and Configure default locale
# NB GHC has its own language handling via Babel.
RUN apt update -y \
&& apt install -y locales \
&& echo "${LOCALE_STR}" > /etc/locale.gen \
&& locale-gen \
&& rm -rf /var/lib/apt/lists/*

# Copy entire GHC repo content to /app
WORKDIR /app
COPY . .

# Install deps (in /app/.pixi/).
RUN pixi install -e prod --locked

# pixi-env.sh: to be sourced, sets all paths and more.
RUN echo '#!/bin/bash' > /app/pixi-env.sh
RUN pixi shell-hook -e prod -s bash --as-is >> /app/pixi-env.sh
RUN echo 'exec "$@"' >> /app/pixi-env.sh
RUN echo chmod +x /app/pixi-env.sh

# Prepare the GHC app, mainly web-related.
RUN pixi run -e prod setup
RUN cp docker/config_site.py instance/
RUN if [ -d docker/plugins ]; then cp -ar docker/plugins/* /app/GeoHealthCheck/plugins/; fi

# Slim down, removing unused files generated within build
RUN rm -rf /app/GeoHealthCheck/docs
RUN find /app/GeoHealthCheck/static/lib -type d -name docs | xargs rm -rf
RUN find /app/GeoHealthCheck/static/lib -type d -name src | xargs rm -rf

FROM ubuntu:24.04 AS production

# Credits to yjacolin for providing first versions
LABEL original_developer="yjacolin <yves.jacolin@camptocamp.com>" \
maintainer="Just van den Broecke <justb4@gmail.com>"

# Copy the compiled locale files from the builder
COPY --from=build /usr/lib/locale/locale-archive /usr/lib/locale/locale-archive
COPY --from=build /etc/locale.gen /etc/locale.gen
COPY --from=build /etc/default/locale /etc/default/locale

# These are default values,
# Override when running container via docker(-compose)

# ARGS
ARG TZ="Etc/UTC"
ARG LANG="en_US.UTF-8"
ARG ADD_DEB_PACKAGES=""

# General ENV settings
ENV LC_ALL="en_US.UTF-8" \
LANG="en_US.UTF-8" \
LANGUAGE="en_US.UTF-8" \
\
\
DEB_PACKAGES="locales gunicorn python3.12-venv postgresql-client python3-gunicorn python3-gevent python3-lxml python3-pyproj" \
DEB_BUILD_DEPS="make python3-pip" \
ENV LANG='en_US.UTF-8' \
LANGUAGE='en_US:en' \
LC_ALL='en_US.UTF-8' \
TZ='Etc/UTC' \
DEB_PACKAGES="ca-certificates postgresql-client" \
DEB_BUILD_DEPS="adduser" \
ADMIN_NAME=admin \
ADMIN_PWD=admin \
ADMIN_EMAIL=admin.istrator@mydomain.com \
SQLALCHEMY_DATABASE_URI='sqlite:////GeoHealthCheck/DB/data.db' \
SQLALCHEMY_DATABASE_URI='sqlite:////app/instance/DB/data.db' \
SQLALCHEMY_ENGINE_OPTION_PRE_PING=False \
SECRET_KEY='d544ccc37dc3ad214c09b1b7faaa64c60351d5c8bb48b342' \
GHC_HOME=/app \
GHC_USER=ghc \
GHC_USER_HOME=/home/ghc \
GHC_PROBE_HTTP_TIMEOUT_SECS=30 \
GHC_MINIMAL_RUN_FREQUENCY_MINS=10 \
GHC_RETENTION_DAYS=30 \
Expand Down Expand Up @@ -54,52 +95,40 @@ ENV LC_ALL="en_US.UTF-8" \
GHC_GEOIP_LATFIELD='lat' \
GHC_GEOIP_LONFIELD='lon' \
GHC_METADATA_CACHE_SECS=900 \
\
# WSGI server settings, assumed is gunicorn \
HOST=0.0.0.0 \
PORT=80 \
WSGI_WORKERS=4 \
WSGI_WORKER_TIMEOUT=6000 \
WSGI_WORKER_CLASS='gevent' \
\
HOST=0.0.0.0 \
PORT=80 \
WSGI_WORKERS=4 \
WSGI_WORKER_TIMEOUT=6000 \
WSGI_WORKER_CLASS='gevent' \
GHC_USER_PLUGINS=''

# GHC Core Plugins modules and/or classes, seldom needed to set: \
# if not specified here or in Container environment \
# all GHC built-in Plugins will be active. \
#ENV GHC_PLUGINS 'GeoHealthCheck.plugins.probe.owsgetcaps,\
# GeoHealthCheck.plugins.probe.wms, ...., ...\
# GeoHealthCheck.plugins.check.checks' \
\
# GHC User Plugins, best be overridden via Container environment \
GHC_USER_PLUGINS=''

# Install operating system dependencies
RUN \
apt-get update \
&& apt-get --no-install-recommends install -y ${DEB_PACKAGES} ${DEB_BUILD_DEPS} ${ADD_DEB_PACKAGES} \
&& localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 \
&& echo "For ${TZ} date=$(date)" && echo "Locale=$(locale)"

# Add standard files and Add/override Plugins
# Alternative Entrypoints to run GHC jobs
# Override default Entrypoint with these on Containers
COPY docker/scripts/*.sh docker/config_site.py docker/plugins /

# Add Source Code
COPY . /GeoHealthCheck
# GHC User Plugins, best be overridden via Container environment \

# Install
# Install remaining dependencies and create user.
RUN \
chmod a+x /*.sh && ./install.sh \
# Cleanup TODO: remove unused Locales and TZs \
&& apt-get remove --purge -y ${DEB_BUILD_DEPS} \
&& apt-get clean \
apt update \
&& apt --no-install-recommends install -y ${DEB_PACKAGES} ${DEB_BUILD_DEPS} \
&& echo "For ${TZ} date=$(date)" && echo "Locale=$(locale)" \
&& adduser --disabled-password --shell /bin/bash --gecos "User" ${GHC_USER} \
&& apt remove --purge -y ${DEB_BUILD_DEPS} \
&& apt clean \
&& apt autoremove -y \
&& rm -rf /var/lib/apt/lists/*

# Copy entire bundle: GHC plus all dependencies, including non-Python binaries in /app.
WORKDIR /app
COPY --from=build --chown=${GHC_USER}:${GHC_USER} /app /app

# For SQLite
VOLUME ["/GeoHealthCheck/DB/"]
# Run Containers as user.
USER ${GHC_USER}

EXPOSE ${PORT}

ENTRYPOINT /run-web.sh
ENTRYPOINT [ "/app/docker/scripts/run-web.sh" ]
53 changes: 37 additions & 16 deletions GeoHealthCheck/manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,16 @@
# Usage:
#
# $ python3 manage.py --help
# usage: manage.py [-h] {shell,db,runserver} ...
#
# positional arguments:
# {shell,db,runserver}
# shell Runs a Python shell inside Flask application context.
# db Perform database migrations
# runserver Runs the Flask development server i.e. app.run()
# usage: manage.py action
#
# optional arguments:
# -h, --help show this help message and exit
#
# For DB management:
# $ python3 manage.py db --help
# $ python manage.py upgrade
# usage: Perform database migrations
#
# positional arguments:
# action arguments:
# {upgrade,migrate,current,stamp,init,downgrade,history,revision}
# upgrade Upgrade to a later version
# migrate Alias for 'revision --autogenerate'
Expand All @@ -37,17 +31,44 @@
# optional arguments:
# -h, --help show this help message and exit

from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
import sys
import os
from flask_migrate import (Migrate, upgrade, downgrade, current,
migrate, history, revision)
from init import App

DB = App.get_db()
APP = App.get_app()
workdir_path = os.path.dirname(__file__)
migrations_path = os.path.join(workdir_path, 'migrations')
Migrate(APP, DB, directory=migrations_path)
ACTIONS = ['current', 'upgrade', 'downgrade', 'migrate', 'history', 'revision']

if __name__ == '__main__':
if len(sys.argv) < 1 or sys.argv[1] not in ACTIONS:
print(f'Invalid action, valid values: {ACTIONS}')
sys.exit(1)

migrate = Migrate(APP, DB)
# Valid action name
action = sys.argv[1]

manager = Manager(APP)
manager.add_command('db', MigrateCommand)
os.chdir(workdir_path)

if __name__ == '__main__':
manager.run()
with APP.app_context():
if action == 'current':
current()
elif action == 'upgrade':
# Upgrade to latest version
upgrade()
elif action == 'downgrade':
# Downgrade one version back
downgrade()
elif action == 'migrate':
# Generate revision
migrate()
elif action == 'history':
# Show revisions
history()
elif action == 'revision':
# Create new revision
revision()
Loading
Loading