diff --git a/.github/setup_evap/action.yml b/.github/setup_evap/action.yml
index 1a2f088a07..f5b29fb758 100644
--- a/.github/setup_evap/action.yml
+++ b/.github/setup_evap/action.yml
@@ -14,6 +14,9 @@ inputs:
description: "whether or not to run `npm ci`"
required: false
default: false
+ working-directory:
+ required: false
+ default: "."
runs:
using: "composite"
@@ -23,17 +26,21 @@ runs:
- uses: nicknovitski/nix-develop@v1
with:
arguments: "${{ inputs.shell }}"
+ if: ${{ inputs.shell != '' }}
- name: Add localsettings
run: cp evap/settings_test.py evap/localsettings.py
shell: bash
+ working-directory: ${{ inputs.working-directory }}
- name: Install Node dependencies
run: npm ci
shell: bash
if: ${{ inputs.npm-ci }}
+ working-directory: ${{ inputs.working-directory }}
- name: Start database
run: nix run .#services -- --detached && nix run .#wait-for-pc
shell: bash
if: ${{ inputs.start-db }}
+ working-directory: ${{ inputs.working-directory }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000000..2f3343c0a5
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,25 @@
+name: EvaP Release
+
+on:
+ pull_request:
+ # release:
+ # types: [published]
+
+jobs:
+ pypi-publish:
+ name: upload release to PyPI
+ runs-on: ubuntu-latest
+ environment: release
+ permissions:
+ id-token: write
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ submodules: true
+ - uses: DeterminateSystems/nix-installer-action@main
+ - uses: DeterminateSystems/magic-nix-cache-action@main
+ - run: nix run .#build-dist
+ - run: tar tvf dist/*.tar.gz
+ - run: unzip -l dist/*.whl
+ - name: Publish package distributions to PyPI
+ uses: pypa/gh-action-pypi-publish@release/v1
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 66007d4ea4..c30442f638 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -5,6 +5,7 @@ on:
branches:
- main
pull_request:
+ workflow_dispatch:
jobs:
test:
@@ -98,30 +99,53 @@ jobs:
- uses: actions/checkout@v4
with:
submodules: true
- - uses: ./.github/setup_evap
+ path: main
+ - uses: ./main/.github/setup_evap
with:
- shell: .#evap # no dev-dependencies
+ shell: ""
start-db: true
+ working-directory: main
- - name: Install additional dependencies
- run: sudo apt-get update && sudo apt-get install gettext
+ - name: Build wheel
+ run: nix run .#build-dist
+ working-directory: main
- - name: GitHub actions has wrong file ownership here, the checkout actions has a problem here (see their 1049)
- run: |
- git config --global --add safe.directory '*'
- sudo -H -u root git config --global --add safe.directory '*'
+ - uses: actions/checkout@v4
+ with:
+ repository: e-valuation/evap-deployment
+ ref: work # todo: remove
+ path: deployment
+
+ - uses: actions/setup-python@v5
+ with:
+ python-version: '3.10'
+
+ - name: Install wheel
+ run: pip install main/dist/*.whl
- name: Load test data
run: |
- python manage.py migrate
- python manage.py loaddata test_data
+ ln -s ../main/data/
+ cat <(echo 'from evap.settings import *') ../main/evap/settings_test.py | tee deployment_settings.py
+ python -m evap migrate
+ python -m evap loaddata test_data
+ working-directory: deployment
+ env:
+ DJANGO_SETTINGS_MODULE: deployment_settings
- name: Backup database
- run: deployment/update_production.sh backup.json
+ run: ./update_production.sh backup.json
env:
EVAP_OVERRIDE_BACKUP_FILENAME: true
- EVAP_SKIP_CHECKOUT: true
+ EVAP_SKIP_UPDATE: true
+ EVAP_SKIP_APACHE_STEPS: true
+ DJANGO_SETTINGS_MODULE: deployment_settings
+ working-directory: deployment
- name: Reload backup
- run: echo "yy" | deployment/load_production_backup.sh backup.json
+ run: echo "yy" | ./load_production_backup.sh backup.json
+ env:
+ EVAP_SKIP_APACHE_STEPS: true
+ DJANGO_SETTINGS_MODULE: deployment_settings
+ working-directory: deployment
compile_scss:
runs-on: ubuntu-22.04
diff --git a/.gitignore b/.gitignore
index caa4789b98..71038aab13 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,7 @@ TAGS
# python files
*.py[cod]
+dist/
# gettext binaries
*.mo
diff --git a/deployment/apache.maintenance-template.conf b/deployment/apache.maintenance-template.conf
deleted file mode 100644
index a246186f78..0000000000
--- a/deployment/apache.maintenance-template.conf
+++ /dev/null
@@ -1,24 +0,0 @@
-
- ServerName evap
-
- DocumentRoot /var/www/html
-
- RewriteEngine on
- RewriteCond %{DOCUMENT_ROOT}/maintenance.html -f
- RewriteCond %{SCRIPT_FILENAME} !maintenance.html
- RewriteRule !\.(png|css|svg)$ /maintenance.html [R=503,L]
- RewriteRule maintenance\.css$ /maintenance.css
- RewriteRule triangles_gray\.svg$ /background_gray.svg
- RewriteRule triangles_color\.svg$ /background_color.svg
- RewriteRule favicon\.png$ /favicon.png
- ErrorDocument 503 /maintenance.html
- Header Set Cache-Control "max-age=0, no-store"
-
- ErrorLog /var/log/apache2/error.log
-
- # Possible values include: debug, info, notice, warn, error, crit,
- # alert, emerg.
- LogLevel info
-
- CustomLog /var/log/apache2/access.log combined
-
diff --git a/deployment/apache.template.conf b/deployment/apache.template.conf
deleted file mode 100644
index e2aceec320..0000000000
--- a/deployment/apache.template.conf
+++ /dev/null
@@ -1,33 +0,0 @@
-
- ServerName evap
-
- DocumentRoot /var/www/
-
- WSGIScriptAlias / ${REPO_FOLDER}/evap/wsgi.py
- WSGIDaemonProcess evap processes=2 threads=15 display-name=%{GROUP} user=evap python-home=${ENV_FOLDER}
- WSGIProcessGroup evap
-
- Alias /static ${REPO_FOLDER}/evap/static_collected
-
- # Cache static assets for at least three hours
- Header set Cache-Control "max-age=10800"
-
-
- # Cache static assets with appended hash for one year
- Header set Cache-Control "max-age=31536000, immutable"
-
-
-
-
- Order deny,allow
- Require all granted
-
-
- ErrorLog /var/log/apache2/error.log
-
- # Possible values include: debug, info, notice, warn, error, crit,
- # alert, emerg.
- LogLevel info
-
- CustomLog /var/log/apache2/access.log combined
-
diff --git a/deployment/disable_maintenance_mode.sh b/deployment/disable_maintenance_mode.sh
deleted file mode 100755
index 70d8d44d00..0000000000
--- a/deployment/disable_maintenance_mode.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-set -e # abort on error
-
-rm -f /var/www/html/maintenance.css
-rm -f /var/www/html/background_gray.svg
-rm -f /var/www/html/background_color.svg
-rm -f /var/www/html/favicon.png
-rm -f /var/www/html/maintenance.html
-a2ensite -q evap.conf
-a2dissite -q evap-maintenance.conf
-service apache2 restart
-echo "Maintenance mode disabled."
diff --git a/deployment/enable_maintenance_mode.sh b/deployment/enable_maintenance_mode.sh
deleted file mode 100755
index a8f97f1dea..0000000000
--- a/deployment/enable_maintenance_mode.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-set -e # abort on error
-
-cp /opt/evap/evap/static/css/evap.css /var/www/html/maintenance.css
-cp /opt/evap/evap/static/images/triangles_gray.svg /var/www/html/background_gray.svg
-cp /opt/evap/evap/static/images/triangles_color.svg /var/www/html/background_color.svg
-cp /opt/evap/evap/static/images/favicon_64.png /var/www/html/favicon.png
-cp /opt/evap/evap/static/maintenance/maintenance.html /var/www/html/maintenance.html
-a2ensite -q evap-maintenance.conf
-a2dissite -q evap.conf
-service apache2 restart
-echo "Maintenance mode enabled."
diff --git a/deployment/load_production_backup.sh b/deployment/load_production_backup.sh
deleted file mode 100755
index 42744ac496..0000000000
--- a/deployment/load_production_backup.sh
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/usr/bin/env bash
-
-# Counter part for update_production script.
-# This script will import the backup made by update_production.
-
-set -e # abort on error
-cd "$(dirname "$0")/.." # change to root directory
-
-CONDITIONAL_NOINPUT=""
-[[ ! -z "$GITHUB_WORKFLOW" ]] && echo "Detected GitHub" && CONDITIONAL_NOINPUT="--noinput" && EVAP_SKIP_APACHE_STEPS=1
-
-COMMIT_HASH="$(git rev-parse --short HEAD)"
-
-# argument 1 is the filename for the backupfile.
-if [ ! $# -eq 1 ] # if there is exactly one argument
- then
- echo "Please specify a backup file to import as command line argument."
- exit
-fi
-
-# Check if commit hash is in file name. Ask for confirmation if its not there.
-if [[ ! $1 =~ ${COMMIT_HASH} ]]
-then
- echo "Looks like the backup was made on another commit. Currently, you are on ${COMMIT_HASH}."
- read -p "Do you want to continue [y]? " -n 1 -r
- echo
-
- if [[ ! $REPLY =~ ^[Yy]$ ]]
- then
- exit 1
- fi
-fi
-
-echo "WARNING! This will cause IRREPARABLE DATA LOSS."
-read -p "Are you sure you want to continue [y]? " -n 1 -r
-echo
-if [[ ! $REPLY =~ ^[Yy]$ ]]
-then
- exit 1
-fi
-
-[[ -z "$EVAP_SKIP_APACHE_STEPS" ]] && sudo service apache2 stop
-
-# sometimes, this fails for some random i18n test translation files.
-./manage.py compilemessages || true
-./manage.py scss --production
-./manage.py collectstatic --noinput
-
-./manage.py reset_db "$CONDITIONAL_NOINPUT"
-./manage.py migrate
-./manage.py flush "$CONDITIONAL_NOINPUT"
-./manage.py loaddata_unlogged "$1"
-
-./manage.py clear_cache --all -v=1
-./manage.py refresh_results_cache
-
-[[ -z "$EVAP_SKIP_APACHE_STEPS" ]] && sudo service apache2 start
-
-{ set +x; } 2>/dev/null # don't print the echo command, and don't print the 'set +x' itself
-
-echo "Backup restored."
diff --git a/deployment/update_production.sh b/deployment/update_production.sh
deleted file mode 100755
index eee24df57a..0000000000
--- a/deployment/update_production.sh
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env bash
-
-set -e # abort on error
-cd "$(dirname "$0")/.." # change to root directory
-
-echo "$PWD"
-
-# used for constructing the backup file name
-COMMIT_HASH="$(git rev-parse --short HEAD)"
-BACKUP_TITLE="backup"
-TIMESTAMP="$(date +%Y-%m-%d_%H:%M:%S)"
-
-[[ ! -z "$GITHUB_WORKFLOW" ]] && echo "Detected GitHub" && EVAP_SKIP_APACHE_STEPS=1
-
-# argument 1 is the title for the backupfile.
-if [ $# -eq 1 ]
- then
- BACKUP_TITLE=$1
-fi
-
-FILENAME="${BACKUP_TITLE}_${TIMESTAMP}_${COMMIT_HASH}.json"
-
-[[ -z "$EVAP_OVERRIDE_BACKUP_FILENAME" ]] || echo "Overriding Automatic Filename"
-[[ -z "$EVAP_OVERRIDE_BACKUP_FILENAME" ]] || FILENAME="${BACKUP_TITLE}"
-
-echo "Backup will be stored in $FILENAME"
-echo "Starting update..."
-
-set -x # print executed commands. enable this here to not print the if above.
-
-git fetch
-
-# Note that apache should not be running during most of the upgrade,
-# since then e.g. the backup might be incomplete or the code does not
-# match the database layout, or https://github.com/e-valuation/EvaP/issues/1237.
-[[ -z "$EVAP_SKIP_APACHE_STEPS" ]] && sudo ./deployment/enable_maintenance_mode.sh
-
-./manage.py dumpdata --natural-foreign --natural-primary --all -e contenttypes -e auth.Permission --indent 2 --output "$FILENAME"
-
-[[ ! -z "$EVAP_SKIP_CHECKOUT" ]] && echo "Skipping Checkout"
-[[ ! -z "$EVAP_SKIP_CHECKOUT" ]] || git checkout origin/release
-# NOTE: The Python environment should be updated here with something like
-# sudo -H -u "$USERNAME" "$ENVDIR/bin/pip" install -r requirements.txt
-
-# sometimes, this fails for some random i18n test translation files.
-./manage.py compilemessages || true
-./manage.py scss --production
-./manage.py ts compile --fresh
-./manage.py collectstatic --noinput
-./manage.py migrate
-./manage.py clear_cache --all -v=1
-./manage.py refresh_results_cache
-
-[[ -z "$EVAP_SKIP_APACHE_STEPS" ]] && sudo ./deployment/disable_maintenance_mode.sh
-
-{ set +x; } 2>/dev/null # don't print the echo command, and don't print the 'set +x' itself
-
-echo "Update completed."
diff --git a/evap/__main__.py b/evap/__main__.py
new file mode 100755
index 0000000000..f33754f5ec
--- /dev/null
+++ b/evap/__main__.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python3
+
+import os
+import sys
+
+from django.conf import settings
+from django.core.management import execute_from_command_line
+
+
+def main():
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "evap.settings")
+ if getattr(settings, "DATADIR", None) is not None:
+ settings.DATADIR.mkdir(exist_ok=True)
+ execute_from_command_line(sys.argv)
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/deployment/localsettings.template.py b/evap/development/localsettings.template.py
similarity index 87%
rename from deployment/localsettings.template.py
rename to evap/development/localsettings.template.py
index 71e27dd760..0258d5c4f2 100644
--- a/deployment/localsettings.template.py
+++ b/evap/development/localsettings.template.py
@@ -1,17 +1,19 @@
+# noqa: N999
+
from fractions import Fraction
from pathlib import Path
from django.utils.safestring import mark_safe
DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.postgresql',
- 'NAME': 'evap',
- 'USER': 'evap',
- 'PASSWORD': 'evap',
+ "default": {
+ "ENGINE": "django.db.backends.postgresql",
+ "NAME": "evap",
+ "USER": "evap",
+ "PASSWORD": "evap",
# Absolute path to use unix domain socket
- 'HOST': Path("./data/").resolve(),
- 'CONN_MAX_AGE': 600,
+ "HOST": Path("./data/").resolve(),
+ "CONN_MAX_AGE": 600,
}
}
diff --git a/deployment/manage_autocompletion.sh b/evap/development/manage_autocompletion.sh
similarity index 100%
rename from deployment/manage_autocompletion.sh
rename to evap/development/manage_autocompletion.sh
diff --git a/evap/static/maintenance/maintenance.html b/evap/static/maintenance/maintenance.html
deleted file mode 100644
index 2a8d80361a..0000000000
--- a/evap/static/maintenance/maintenance.html
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
- EvaP
-
-
-
-
-
-
-
-
-
Wartung
-
-
- EvaP wird gerade auf den neuesten Stand gebracht. Bitte versuchen Sie es in ein paar Minuten noch einmal.
-
-
-
-
-
Maintenance
-
-
- EvaP is being updated right now. Please try again in a few minutes.
-
-
-
-
-
-
-
diff --git a/evap/wsgi.py b/evap/wsgi.py
index 5d4e2ff0a2..60e0fbf7fa 100644
--- a/evap/wsgi.py
+++ b/evap/wsgi.py
@@ -7,15 +7,6 @@
https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
"""
-import os
-import sys
-
from django.core.wsgi import get_wsgi_application
-# this adds the project root to the python path.
-PWD = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-sys.path = [PWD] + sys.path
-
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "evap.settings")
-
application = get_wsgi_application()
diff --git a/flake.nix b/flake.nix
index bf6c900bdf..5cf247f535 100644
--- a/flake.nix
+++ b/flake.nix
@@ -90,6 +90,24 @@
done
'';
};
+
+ build-dist = pkgs.writeShellApplication {
+ name = "build-dist";
+ runtimeInputs = with pkgs; [ nodejs gettext git ];
+ text =
+ let
+ python-dev = self.devShells.${system}.evap-dev.passthru.venv;
+ python-build = self.packages.${system}.python3.withPackages (ps: [ ps.build ]);
+ in
+ ''
+ set -x
+ npm ci
+ ${python-dev}/bin/python ./manage.py compilemessages
+ ${python-dev}/bin/python ./manage.py scss --production
+ ${python-dev}/bin/python ./manage.py ts compile --fresh
+ ${python-build}/bin/python -m build
+ '';
+ };
});
};
}
diff --git a/manage.py b/manage.py
index 3dac837a2d..703b7a085f 100755
--- a/manage.py
+++ b/manage.py
@@ -1,13 +1,5 @@
#!/usr/bin/env python3
-import os
-import sys
+from evap.__main__ import main
-if __name__ == "__main__":
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "evap.settings")
-
- from django.conf import settings
- from django.core.management import execute_from_command_line
-
- settings.DATADIR.mkdir(exist_ok=True)
- execute_from_command_line(sys.argv)
+main()
diff --git a/nix/services.nix b/nix/services.nix
index f2202df332..76bd684631 100644
--- a/nix/services.nix
+++ b/nix/services.nix
@@ -63,7 +63,7 @@
exit 0
fi
set -x
- cp deployment/localsettings.template.py evap/localsettings.py
+ cp evap/development/localsettings.template.py evap/localsettings.py
sed -i -e "s/\$SECRET_KEY/$(head /dev/urandom | LC_ALL=C tr -dc A-Za-z0-9 | head -c 32)/" evap/localsettings.py
git submodule update --init
./manage.py collectstatic --noinput
diff --git a/nix/shell.nix b/nix/shell.nix
index 59f939b44c..94086e2135 100644
--- a/nix/shell.nix
+++ b/nix/shell.nix
@@ -4,7 +4,7 @@ let
# When running a nix shell, XDG_DATA_DIRS will be populated so that bash_completion can (lazily) find this completion script
evap-managepy-completion = pkgs.runCommand "evap-managepy-completion" { } ''
mkdir -p "$out/share/bash-completion/completions"
- install ${../deployment/manage_autocompletion.sh} "$out/share/bash-completion/completions/manage.py.bash"
+ install ${../evap/development/manage_autocompletion.sh} "$out/share/bash-completion/completions/manage.py.bash"
'';
clean-setup = pkgs.writeShellScriptBin "clean-setup" ''
diff --git a/pyproject.toml b/pyproject.toml
index 37375a14ad..191010adca 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,7 +1,7 @@
[project]
name = "evap"
description = "EvaP"
-version = "0.0.0"
+version = "2024.11.12"
readme = "README.md"
requires-python = "~=3.10.0"
dependencies = [
@@ -39,13 +39,31 @@ dev = [
"typeguard~=4.4.0",
]
+[tool.uv]
+no-binary-package = [
+ "psycopg-c",
+]
+
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
-[tool.uv]
-no-binary-package = [
- "psycopg-c",
+[tool.hatch.build]
+skip-excluded-dirs = false # otherwise, the artifacts below will be skipped
+exclude = [
+ "evap/static/bootstrap",
+ "evap/static/font-awesome",
+]
+artifacts = [
+ "evap/static/css/evap.css",
+ "evap/static/css/evap.css.map",
+ "evap/static/js/*.js",
+ "evap/static/js/*.map",
+ "evap/static/bootstrap/dist/js/bootstrap.bundle.min.js",
+ "evap/static/bootstrap/dist/js/bootstrap.bundle.min.js.map",
+ "evap/static/font-awesome/webfonts/",
+
+ "evap/locale/*.mo",
]
##############################################
diff --git a/uv.lock b/uv.lock
index 01f675ccd7..e025799233 100644
--- a/uv.lock
+++ b/uv.lock
@@ -312,7 +312,7 @@ wheels = [
[[package]]
name = "evap"
-version = "0.0.0"
+version = "2024.11.7"
source = { editable = "." }
dependencies = [
{ name = "django" },