mirror of
https://github.com/YunoHost-Apps/django-for-runners_ynh.git
synced 2024-09-03 18:26:16 +02:00
Apply manageprojects updates
https://github.com/jedie/cookiecutter_templates/#base-django-yunohost-app migrated from Poetry to pip-tools and to manifest v2 Apply these changes here.
This commit is contained in:
parent
9edb4d78af
commit
179765f117
38 changed files with 3649 additions and 4366 deletions
16
.github/workflows/package_linter.yml
vendored
16
.github/workflows/package_linter.yml
vendored
|
@ -15,24 +15,24 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
# https://github.com/marketplace/actions/checkout
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- uses: actions/cache@v3
|
- name: Set up Python
|
||||||
# https://github.com/marketplace/actions/cache
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
path: ~/.cache/
|
python-version: '3.9'
|
||||||
key: dot-cache-files
|
|
||||||
|
|
||||||
- name: 'Install dependencies'
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
pip install toml
|
pip install toml
|
||||||
|
|
||||||
- name: 'Clone YunoHost apps package linter'
|
- name: 'Clone YunoHost apps package linter'
|
||||||
run: |
|
run: |
|
||||||
git clone --depth=1 https://github.com/YunoHost/package_linter ~/package_linter
|
git clone --depth=1 https://github.com/YunoHost/package_linter ~/package_linter
|
||||||
|
|
||||||
|
- name: 'Install requirements'
|
||||||
|
run: pip3 install toml
|
||||||
|
|
||||||
- name: 'Run linter'
|
- name: 'Run linter'
|
||||||
run: |
|
run: |
|
||||||
~/package_linter/package_linter.py .
|
~/package_linter/package_linter.py .
|
||||||
|
|
66
.github/workflows/pytest.yml
vendored
66
.github/workflows/pytest.yml
vendored
|
@ -1,66 +0,0 @@
|
||||||
name: pytest
|
|
||||||
|
|
||||||
on:
|
|
||||||
# Allow to manually trigger the workflow
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
pull_request:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 8 * * *'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
python-version: ["3.11", "3.10", "3.9"]
|
|
||||||
env:
|
|
||||||
PYTHONUNBUFFERED: 1
|
|
||||||
PYTHONWARNINGS: always
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
# https://github.com/marketplace/actions/checkout
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: 'fetch master and testing (for Darker/Black)'
|
|
||||||
run: |
|
|
||||||
git fetch origin master
|
|
||||||
git fetch origin testing
|
|
||||||
|
|
||||||
- name: 'Set up Python ${{ matrix.python-version }}'
|
|
||||||
uses: actions/setup-python@v2
|
|
||||||
with:
|
|
||||||
python-version: '${{ matrix.python-version }}'
|
|
||||||
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
# https://github.com/marketplace/actions/cache
|
|
||||||
with:
|
|
||||||
path: ~/.cache/
|
|
||||||
key: dot-cache-files
|
|
||||||
|
|
||||||
- name: 'Install package'
|
|
||||||
run: |
|
|
||||||
pip3 install poetry
|
|
||||||
make install
|
|
||||||
|
|
||||||
- name: 'List installed packages'
|
|
||||||
run: |
|
|
||||||
poetry run pip freeze
|
|
||||||
|
|
||||||
- name: 'Run tests with Python v${{ matrix.python-version }}'
|
|
||||||
run: |
|
|
||||||
make pytest
|
|
||||||
|
|
||||||
- name: 'Run Safety check'
|
|
||||||
run: |
|
|
||||||
make safety
|
|
||||||
|
|
||||||
- name: 'Upload coverage report'
|
|
||||||
uses: codecov/codecov-action@v3
|
|
||||||
# https://github.com/marketplace/actions/codecov
|
|
||||||
with:
|
|
||||||
fail_ci_if_error: false
|
|
||||||
verbose: true
|
|
63
.github/workflows/tests.yml
vendored
Normal file
63
.github/workflows/tests.yml
vendored
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
name: tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 8 * * *'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
python-version: ["3.12", "3.11", "3.10", "3.9"]
|
||||||
|
env:
|
||||||
|
PYTHONUNBUFFERED: 1
|
||||||
|
PYTHONWARNINGS: always
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
run: |
|
||||||
|
echo $GITHUB_REF $GITHUB_SHA
|
||||||
|
git clone https://github.com/$GITHUB_REPOSITORY.git .
|
||||||
|
git fetch origin $GITHUB_SHA:temporary-ci-branch
|
||||||
|
git checkout $GITHUB_SHA || (git fetch && git checkout $GITHUB_SHA)
|
||||||
|
- name: 'fetch master'
|
||||||
|
run: |
|
||||||
|
git fetch origin master
|
||||||
|
|
||||||
|
- name: 'Set up Python ${{ matrix.python-version }}'
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
# https://github.com/marketplace/actions/setup-python
|
||||||
|
with:
|
||||||
|
python-version: '${{ matrix.python-version }}'
|
||||||
|
cache: 'pip' # caching pip dependencies
|
||||||
|
cache-dependency-path: '**/requirements.dev.txt'
|
||||||
|
|
||||||
|
- name: 'Bootstrap dev venv'
|
||||||
|
# The first CLI call will create the .venv
|
||||||
|
run: |
|
||||||
|
./dev-cli.py version
|
||||||
|
|
||||||
|
- name: 'dev CLI help'
|
||||||
|
run: |
|
||||||
|
./dev-cli.py --help
|
||||||
|
|
||||||
|
- name: 'Safety'
|
||||||
|
run: |
|
||||||
|
./dev-cli.py safety
|
||||||
|
|
||||||
|
- name: 'Run tests with Python v${{ matrix.python-version }}'
|
||||||
|
run: |
|
||||||
|
.venv/bin/coverage erase
|
||||||
|
./dev-cli.py coverage
|
||||||
|
|
||||||
|
- name: 'Upload coverage report'
|
||||||
|
uses: codecov/codecov-action@v3
|
||||||
|
# https://github.com/marketplace/actions/codecov
|
||||||
|
with:
|
||||||
|
fail_ci_if_error: false
|
||||||
|
verbose: true
|
13
.gitignore
vendored
13
.gitignore
vendored
|
@ -1,12 +1,17 @@
|
||||||
.*
|
.*
|
||||||
|
*.egg-info
|
||||||
|
__pycache__
|
||||||
|
/dist/
|
||||||
|
/coverage.*
|
||||||
|
/htmlcov/
|
||||||
|
*.orig
|
||||||
|
|
||||||
!.github
|
!.github
|
||||||
!.editorconfig
|
!.editorconfig
|
||||||
!.flake8
|
!.flake8
|
||||||
!.gitignore
|
!.gitignore
|
||||||
|
!.gitkeep
|
||||||
!/doc/screenshots/.gitkeep
|
!/doc/screenshots/.gitkeep
|
||||||
__pycache__
|
|
||||||
secret.txt
|
secret.txt
|
||||||
/local_test/
|
/local_test/
|
||||||
/coverage.json
|
|
||||||
/coverage.xml
|
|
||||||
/htmlcov/
|
|
||||||
|
|
65
Makefile
65
Makefile
|
@ -1,65 +0,0 @@
|
||||||
SHELL := /bin/bash
|
|
||||||
MAX_LINE_LENGTH := 100
|
|
||||||
|
|
||||||
all: help
|
|
||||||
|
|
||||||
help:
|
|
||||||
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z0-9 -]+:.*?## / {printf "\033[36m%-22s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
|
||||||
|
|
||||||
check-poetry:
|
|
||||||
@if [[ "$(shell poetry --version 2>/dev/null)" == *"Poetry"* ]] ; \
|
|
||||||
then \
|
|
||||||
echo "Poetry found, ok." ; \
|
|
||||||
else \
|
|
||||||
echo 'Please install poetry first, with e.g.:' ; \
|
|
||||||
echo 'make install-poetry' ; \
|
|
||||||
exit 1 ; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
install-base-req: ## Install needed base packages via apt
|
|
||||||
sudo apt install python3-pip python3-venv
|
|
||||||
|
|
||||||
install-poetry: ## install or update poetry
|
|
||||||
curl -sSL https://install.python-poetry.org | python3 -
|
|
||||||
|
|
||||||
install: check-poetry ## install project via poetry
|
|
||||||
python3 -m venv .venv
|
|
||||||
poetry install
|
|
||||||
|
|
||||||
update: check-poetry ## update the sources and installation and generate "conf/requirements.txt"
|
|
||||||
python3 -m venv .venv
|
|
||||||
poetry self update
|
|
||||||
poetry update -v
|
|
||||||
poetry install
|
|
||||||
poetry export -f requirements.txt --output conf/requirements.txt
|
|
||||||
|
|
||||||
lint: ## Run code formatters and linter
|
|
||||||
poetry run darker --check
|
|
||||||
poetry run isort --check-only .
|
|
||||||
poetry run flake8 .
|
|
||||||
|
|
||||||
fix-code-style: ## Fix code formatting
|
|
||||||
poetry run darker
|
|
||||||
poetry run isort .
|
|
||||||
|
|
||||||
tox-listenvs: check-poetry ## List all tox test environments
|
|
||||||
poetry run tox --listenvs
|
|
||||||
|
|
||||||
tox: check-poetry ## Run pytest via tox with all environments
|
|
||||||
poetry run tox
|
|
||||||
|
|
||||||
pytest: install ## Run pytest
|
|
||||||
poetry run pytest
|
|
||||||
|
|
||||||
local-test: install ## Run local_test.py to run the project locally
|
|
||||||
poetry run python3 ./local_test.py
|
|
||||||
|
|
||||||
local-diff-settings: ## Run "manage.py diffsettings" with local test
|
|
||||||
poetry run python3 local_test/opt_yunohost/manage.py diffsettings
|
|
||||||
|
|
||||||
safety: ## Run https://github.com/pyupio/safety
|
|
||||||
poetry run safety check --full-report
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
.PHONY: help check-poetry install-poetry install update local-test
|
|
|
@ -17,4 +17,4 @@ accesslog = '__LOG_FILE__'
|
||||||
errorlog = '__LOG_FILE__'
|
errorlog = '__LOG_FILE__'
|
||||||
|
|
||||||
# https://docs.gunicorn.org/en/latest/settings.html#pidfile
|
# https://docs.gunicorn.org/en/latest/settings.html#pidfile
|
||||||
pidfile = '__FINALPATH__/gunicorn.pid'
|
pidfile = '__DATA_DIR__/gunicorn.pid' # /home/yunohost.app/$app/gunicorn.pid
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!__FINALPATH__/venv/bin/python
|
#!__DATA_DIR__/venv/bin/python
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
|
||||||
location __PATH__/static/ {
|
location __PATH__/static/ {
|
||||||
# Service static files by nginx
|
# Service static files by nginx
|
||||||
# e.g.: /var/www/$app/static
|
# e.g.: /var/www/$app/static/
|
||||||
alias __PUBLIC_PATH__/static/;
|
alias __INSTALL_DIR__/static/;
|
||||||
expires 30d;
|
expires 30d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
# Please do not modify this file, it will be reset at the next update.
|
# Please do not modify this file, it will be reset at the next update.
|
||||||
# You can edit the file __FINALPATH__/local_settings.py and add/modify the settings you need.
|
# You can edit the file __DATA_DIR__/local_settings.py and add/modify the settings you need.
|
||||||
# The parameters you add in local_settings.py will overwrite these,
|
# The parameters you add in local_settings.py will overwrite these,
|
||||||
# but you can use the options and documentation in this file to find out what can be done.
|
# but you can use the options and documentation in this file to find out what can be done.
|
||||||
|
|
||||||
|
@ -22,16 +22,16 @@ from for_runners_project.settings.prod import * # noqa:F401,F403 isort:skip
|
||||||
from django_yunohost_integration.base_settings import LOGGING # noqa:F401 isort:skip
|
from django_yunohost_integration.base_settings import LOGGING # noqa:F401 isort:skip
|
||||||
|
|
||||||
|
|
||||||
FINALPATH = __Path('__FINALPATH__') # /opt/yunohost/$app
|
DATA_DIR_PATH = __Path('__DATA_DIR__') # /home/yunohost.app/$app/
|
||||||
assert FINALPATH.is_dir(), f'Directory not exists: {FINALPATH}'
|
assert DATA_DIR_PATH.is_dir(), f'Directory not exists: {DATA_DIR_PATH}'
|
||||||
|
|
||||||
PUBLIC_PATH = __Path('__PUBLIC_PATH__') # /var/www/$app
|
INSTALL_DIR_PATH = __Path('__INSTALL_DIR__') # /var/www/$app/
|
||||||
assert PUBLIC_PATH.is_dir(), f'Directory not exists: {PUBLIC_PATH}'
|
assert INSTALL_DIR_PATH.is_dir(), f'Directory not exists: {INSTALL_DIR_PATH}'
|
||||||
|
|
||||||
LOG_FILE = __Path('__LOG_FILE__') # /var/log/$app/for_runners_ynh.log
|
LOG_FILE_PATH = __Path('__LOG_FILE__') # /var/log/$app/for_runners_ynh.log
|
||||||
assert LOG_FILE.is_file(), f'File not exists: {LOG_FILE}'
|
assert LOG_FILE_PATH.is_file(), f'File not exists: {LOG_FILE_PATH}'
|
||||||
|
|
||||||
PATH_URL = '__PATH_URL__' # $YNH_APP_ARG_PATH
|
PATH_URL = '__PATH__'
|
||||||
PATH_URL = PATH_URL.strip('/')
|
PATH_URL = PATH_URL.strip('/')
|
||||||
|
|
||||||
YNH_CURRENT_HOST = '__YNH_CURRENT_HOST__' # YunoHost main domain from: /etc/yunohost/current_host
|
YNH_CURRENT_HOST = '__YNH_CURRENT_HOST__' # YunoHost main domain from: /etc/yunohost/current_host
|
||||||
|
@ -40,7 +40,7 @@ YNH_CURRENT_HOST = '__YNH_CURRENT_HOST__' # YunoHost main domain from: /etc/yun
|
||||||
# config_panel.toml settings:
|
# config_panel.toml settings:
|
||||||
|
|
||||||
DEBUG_ENABLED = '__DEBUG_ENABLED__'
|
DEBUG_ENABLED = '__DEBUG_ENABLED__'
|
||||||
DEBUG = bool(int(DEBUG_ENABLED))
|
DEBUG = DEBUG_ENABLED == 'YES'
|
||||||
|
|
||||||
LOG_LEVEL = '__LOG_LEVEL__'
|
LOG_LEVEL = '__LOG_LEVEL__'
|
||||||
ADMIN_EMAIL = '__ADMIN_EMAIL__'
|
ADMIN_EMAIL = '__ADMIN_EMAIL__'
|
||||||
|
@ -52,8 +52,6 @@ DEFAULT_FROM_EMAIL = '__DEFAULT_FROM_EMAIL__'
|
||||||
# Function that will be called to finalize a user profile:
|
# Function that will be called to finalize a user profile:
|
||||||
YNH_SETUP_USER = 'setup_user.setup_project_user'
|
YNH_SETUP_USER = 'setup_user.setup_project_user'
|
||||||
|
|
||||||
SECRET_KEY = __get_or_create_secret(FINALPATH / 'secret.txt') # /opt/yunohost/$app/secret.txt
|
|
||||||
|
|
||||||
|
|
||||||
if 'axes' not in INSTALLED_APPS:
|
if 'axes' not in INSTALLED_APPS:
|
||||||
INSTALLED_APPS.append('axes') # https://github.com/jazzband/django-axes
|
INSTALLED_APPS.append('axes') # https://github.com/jazzband/django-axes
|
||||||
|
@ -61,6 +59,9 @@ if 'axes' not in INSTALLED_APPS:
|
||||||
INSTALLED_APPS.append('django_yunohost_integration.apps.YunohostIntegrationConfig')
|
INSTALLED_APPS.append('django_yunohost_integration.apps.YunohostIntegrationConfig')
|
||||||
|
|
||||||
|
|
||||||
|
SECRET_KEY = __get_or_create_secret(DATA_DIR_PATH / 'secret.txt') # /home/yunohost.app/$app/secret.txt
|
||||||
|
|
||||||
|
|
||||||
MIDDLEWARE.insert(
|
MIDDLEWARE.insert(
|
||||||
MIDDLEWARE.index('django.contrib.auth.middleware.AuthenticationMiddleware') + 1,
|
MIDDLEWARE.index('django.contrib.auth.middleware.AuthenticationMiddleware') + 1,
|
||||||
# login a user via HTTP_REMOTE_USER header from SSOwat:
|
# login a user via HTTP_REMOTE_USER header from SSOwat:
|
||||||
|
@ -154,14 +155,14 @@ else:
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
MEDIA_URL = '/media/'
|
MEDIA_URL = '/media/'
|
||||||
|
|
||||||
STATIC_ROOT = str(PUBLIC_PATH / 'static')
|
STATIC_ROOT = str(INSTALL_DIR_PATH / 'static')
|
||||||
MEDIA_ROOT = str(PUBLIC_PATH / 'media')
|
MEDIA_ROOT = str(INSTALL_DIR_PATH / 'media')
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
# Set log file to e.g.: /var/log/$app/$app.log
|
# Set log file to e.g.: /var/log/$app/$app.log
|
||||||
LOGGING['handlers']['log_file']['filename'] = str(LOG_FILE)
|
LOGGING['handlers']['log_file']['filename'] = str(LOG_FILE_PATH)
|
||||||
|
|
||||||
# Example how to add logging to own app:
|
# Example how to add logging to own app:
|
||||||
LOGGING['loggers']['for_runners'] = {
|
LOGGING['loggers']['for_runners'] = {
|
||||||
|
|
|
@ -5,9 +5,9 @@ After=redis.service postgresql.service
|
||||||
[Service]
|
[Service]
|
||||||
User=__APP__
|
User=__APP__
|
||||||
Group=__APP__
|
Group=__APP__
|
||||||
WorkingDirectory=__FINALPATH__/
|
WorkingDirectory=__DATA_DIR__/
|
||||||
|
|
||||||
ExecStart=__FINALPATH__/venv/bin/gunicorn --config __FINALPATH__/gunicorn.conf.py wsgi
|
ExecStart=__DATA_DIR__/venv/bin/gunicorn --config __DATA_DIR__/gunicorn.conf.py wsgi
|
||||||
|
|
||||||
StandardOutput=syslog
|
StandardOutput=syslog
|
||||||
StandardError=syslog
|
StandardError=syslog
|
||||||
|
|
|
@ -6,7 +6,7 @@ from for_runners.views.media_files import UserMediaView
|
||||||
|
|
||||||
|
|
||||||
if settings.PATH_URL:
|
if settings.PATH_URL:
|
||||||
# settings.PATH_URL is the $YNH_APP_ARG_PATH
|
# settings.PATH_URL is __PATH__
|
||||||
# Prefix all urls with "PATH_URL":
|
# Prefix all urls with "PATH_URL":
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path(f'{settings.PATH_URL}/media/<slug:user_name>/<path:path>', UserMediaView.as_view()),
|
path(f'{settings.PATH_URL}/media/<slug:user_name>/<path:path>', UserMediaView.as_view()),
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# https://yunohost.org/en/packaging_config_panels
|
||||||
# https://github.com/YunoHost/example_ynh/blob/master/config_panel.toml.example
|
# https://github.com/YunoHost/example_ynh/blob/master/config_panel.toml.example
|
||||||
|
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
|
@ -14,13 +15,16 @@ services = ["__APP__"]
|
||||||
ask = "from email"
|
ask = "from email"
|
||||||
type = "email"
|
type = "email"
|
||||||
help = "Default email address to use for various automated emails."
|
help = "Default email address to use for various automated emails."
|
||||||
bind = "default_from_email:__FINALPATH__/settings.py"
|
#
|
||||||
|
# We can't use "__DATA_DIR__" in bind value, because of this bug:
|
||||||
|
# https://github.com/YunoHost/issues/issues/2283
|
||||||
|
bind = "default_from_email:/home/yunohost.app/__APP__/settings.py"
|
||||||
|
|
||||||
[main.config.admin_email]
|
[main.config.admin_email]
|
||||||
ask = "ADMIN email"
|
ask = "ADMIN email"
|
||||||
type = "email"
|
type = "email"
|
||||||
help = "EMail address for error emails."
|
help = "EMail address for error emails."
|
||||||
bind = "admin_email:__FINALPATH__/settings.py"
|
bind = "admin_email:/home/yunohost.app/__APP__/settings.py"
|
||||||
|
|
||||||
[main.config.debug_enabled]
|
[main.config.debug_enabled]
|
||||||
ask = "DEBUG mode"
|
ask = "DEBUG mode"
|
||||||
|
@ -28,11 +32,11 @@ services = ["__APP__"]
|
||||||
yes = "1"
|
yes = "1"
|
||||||
no = "0"
|
no = "0"
|
||||||
help = "Should be never enabled in production!"
|
help = "Should be never enabled in production!"
|
||||||
bind = "debug_enabled:__FINALPATH__/settings.py"
|
bind = "debug_enabled:/home/yunohost.app/__APP__/settings.py"
|
||||||
|
|
||||||
[main.config.log_level]
|
[main.config.log_level]
|
||||||
type = "string"
|
type = "string"
|
||||||
ask = "Log Level"
|
ask = "Log Level"
|
||||||
choices = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
choices = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
||||||
default = "WARNING"
|
default = "WARNING"
|
||||||
bind = "log_level:__FINALPATH__/settings.py"
|
bind = "log_level:/home/yunohost.app/__APP__/settings.py"
|
||||||
|
|
115
dev-cli.py
Executable file
115
dev-cli.py
Executable file
|
@ -0,0 +1,115 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
"""
|
||||||
|
bootstrap CLI
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Just call this file, and the magic happens ;)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import venv
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def print_no_pip_error():
|
||||||
|
print('Error: Pip not available!')
|
||||||
|
print('Hint: "apt-get install python3-venv"\n')
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from ensurepip import version
|
||||||
|
except ModuleNotFoundError as err:
|
||||||
|
print(err)
|
||||||
|
print('-' * 100)
|
||||||
|
print_no_pip_error()
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
if not version():
|
||||||
|
print_no_pip_error()
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
|
||||||
|
assert sys.version_info >= (3, 9), 'Python version is too old!'
|
||||||
|
|
||||||
|
|
||||||
|
if sys.platform == 'win32': # wtf
|
||||||
|
# Files under Windows, e.g.: .../.venv/Scripts/python.exe
|
||||||
|
BIN_NAME = 'Scripts'
|
||||||
|
FILE_EXT = '.exe'
|
||||||
|
else:
|
||||||
|
# Files under Linux/Mac and all other than Windows, e.g.: .../.venv/bin/python
|
||||||
|
BIN_NAME = 'bin'
|
||||||
|
FILE_EXT = ''
|
||||||
|
|
||||||
|
BASE_PATH = Path(__file__).parent
|
||||||
|
VENV_PATH = BASE_PATH / '.venv'
|
||||||
|
BIN_PATH = VENV_PATH / BIN_NAME
|
||||||
|
PYTHON_PATH = BIN_PATH / f'python{FILE_EXT}'
|
||||||
|
PIP_PATH = BIN_PATH / f'pip{FILE_EXT}'
|
||||||
|
PIP_SYNC_PATH = BIN_PATH / f'pip-sync{FILE_EXT}'
|
||||||
|
|
||||||
|
DEP_LOCK_PATH = BASE_PATH / 'requirements.dev.txt'
|
||||||
|
DEP_HASH_PATH = VENV_PATH / '.dep_hash'
|
||||||
|
|
||||||
|
# script file defined in pyproject.toml as [console_scripts]
|
||||||
|
# (Under Windows: ".exe" not added!)
|
||||||
|
PROJECT_SHELL_SCRIPT = BIN_PATH / 'for_runners_ynh_dev'
|
||||||
|
|
||||||
|
|
||||||
|
def get_dep_hash():
|
||||||
|
"""Get SHA512 hash from lock file content."""
|
||||||
|
return hashlib.sha512(DEP_LOCK_PATH.read_bytes()).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def store_dep_hash():
|
||||||
|
"""Generate .venv/.dep_hash"""
|
||||||
|
DEP_HASH_PATH.write_text(get_dep_hash())
|
||||||
|
|
||||||
|
|
||||||
|
def venv_up2date():
|
||||||
|
"""Is existing .venv is up-to-date?"""
|
||||||
|
if DEP_HASH_PATH.is_file():
|
||||||
|
return DEP_HASH_PATH.read_text() == get_dep_hash()
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def verbose_check_call(*popen_args):
|
||||||
|
print(f'\n+ {" ".join(str(arg) for arg in popen_args)}\n')
|
||||||
|
return subprocess.check_call(popen_args)
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
assert DEP_LOCK_PATH.is_file(), f'File not found: "{DEP_LOCK_PATH}" !'
|
||||||
|
|
||||||
|
# Create virtual env in ".venv/":
|
||||||
|
if not PYTHON_PATH.is_file():
|
||||||
|
print('Create virtual env here:', VENV_PATH.absolute())
|
||||||
|
builder = venv.EnvBuilder(symlinks=True, upgrade=True, with_pip=True)
|
||||||
|
builder.create(env_dir=VENV_PATH)
|
||||||
|
# Update pip
|
||||||
|
verbose_check_call(PYTHON_PATH, '-m', 'pip', 'install', '-U', 'pip')
|
||||||
|
|
||||||
|
if not PIP_SYNC_PATH.is_file():
|
||||||
|
# Install pip-tools
|
||||||
|
verbose_check_call(PYTHON_PATH, '-m', 'pip', 'install', '-U', 'pip-tools')
|
||||||
|
|
||||||
|
if not PROJECT_SHELL_SCRIPT.is_file() or not venv_up2date():
|
||||||
|
# install requirements via "pip-sync"
|
||||||
|
verbose_check_call(PIP_SYNC_PATH, str(DEP_LOCK_PATH))
|
||||||
|
|
||||||
|
# install project
|
||||||
|
verbose_check_call(PIP_PATH, 'install', '--no-deps', '-e', '.')
|
||||||
|
store_dep_hash()
|
||||||
|
|
||||||
|
# Call our entry point CLI:
|
||||||
|
try:
|
||||||
|
verbose_check_call(PROJECT_SHELL_SCRIPT, *argv[1:])
|
||||||
|
except subprocess.CalledProcessError as err:
|
||||||
|
sys.exit(err.returncode)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main(sys.argv)
|
7
for_runners_ynh/__init__.py
Normal file
7
for_runners_ynh/__init__.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
"""
|
||||||
|
for_runners_ynh
|
||||||
|
YunoHost app package for https://github.com/jedie/django-for-runners
|
||||||
|
"""
|
||||||
|
|
||||||
|
__version__ = '0.17.4+ynh1'
|
||||||
|
__author__ = 'Jens Diemer <git@jensdiemer.de>'
|
0
for_runners_ynh/cli/__init__.py
Normal file
0
for_runners_ynh/cli/__init__.py
Normal file
368
for_runners_ynh/cli/dev.py
Normal file
368
for_runners_ynh/cli/dev.py
Normal file
|
@ -0,0 +1,368 @@
|
||||||
|
"""
|
||||||
|
CLI for development
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import rich_click as click
|
||||||
|
from bx_py_utils.path import assert_is_file
|
||||||
|
from cli_base.cli_tools.subprocess_utils import verbose_check_call
|
||||||
|
from cli_base.cli_tools.version_info import print_version
|
||||||
|
from django_yunohost_integration.local_test import create_local_test
|
||||||
|
from manageprojects.utilities import code_style
|
||||||
|
from manageprojects.utilities.publish import publish_package
|
||||||
|
from rich import print # noqa; noqa
|
||||||
|
from rich_click import RichGroup
|
||||||
|
|
||||||
|
import for_runners_ynh
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
PACKAGE_ROOT = Path(for_runners_ynh.__file__).parent.parent
|
||||||
|
assert_is_file(PACKAGE_ROOT / 'pyproject.toml')
|
||||||
|
|
||||||
|
OPTION_ARGS_DEFAULT_TRUE = dict(is_flag=True, show_default=True, default=True)
|
||||||
|
OPTION_ARGS_DEFAULT_FALSE = dict(is_flag=True, show_default=True, default=False)
|
||||||
|
ARGUMENT_EXISTING_DIR = dict(
|
||||||
|
type=click.Path(exists=True, file_okay=False, dir_okay=True, readable=True, path_type=Path)
|
||||||
|
)
|
||||||
|
ARGUMENT_NOT_EXISTING_DIR = dict(
|
||||||
|
type=click.Path(
|
||||||
|
exists=False,
|
||||||
|
file_okay=False,
|
||||||
|
dir_okay=True,
|
||||||
|
readable=False,
|
||||||
|
writable=True,
|
||||||
|
path_type=Path,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ARGUMENT_EXISTING_FILE = dict(
|
||||||
|
type=click.Path(exists=True, file_okay=True, dir_okay=False, readable=True, path_type=Path)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ClickGroup(RichGroup): # FIXME: How to set the "info_name" easier?
|
||||||
|
def make_context(self, info_name, *args, **kwargs):
|
||||||
|
info_name = './dev-cli.py'
|
||||||
|
return super().make_context(info_name, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@click.group(
|
||||||
|
cls=ClickGroup,
|
||||||
|
epilog='Project Homepage: https://github.com/YunoHost-Apps/django-for-runners_ynh',
|
||||||
|
)
|
||||||
|
def cli():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
@click.option('--verbose/--no-verbose', **OPTION_ARGS_DEFAULT_FALSE)
|
||||||
|
def mypy(verbose: bool = True):
|
||||||
|
"""Run Mypy (configured in pyproject.toml)"""
|
||||||
|
verbose_check_call('mypy', '.', cwd=PACKAGE_ROOT, verbose=verbose, exit_on_error=True)
|
||||||
|
|
||||||
|
|
||||||
|
cli.add_command(mypy)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
@click.option('--verbose/--no-verbose', **OPTION_ARGS_DEFAULT_FALSE)
|
||||||
|
def coverage(verbose: bool = True):
|
||||||
|
"""
|
||||||
|
Run and show coverage.
|
||||||
|
"""
|
||||||
|
verbose_check_call('coverage', 'run', verbose=verbose, exit_on_error=True)
|
||||||
|
verbose_check_call('coverage', 'combine', '--append', verbose=verbose, exit_on_error=True)
|
||||||
|
verbose_check_call('coverage', 'report', '--fail-under=30', verbose=verbose, exit_on_error=True)
|
||||||
|
verbose_check_call('coverage', 'xml', verbose=verbose, exit_on_error=True)
|
||||||
|
verbose_check_call('coverage', 'json', verbose=verbose, exit_on_error=True)
|
||||||
|
|
||||||
|
|
||||||
|
cli.add_command(coverage)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
def install():
|
||||||
|
"""
|
||||||
|
Run pip-sync and install 'for_runners_ynh' via pip as editable.
|
||||||
|
"""
|
||||||
|
verbose_check_call('pip-sync', PACKAGE_ROOT / 'requirements.dev.txt')
|
||||||
|
verbose_check_call('pip', 'install', '--no-deps', '-e', '.')
|
||||||
|
|
||||||
|
|
||||||
|
cli.add_command(install)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
def safety():
|
||||||
|
"""
|
||||||
|
Run safety check against current requirements files
|
||||||
|
"""
|
||||||
|
verbose_check_call('safety', 'check', '-r', 'requirements.dev.txt')
|
||||||
|
|
||||||
|
|
||||||
|
cli.add_command(safety)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
def update():
|
||||||
|
"""
|
||||||
|
Update "requirements*.txt" dependencies files
|
||||||
|
"""
|
||||||
|
bin_path = Path(sys.executable).parent
|
||||||
|
|
||||||
|
verbose_check_call(bin_path / 'pip', 'install', '-U', 'pip')
|
||||||
|
verbose_check_call(bin_path / 'pip', 'install', '-U', 'pip-tools')
|
||||||
|
|
||||||
|
extra_env = dict(
|
||||||
|
CUSTOM_COMPILE_COMMAND='./dev-cli.py update',
|
||||||
|
)
|
||||||
|
|
||||||
|
pip_compile_base = [
|
||||||
|
bin_path / 'pip-compile',
|
||||||
|
'--verbose',
|
||||||
|
'--allow-unsafe', # https://pip-tools.readthedocs.io/en/latest/#deprecations
|
||||||
|
'--resolver=backtracking', # https://pip-tools.readthedocs.io/en/latest/#deprecations
|
||||||
|
'--upgrade',
|
||||||
|
'--generate-hashes',
|
||||||
|
]
|
||||||
|
|
||||||
|
# Only "prod" dependencies:
|
||||||
|
verbose_check_call(
|
||||||
|
*pip_compile_base,
|
||||||
|
'pyproject.toml',
|
||||||
|
'--output-file',
|
||||||
|
'conf/requirements.txt',
|
||||||
|
extra_env=extra_env,
|
||||||
|
)
|
||||||
|
|
||||||
|
# dependencies + "dev"-optional-dependencies:
|
||||||
|
verbose_check_call(
|
||||||
|
*pip_compile_base,
|
||||||
|
'pyproject.toml',
|
||||||
|
'--extra=dev',
|
||||||
|
'--output-file',
|
||||||
|
'requirements.dev.txt',
|
||||||
|
extra_env=extra_env,
|
||||||
|
)
|
||||||
|
|
||||||
|
verbose_check_call(bin_path / 'safety', 'check', '-r', 'requirements.dev.txt')
|
||||||
|
|
||||||
|
# Install new dependencies in current .venv:
|
||||||
|
verbose_check_call(bin_path / 'pip-sync', 'requirements.dev.txt')
|
||||||
|
|
||||||
|
|
||||||
|
cli.add_command(update)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
def publish():
|
||||||
|
"""
|
||||||
|
Build and upload this project to PyPi
|
||||||
|
"""
|
||||||
|
_run_unittest_cli(verbose=False, exit_after_run=False) # Don't publish a broken state
|
||||||
|
|
||||||
|
publish_package(
|
||||||
|
module=for_runners_ynh,
|
||||||
|
package_path=PACKAGE_ROOT,
|
||||||
|
distribution_name='for_runners_ynh',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
cli.add_command(publish)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
@click.option('--color/--no-color', **OPTION_ARGS_DEFAULT_TRUE)
|
||||||
|
@click.option('--verbose/--no-verbose', **OPTION_ARGS_DEFAULT_FALSE)
|
||||||
|
def fix_code_style(color: bool = True, verbose: bool = False):
|
||||||
|
"""
|
||||||
|
Fix code style of all for_runners_ynh source code files via darker
|
||||||
|
"""
|
||||||
|
code_style.fix(package_root=PACKAGE_ROOT, color=color, verbose=verbose)
|
||||||
|
|
||||||
|
|
||||||
|
cli.add_command(fix_code_style)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
@click.option('--color/--no-color', **OPTION_ARGS_DEFAULT_TRUE)
|
||||||
|
@click.option('--verbose/--no-verbose', **OPTION_ARGS_DEFAULT_FALSE)
|
||||||
|
def check_code_style(color: bool = True, verbose: bool = False):
|
||||||
|
"""
|
||||||
|
Check code style by calling darker + flake8
|
||||||
|
"""
|
||||||
|
code_style.check(package_root=PACKAGE_ROOT, color=color, verbose=verbose)
|
||||||
|
|
||||||
|
|
||||||
|
cli.add_command(check_code_style)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
def update_test_snapshot_files():
|
||||||
|
"""
|
||||||
|
Update all test snapshot files (by remove and recreate all snapshot files)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def iter_snapshot_files():
|
||||||
|
yield from PACKAGE_ROOT.rglob('*.snapshot.*')
|
||||||
|
|
||||||
|
removed_file_count = 0
|
||||||
|
for item in iter_snapshot_files():
|
||||||
|
item.unlink()
|
||||||
|
removed_file_count += 1
|
||||||
|
print(f'{removed_file_count} test snapshot files removed... run tests...')
|
||||||
|
|
||||||
|
# Just recreate them by running tests:
|
||||||
|
_run_unittest_cli(
|
||||||
|
extra_env=dict(
|
||||||
|
RAISE_SNAPSHOT_ERRORS='0', # Recreate snapshot files without error
|
||||||
|
),
|
||||||
|
verbose=False,
|
||||||
|
exit_after_run=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
new_files = len(list(iter_snapshot_files()))
|
||||||
|
print(f'{new_files} test snapshot files created, ok.\n')
|
||||||
|
|
||||||
|
|
||||||
|
cli.add_command(update_test_snapshot_files)
|
||||||
|
|
||||||
|
|
||||||
|
def _run_unittest_cli(extra_env=None, verbose=True, exit_after_run=True):
|
||||||
|
"""
|
||||||
|
Call the origin unittest CLI and pass all args to it.
|
||||||
|
"""
|
||||||
|
if extra_env is None:
|
||||||
|
extra_env = dict()
|
||||||
|
|
||||||
|
extra_env.update(
|
||||||
|
dict(
|
||||||
|
PYTHONUNBUFFERED='1',
|
||||||
|
PYTHONWARNINGS='always',
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
args = sys.argv[2:]
|
||||||
|
if not args:
|
||||||
|
if verbose:
|
||||||
|
args = ('--verbose', '--locals', '--buffer')
|
||||||
|
else:
|
||||||
|
args = ('--locals', '--buffer')
|
||||||
|
|
||||||
|
verbose_check_call(
|
||||||
|
sys.executable,
|
||||||
|
'-m',
|
||||||
|
'unittest',
|
||||||
|
*args,
|
||||||
|
timeout=15 * 60,
|
||||||
|
extra_env=extra_env,
|
||||||
|
)
|
||||||
|
if exit_after_run:
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command() # Dummy command
|
||||||
|
def test():
|
||||||
|
"""
|
||||||
|
Run unittests
|
||||||
|
"""
|
||||||
|
_run_unittest_cli()
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: Replace pytest with normal Django unittests:
|
||||||
|
# cli.add_command(test)
|
||||||
|
|
||||||
|
|
||||||
|
def _run_tox():
|
||||||
|
verbose_check_call(sys.executable, '-m', 'tox', *sys.argv[2:])
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command() # Dummy "tox" command
|
||||||
|
def tox():
|
||||||
|
"""
|
||||||
|
Run tox
|
||||||
|
"""
|
||||||
|
_run_tox()
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: cli.add_command(tox)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
def version():
|
||||||
|
"""Print version and exit"""
|
||||||
|
# Pseudo command, because the version always printed on every CLI call ;)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
cli.add_command(version)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
def local_test():
|
||||||
|
"""
|
||||||
|
Build a "local_test" YunoHost installation and start the Django dev. server against it.
|
||||||
|
"""
|
||||||
|
create_local_test(
|
||||||
|
django_settings_path=PACKAGE_ROOT / 'conf' / 'settings.py',
|
||||||
|
destination=PACKAGE_ROOT / 'local_test',
|
||||||
|
runserver=True,
|
||||||
|
extra_replacements={
|
||||||
|
'__DEBUG_ENABLED__': '1',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
cli.add_command(local_test)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
def diffsettings():
|
||||||
|
"""
|
||||||
|
Run "diffsettings" manage command against a "local_test" YunoHost installation.
|
||||||
|
"""
|
||||||
|
destination = PACKAGE_ROOT / 'local_test'
|
||||||
|
create_local_test(
|
||||||
|
django_settings_path=PACKAGE_ROOT / 'conf' / 'settings.py',
|
||||||
|
destination=destination,
|
||||||
|
runserver=False,
|
||||||
|
extra_replacements={
|
||||||
|
'__DEBUG_ENABLED__': '1',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
app_path = destination / 'opt_yunohost'
|
||||||
|
verbose_check_call(sys.executable, app_path / 'manage.py', 'diffsettings', cwd=app_path)
|
||||||
|
|
||||||
|
|
||||||
|
cli.add_command(diffsettings)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
def pytest():
|
||||||
|
"""
|
||||||
|
Run tests via "pytest"
|
||||||
|
"""
|
||||||
|
verbose_check_call(sys.executable, '-m', 'pytest', *sys.argv[2:], cwd=PACKAGE_ROOT)
|
||||||
|
|
||||||
|
|
||||||
|
cli.add_command(pytest)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print_version(for_runners_ynh)
|
||||||
|
|
||||||
|
if len(sys.argv) >= 2:
|
||||||
|
# Check if we just pass a command call
|
||||||
|
command = sys.argv[1]
|
||||||
|
if command == 'test':
|
||||||
|
_run_unittest_cli()
|
||||||
|
elif command == 'tox':
|
||||||
|
_run_tox()
|
||||||
|
|
||||||
|
# Execute Click CLI:
|
||||||
|
cli()
|
6
for_runners_ynh/tests/__init__.py
Normal file
6
for_runners_ynh/tests/__init__.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import os
|
||||||
|
import unittest.util
|
||||||
|
|
||||||
|
|
||||||
|
# Hacky way to expand the failed test output:
|
||||||
|
unittest.util._MAX_LENGTH = os.environ.get('UNITTEST_MAX_LENGTH', 300)
|
10
for_runners_ynh/tests/test_doctests.py
Normal file
10
for_runners_ynh/tests/test_doctests.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
from bx_py_utils.test_utils.unittest_utils import BaseDocTests
|
||||||
|
|
||||||
|
import for_runners_ynh
|
||||||
|
|
||||||
|
|
||||||
|
class DocTests(BaseDocTests):
|
||||||
|
def test_doctests(self):
|
||||||
|
self.run_doctests(
|
||||||
|
modules=(for_runners_ynh,),
|
||||||
|
)
|
68
for_runners_ynh/tests/test_project_setup.py
Normal file
68
for_runners_ynh/tests/test_project_setup.py
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
import subprocess
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
from bx_py_utils.path import assert_is_file
|
||||||
|
from manageprojects.test_utils.click_cli_utils import subprocess_cli
|
||||||
|
from manageprojects.test_utils.project_setup import check_editor_config, get_py_max_line_length
|
||||||
|
from manageprojects.utilities import code_style
|
||||||
|
from packaging.version import Version
|
||||||
|
|
||||||
|
from for_runners_ynh import __version__
|
||||||
|
from for_runners_ynh.cli.dev import PACKAGE_ROOT
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectSetupTestCase(TestCase):
|
||||||
|
def test_version(self):
|
||||||
|
self.assertIsNotNone(__version__)
|
||||||
|
|
||||||
|
version = Version(__version__) # Will raise InvalidVersion() if wrong formatted
|
||||||
|
self.assertEqual(str(version), __version__)
|
||||||
|
|
||||||
|
dev_cli_bin = PACKAGE_ROOT / 'dev-cli.py'
|
||||||
|
assert_is_file(dev_cli_bin)
|
||||||
|
|
||||||
|
output = subprocess.check_output([dev_cli_bin, 'version'], text=True)
|
||||||
|
self.assertIn(f'for_runners_ynh v{__version__}', output)
|
||||||
|
|
||||||
|
def test_code_style(self):
|
||||||
|
dev_cli_bin = PACKAGE_ROOT / 'dev-cli.py'
|
||||||
|
assert_is_file(dev_cli_bin)
|
||||||
|
|
||||||
|
try:
|
||||||
|
output = subprocess_cli(
|
||||||
|
cli_bin=dev_cli_bin,
|
||||||
|
args=('check-code-style',),
|
||||||
|
exit_on_error=False,
|
||||||
|
)
|
||||||
|
except subprocess.CalledProcessError as err:
|
||||||
|
self.assertIn('.venv/bin/darker', err.stdout) # darker was called?
|
||||||
|
else:
|
||||||
|
if 'Code style: OK' in output:
|
||||||
|
self.assertIn('.venv/bin/darker', output) # darker was called?
|
||||||
|
return # Nothing to fix -> OK
|
||||||
|
|
||||||
|
# Try to "auto" fix code style:
|
||||||
|
|
||||||
|
try:
|
||||||
|
output = subprocess_cli(
|
||||||
|
cli_bin=dev_cli_bin,
|
||||||
|
args=('fix-code-style',),
|
||||||
|
exit_on_error=False,
|
||||||
|
)
|
||||||
|
except subprocess.CalledProcessError as err:
|
||||||
|
output = err.stdout
|
||||||
|
|
||||||
|
self.assertIn('.venv/bin/darker', output) # darker was called?
|
||||||
|
|
||||||
|
# Check again and display the output:
|
||||||
|
|
||||||
|
try:
|
||||||
|
code_style.check(package_root=PACKAGE_ROOT)
|
||||||
|
except SystemExit as err:
|
||||||
|
self.assertEqual(err.code, 0, 'Code style error, see output above!')
|
||||||
|
|
||||||
|
def test_check_editor_config(self):
|
||||||
|
check_editor_config(package_root=PACKAGE_ROOT)
|
||||||
|
|
||||||
|
max_line_length = get_py_max_line_length(package_root=PACKAGE_ROOT)
|
||||||
|
self.assertEqual(max_line_length, 119)
|
|
@ -1,32 +0,0 @@
|
||||||
"""
|
|
||||||
Build a "local_test" YunoHost installation and start the Django dev. server against it.
|
|
||||||
|
|
||||||
Run via:
|
|
||||||
make local-test
|
|
||||||
|
|
||||||
see README for details ;)
|
|
||||||
"""
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
from django_yunohost_integration.local_test import create_local_test
|
|
||||||
except ImportError as err:
|
|
||||||
raise ImportError('Did you forget to activate a virtual environment?') from err
|
|
||||||
|
|
||||||
BASE_PATH = Path(__file__).parent
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
create_local_test(
|
|
||||||
django_settings_path=BASE_PATH / 'conf' / 'settings.py',
|
|
||||||
destination=BASE_PATH / 'local_test',
|
|
||||||
runserver=True,
|
|
||||||
extra_replacements={
|
|
||||||
'__DEBUG_ENABLED__': '1',
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
|
@ -1,56 +0,0 @@
|
||||||
{
|
|
||||||
"name": "django-for-runners",
|
|
||||||
"id": "django-for-runners",
|
|
||||||
"packaging_format": 1,
|
|
||||||
"description": {
|
|
||||||
"en": "Store your GPX tracks of your running (or other sports activity)"
|
|
||||||
},
|
|
||||||
"version": "0.17.3~ynh3",
|
|
||||||
"url": "https://github.com/jedie/django-for-runners",
|
|
||||||
"upstream": {
|
|
||||||
"license": "GPL-3.0",
|
|
||||||
"admindoc": "https://github.com/YunoHost-Apps/django-for-runners_ynh",
|
|
||||||
"userdoc": "https://github.com/jedie/django-for-runners",
|
|
||||||
"code": "https://github.com/jedie/django-for-runners"
|
|
||||||
},
|
|
||||||
"license": "GPL-3.0-or-later",
|
|
||||||
"maintainer": {
|
|
||||||
"name": "Jens Diemer",
|
|
||||||
"email": "django-for-runners_ynh@jensdiemer.de"
|
|
||||||
},
|
|
||||||
"previous_maintainers": [],
|
|
||||||
"requirements": {
|
|
||||||
"yunohost": ">=11"
|
|
||||||
},
|
|
||||||
"multi_instance": true,
|
|
||||||
"services": [
|
|
||||||
"nginx", "postgresql", "redis"
|
|
||||||
],
|
|
||||||
"arguments": {
|
|
||||||
"install" : [
|
|
||||||
{
|
|
||||||
"name": "domain",
|
|
||||||
"type": "domain"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "path",
|
|
||||||
"type": "path",
|
|
||||||
"example": "/django-for-runners",
|
|
||||||
"default": "/django-for-runners"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "admin",
|
|
||||||
"type": "user"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "is_public",
|
|
||||||
"type": "boolean",
|
|
||||||
"help": {
|
|
||||||
"en": "Any YunoHost user and anonymous people from the web will be able to access the application",
|
|
||||||
"fr": "Tout utilisateur YunoHost et les personnes anonymes pourront accéder à l'application"
|
|
||||||
},
|
|
||||||
"default": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
110
manifest.toml
Normal file
110
manifest.toml
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
# https://yunohost.org/en/packaging_manifest
|
||||||
|
packaging_format = 2
|
||||||
|
|
||||||
|
id = "django-for-runners"
|
||||||
|
name = "django-for-runners"
|
||||||
|
description.en = "YunoHost app package for https://github.com/jedie/django-for-runners"
|
||||||
|
|
||||||
|
version = "0.17.4~ynh1"
|
||||||
|
|
||||||
|
maintainers = ["Jens Diemer"]
|
||||||
|
|
||||||
|
|
||||||
|
[upstream]
|
||||||
|
# https://yunohost.org/en/packaging_manifest#upstream-section
|
||||||
|
license = "GPL-3.0-or-later"
|
||||||
|
website = "https://github.com/YunoHost-Apps/django-for-runners_ynh"
|
||||||
|
admindoc = "https://github.com/YunoHost-Apps/django-for-runners_ynh"
|
||||||
|
userdoc = "https://github.com/jedie/django-for-runners"
|
||||||
|
code = "https://github.com/YunoHost-Apps/django-for-runners_ynh"
|
||||||
|
|
||||||
|
|
||||||
|
[integration]
|
||||||
|
# https://yunohost.org/en/packaging_manifest#integration-section
|
||||||
|
yunohost = ">=11"
|
||||||
|
architectures = "all"
|
||||||
|
multi_instance = true
|
||||||
|
ldap = true
|
||||||
|
sso = true
|
||||||
|
disk = "50M" # **estimate** minimum disk requirement. e.g. 20M, 400M, 1G, ...
|
||||||
|
ram.build = "50M" # **estimate** minimum ram requirement. e.g. 50M, 400M, 1G, ...
|
||||||
|
ram.runtime = "50M" # **estimate** minimum ram requirement. e.g. 50M, 400M, 1G, ...
|
||||||
|
|
||||||
|
|
||||||
|
[install]
|
||||||
|
[install.domain]
|
||||||
|
# this is a generic question - ask strings are automatically handled by Yunohost's core
|
||||||
|
type = "domain"
|
||||||
|
|
||||||
|
[install.path]
|
||||||
|
# this is a generic question - ask strings are automatically handled by Yunohost's core
|
||||||
|
# setting $path and template variable __PATH__
|
||||||
|
type = "path"
|
||||||
|
default = "/for_runners_ynh"
|
||||||
|
|
||||||
|
[install.admin]
|
||||||
|
# this is a generic question - ask strings are automatically handled by Yunohost's core
|
||||||
|
type = "user"
|
||||||
|
default = "admin"
|
||||||
|
|
||||||
|
[install.init_main_permission]
|
||||||
|
type = "group"
|
||||||
|
default = "admins"
|
||||||
|
|
||||||
|
[install.default_from_email] # __DEFAULT_FROM_EMAIL__
|
||||||
|
ask.en = "Default email address to use for various automated emails."
|
||||||
|
type = "email"
|
||||||
|
example = "admin@example.com"
|
||||||
|
|
||||||
|
[install.admin_email] # __ADMIN_EMAIL__
|
||||||
|
ask.en = "EMail address for error emails."
|
||||||
|
type = "email"
|
||||||
|
example = "admin@example.com"
|
||||||
|
|
||||||
|
[install.debug_enabled] # __DEBUG_ENABLED__
|
||||||
|
ask.en = "Should be never enabled in production!"
|
||||||
|
type = "select"
|
||||||
|
choices = ["YES", "NO"]
|
||||||
|
default = "NO"
|
||||||
|
|
||||||
|
[install.log_level] # __LOG_LEVEL__
|
||||||
|
ask.en = "Logging level"
|
||||||
|
type = "select"
|
||||||
|
choices = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
||||||
|
default = "WARNING"
|
||||||
|
|
||||||
|
|
||||||
|
[resources]
|
||||||
|
[resources.system_user]
|
||||||
|
# This will provision/deprovision a unix system user
|
||||||
|
|
||||||
|
[resources.install_dir]
|
||||||
|
# https://yunohost.org/en/packaging_apps_resources#install-dir
|
||||||
|
# This will create/remove the install dir as /var/www/$app/
|
||||||
|
# and store the corresponding setting $install_dir and template variable __INSTALL_DIR__
|
||||||
|
|
||||||
|
[resources.data_dir]
|
||||||
|
# https://yunohost.org/en/packaging_apps_resources#data-dir
|
||||||
|
# This will create/remove the data dir as /home/yunohost.app/$app/
|
||||||
|
# and store the corresponding setting $data_dir and template variable __DATA_DIR__
|
||||||
|
|
||||||
|
[resources.permissions]
|
||||||
|
# https://yunohost.org/en/packaging_apps_resources#permissions
|
||||||
|
# This will configure SSOwat permission for $domain/$path/
|
||||||
|
# The initial allowed group of user is configured via the init_main_permission question (public=visitors, private=all_users)
|
||||||
|
main.url = "/"
|
||||||
|
|
||||||
|
[resources.ports]
|
||||||
|
# https://yunohost.org/en/packaging_apps_resources#ports
|
||||||
|
# This will pick a random port for reverse-proxying and store it as the $port setting
|
||||||
|
|
||||||
|
[resources.apt]
|
||||||
|
# https://yunohost.org/en/packaging_apps_resources#apt
|
||||||
|
# This will automatically install/uninstall the following apt packages
|
||||||
|
packages = "build-essential, python3-dev, python3-pip, python3-venv, git, libpq-dev, postgresql, postgresql-contrib"
|
||||||
|
|
||||||
|
[resources.database]
|
||||||
|
# https://yunohost.org/en/packaging_apps_resources#database
|
||||||
|
# This will automatically provision/deprovison a Postgres DB
|
||||||
|
# and store the corresponding credentials in settings $db_user, $db_name, $db_pwd
|
||||||
|
type = "postgresql"
|
2715
poetry.lock
generated
2715
poetry.lock
generated
File diff suppressed because it is too large
Load diff
145
pyproject.toml
145
pyproject.toml
|
@ -1,61 +1,87 @@
|
||||||
[tool.poetry]
|
[project]
|
||||||
name = "for_runners_ynh"
|
name = "for_runners_ynh"
|
||||||
version = "0.17.3+ynh3"
|
dynamic = ["version"]
|
||||||
description = "YunoHost app package for https://github.com/jedie/django-for-runners"
|
description = "YunoHost app package for https://github.com/jedie/django-for-runners"
|
||||||
authors = ["Jens Diemer <git@jensdiemer.de>"]
|
license = {text = "GPL-3.0-or-later"}
|
||||||
homepage = "https://github.com/YunoHost-Apps/django-for-runners_ynh"
|
readme = "README.md"
|
||||||
license = "GPL-3.0-or-later"
|
authors = [
|
||||||
readme = 'README.md'
|
{name = 'Jens Diemer', email = 'git@jensdiemer.de'}
|
||||||
|
]
|
||||||
|
requires-python = ">=3.9" # Stay with 3.9 until YunoHost used >=Debian 11 (Bullseye)
|
||||||
|
dependencies = [
|
||||||
|
"django_for_runners", # https://github.com/jedie/django-for-runners
|
||||||
|
#
|
||||||
|
# extras "ynh" will install: gunicorn, psycopg2, django-redis and django-axes
|
||||||
|
# see: https://github.com/YunoHost-Apps/django_yunohost_integration/blob/main/pyproject.toml
|
||||||
|
"django_yunohost_integration[ynh]", # https://github.com/YunoHost-Apps/django_yunohost_integration
|
||||||
|
#
|
||||||
|
"cli-base-utilities", # https://github.com/jedie/cli-base-utilities
|
||||||
|
#
|
||||||
|
# indirect depencies, added because we didn't create the requirements.txt with Python <3.11
|
||||||
|
# See: https://github.com/jazzband/pip-tools/issues/1326
|
||||||
|
"async-timeout", # needed by redis for python<=3.11.2
|
||||||
|
]
|
||||||
|
[project.optional-dependencies]
|
||||||
|
dev = [
|
||||||
|
"bx_django_utils", # https://github.com/boxine/bx_django_utils
|
||||||
|
"beautifulsoup4",
|
||||||
|
#
|
||||||
|
# TODO: Remove "pytest" and use normal unittests ;)
|
||||||
|
"pytest",
|
||||||
|
"pytest-cov",
|
||||||
|
"pytest-django",
|
||||||
|
#
|
||||||
|
"manageprojects>=0.15.0", # https://github.com/jedie/manageprojects
|
||||||
|
"pip-tools", # https://github.com/jazzband/pip-tools/
|
||||||
|
"tox", # https://github.com/tox-dev/tox
|
||||||
|
"coverage", # https://github.com/nedbat/coveragepy
|
||||||
|
"autopep8", # https://github.com/hhatto/autopep8
|
||||||
|
"pyupgrade", # https://github.com/asottile/pyupgrade
|
||||||
|
"flake8", # https://github.com/pycqa/flake8
|
||||||
|
"pyflakes", # https://github.com/PyCQA/pyflakes
|
||||||
|
"codespell", # https://github.com/codespell-project/codespell
|
||||||
|
"EditorConfig", # https://github.com/editorconfig/editorconfig-core-py
|
||||||
|
"safety", # https://github.com/pyupio/safety
|
||||||
|
"mypy", # https://github.com/python/mypy
|
||||||
|
"twine", # https://github.com/pypa/twine
|
||||||
|
|
||||||
[tool.poetry.urls]
|
# https://github.com/akaihola/darker
|
||||||
"Bug Tracker" = "https://github.com/jedie/django-for-runners/issues"
|
# https://github.com/ikamensh/flynt
|
||||||
|
# https://github.com/pycqa/isort
|
||||||
|
# https://github.com/pygments/pygments
|
||||||
|
"darker[flynt, isort, color]",
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
# indirect depencies added because of bug:
|
||||||
python = ">=3.9,<4.0.0" # Stay with 3.9 until YunoHost used >=Debian 11 (Bullseye)
|
# https://github.com/pypa/pip/issues/9644 / https://github.com/jazzband/pip-tools/issues/1866
|
||||||
#
|
# to avoid errors like:
|
||||||
django_for_runners = ">=0.17.3" # https://github.com/jedie/django-for-runners
|
# In --require-hashes mode, all requirements must have their versions pinned with ==. These do not: ...
|
||||||
#
|
"tomli", # Only needed for Python <3.11
|
||||||
# extras "ynh" will install: gunicorn, psycopg2, django-redis and django-axes
|
"exceptiongroup", # needed by pytest
|
||||||
# see: https://github.com/YunoHost-Apps/django_yunohost_integration/blob/main/pyproject.toml
|
]
|
||||||
django_yunohost_integration = {version = ">=0.5.1", extras = ["ynh"]} # https://github.com/YunoHost-Apps/django_yunohost_integration
|
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
Documentation = "https://github.com/YunoHost-Apps/django-for-runners_ynh"
|
||||||
|
Source = "https://github.com/YunoHost-Apps/django-for-runners_ynh"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[project.scripts]
|
||||||
bx_py_utils = "*" # https://github.com/boxine/bx_py_utils
|
for_runners_ynh_app = "for_runners_ynh.__main__:main"
|
||||||
bx_django_utils = "*" # https://github.com/boxine/bx_django_utils
|
for_runners_ynh_dev = "for_runners_ynh.cli.dev:main"
|
||||||
tox = ">=4.4.4" # https://github.com/tox-dev/tox
|
|
||||||
coverage= "*" # https://github.com/nedbat/coveragepy
|
|
||||||
flake8 = "*" # https://github.com/pycqa/flake8
|
|
||||||
EditorConfig = "*" # https://github.com/editorconfig/editorconfig-core-py
|
|
||||||
safety = "*" # https://github.com/pyupio/safety
|
|
||||||
mypy = "*" # https://github.com/python/mypy
|
|
||||||
twine = "*" # https://github.com/pypa/twine
|
|
||||||
poetry-publish = "*" # https://github.com/jedie/poetry-publish
|
|
||||||
pytest = "*"
|
|
||||||
pytest-cov = "*"
|
|
||||||
pytest-django = "*"
|
|
||||||
requests = "*" # https://github.com/psf/requests
|
|
||||||
packaging = "*" # https://github.com/pypa/packagi
|
|
||||||
beautifulsoup4 = "*" # https://pypi.org/project/beautifulsoup4/
|
|
||||||
|
|
||||||
# https://github.com/akaihola/darker
|
|
||||||
# https://github.com/ikamensh/flynt
|
|
||||||
# https://github.com/pycqa/isort
|
|
||||||
# https://github.com/pygments/pygments
|
|
||||||
darker = { version = "*", extras = ["flynt", "isort", "color"] }
|
|
||||||
|
|
||||||
tomli = "*" # https://github.com/hukkin/tomli
|
|
||||||
# tomli only needed for Python <3.11, but see bug:
|
|
||||||
# https://github.com/pypa/pip/issues/9644#issuecomment-1456583402
|
|
||||||
#tomli = {version = "*", markers = "python_version < \"3.11\""} # https://github.com/hukkin/tomli
|
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core"]
|
requires = ["setuptools>=61.0", "setuptools_scm>=7.1"]
|
||||||
build-backend = "poetry.core.masonry.api"
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[tool.setuptools.packages.find]
|
||||||
|
where = ["."]
|
||||||
|
include = ["for_runners_ynh*"]
|
||||||
|
|
||||||
|
[tool.setuptools.dynamic]
|
||||||
|
version = {attr = "for_runners_ynh.__version__"}
|
||||||
|
|
||||||
|
|
||||||
[tool.darker]
|
[tool.darker]
|
||||||
src = ['.']
|
src = ['.']
|
||||||
|
# YunoHost apps still use "master" istead of "main", isn't it?
|
||||||
revision = "origin/master..."
|
revision = "origin/master..."
|
||||||
line_length = 119
|
line_length = 119
|
||||||
verbose = true
|
verbose = true
|
||||||
|
@ -77,7 +103,7 @@ log_level = "INFO"
|
||||||
atomic=true
|
atomic=true
|
||||||
profile='black'
|
profile='black'
|
||||||
skip_glob=[".*", "*/htmlcov/*","*/migrations/*","*/local_test/*"]
|
skip_glob=[".*", "*/htmlcov/*","*/migrations/*","*/local_test/*"]
|
||||||
known_first_party=['for_runners']
|
known_first_party=['django_for_runners', 'for_runners_ynh']
|
||||||
line_length=119
|
line_length=119
|
||||||
lines_after_imports=2
|
lines_after_imports=2
|
||||||
|
|
||||||
|
@ -114,6 +140,10 @@ branch = true
|
||||||
parallel = true
|
parallel = true
|
||||||
concurrency = ["multiprocessing"]
|
concurrency = ["multiprocessing"]
|
||||||
source = ['.']
|
source = ['.']
|
||||||
|
# TODO: pytest -> Django unitests:
|
||||||
|
#command_line = '-m unittest --verbose --locals --buffer'
|
||||||
|
command_line = '-m pytest'
|
||||||
|
disable_warnings = ["couldnt-parse"]
|
||||||
|
|
||||||
[tool.coverage.report]
|
[tool.coverage.report]
|
||||||
omit = ['.*', '*/tests/*']
|
omit = ['.*', '*/tests/*']
|
||||||
|
@ -132,18 +162,32 @@ exclude_lines = [
|
||||||
legacy_tox_ini = """
|
legacy_tox_ini = """
|
||||||
[tox]
|
[tox]
|
||||||
isolated_build = True
|
isolated_build = True
|
||||||
envlist = py{311,310,39}
|
envlist = py{312,311,310,39}
|
||||||
skip_missing_interpreters = True
|
skip_missing_interpreters = True
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
passenv = *
|
passenv = *
|
||||||
skip_install = true
|
skip_install = true
|
||||||
allowlist_externals = make
|
commands_pre =
|
||||||
|
pip install -U pip-tools
|
||||||
|
pip-sync requirements.dev.txt
|
||||||
commands =
|
commands =
|
||||||
make pytest
|
{envpython} -m coverage run --context='{envname}'
|
||||||
|
{envpython} -m coverage combine --append
|
||||||
|
{envpython} -m coverage xml
|
||||||
|
{envpython} -m coverage report
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
[tool.mypy]
|
||||||
|
warn_unused_configs = true
|
||||||
|
ignore_missing_imports = true
|
||||||
|
allow_redefinition = true # https://github.com/python/mypy/issues/7165
|
||||||
|
show_error_codes = true
|
||||||
|
plugins = []
|
||||||
|
exclude = ['.venv', 'tests']
|
||||||
|
|
||||||
|
|
||||||
[manageprojects] # https://github.com/jedie/manageprojects
|
[manageprojects] # https://github.com/jedie/manageprojects
|
||||||
initial_revision = "2281f4b"
|
initial_revision = "2281f4b"
|
||||||
initial_date = 2023-04-02T17:40:58+02:00
|
initial_date = 2023-04-02T17:40:58+02:00
|
||||||
|
@ -151,6 +195,7 @@ cookiecutter_template = "https://github.com/jedie/cookiecutter_templates/"
|
||||||
cookiecutter_directory = "yunohost_django_package"
|
cookiecutter_directory = "yunohost_django_package"
|
||||||
applied_migrations = [
|
applied_migrations = [
|
||||||
"183124a", # 2023-04-04T12:26:15+02:00
|
"183124a", # 2023-04-04T12:26:15+02:00
|
||||||
|
"3383cb0", # 2023-11-09T20:14:05+01:00
|
||||||
]
|
]
|
||||||
|
|
||||||
[manageprojects.cookiecutter_context.cookiecutter]
|
[manageprojects.cookiecutter_context.cookiecutter]
|
||||||
|
|
1531
requirements.dev.txt
Normal file
1531
requirements.dev.txt
Normal file
File diff suppressed because it is too large
Load diff
|
@ -4,13 +4,6 @@
|
||||||
# RETRIEVE ARGUMENTS FROM THE MANIFEST
|
# RETRIEVE ARGUMENTS FROM THE MANIFEST
|
||||||
#=================================================
|
#=================================================
|
||||||
|
|
||||||
domain=$YNH_APP_ARG_DOMAIN
|
|
||||||
path_url=$YNH_APP_ARG_PATH
|
|
||||||
|
|
||||||
admin=$YNH_APP_ARG_ADMIN
|
|
||||||
is_public=$YNH_APP_ARG_IS_PUBLIC
|
|
||||||
app=$YNH_APP_INSTANCE_NAME
|
|
||||||
|
|
||||||
# Transfer the main SSO domain to the App:
|
# Transfer the main SSO domain to the App:
|
||||||
ynh_current_host=$(cat /etc/yunohost/current_host)
|
ynh_current_host=$(cat /etc/yunohost/current_host)
|
||||||
__YNH_CURRENT_HOST__=${ynh_current_host}
|
__YNH_CURRENT_HOST__=${ynh_current_host}
|
||||||
|
@ -20,7 +13,7 @@ __YNH_CURRENT_HOST__=${ynh_current_host}
|
||||||
#=================================================
|
#=================================================
|
||||||
|
|
||||||
# 'debug_enabled' -> '__DEBUG_ENABLED__' -> settings.DEBUG
|
# 'debug_enabled' -> '__DEBUG_ENABLED__' -> settings.DEBUG
|
||||||
debug_enabled="0"
|
debug_enabled="NO" # "YES" or "NO" string
|
||||||
|
|
||||||
# 'log_level' -> '__LOG_LEVEL__' -> settings.LOG_LEVEL
|
# 'log_level' -> '__LOG_LEVEL__' -> settings.LOG_LEVEL
|
||||||
log_level="WARNING"
|
log_level="WARNING"
|
||||||
|
@ -35,26 +28,62 @@ default_from_email="${app}@${domain}"
|
||||||
# SET CONSTANTS
|
# SET CONSTANTS
|
||||||
#=================================================
|
#=================================================
|
||||||
|
|
||||||
public_path=/var/www/$app
|
# e.g.: point pip cache to: /home/yunohost.app/$app/.cache/
|
||||||
final_path=/opt/yunohost/$app
|
XDG_CACHE_HOME="$data_dir/.cache/"
|
||||||
|
|
||||||
log_path=/var/log/$app
|
log_path=/var/log/$app
|
||||||
log_file="${log_path}/${app}.log"
|
log_file="${log_path}/${app}.log"
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# COMMON VARIABLES
|
# HELPERS
|
||||||
#=================================================
|
#=================================================
|
||||||
|
|
||||||
# Needed base dependencies:
|
myynh_setup_python_venv() {
|
||||||
pkg_dependencies="build-essential python3-dev python3-pip python3-venv git"
|
# Always recreate everything fresh with current python version
|
||||||
|
ynh_secure_remove "$data_dir/venv"
|
||||||
|
|
||||||
# For pillow:
|
# Skip pip because of: https://github.com/YunoHost/issues/issues/1960
|
||||||
pkg_dependencies="${pkg_dependencies} libjpeg-dev"
|
python3 -m venv --without-pip "$data_dir/venv"
|
||||||
|
|
||||||
# Postgres and Python's "psycopg2":
|
chown -c -R "$app:" "$data_dir"
|
||||||
pkg_dependencies="${pkg_dependencies} libpq-dev postgresql postgresql-contrib"
|
|
||||||
|
|
||||||
# Needed for lxml: https://lxml.de/installation.html#requirements
|
# run source in a 'sub shell'
|
||||||
pkg_dependencies="${pkg_dependencies} libxml2-dev libxslt-dev"
|
(
|
||||||
|
set +o nounset
|
||||||
|
source "$data_dir/venv/bin/activate"
|
||||||
|
set -o nounset
|
||||||
|
set -x
|
||||||
|
ynh_exec_as $app $data_dir/venv/bin/python3 -m ensurepip
|
||||||
|
ynh_exec_as $app $data_dir/venv/bin/pip3 install --upgrade wheel pip setuptools
|
||||||
|
ynh_exec_as $app $data_dir/venv/bin/pip3 install --no-deps -r "$data_dir/requirements.txt"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
myynh_setup_log_file() {
|
||||||
|
(
|
||||||
|
set -x
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "$log_file")"
|
||||||
|
touch "$log_file"
|
||||||
|
|
||||||
|
chown -c -R $app:$app "$log_path"
|
||||||
|
chmod -c o-rwx "$log_path"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
myynh_fix_file_permissions() {
|
||||||
|
(
|
||||||
|
set -x
|
||||||
|
|
||||||
|
# /var/www/$app/
|
||||||
|
chown -c -R "$app:www-data" "$install_dir"
|
||||||
|
chmod -c o-rwx "$install_dir"
|
||||||
|
|
||||||
|
# /home/yunohost.app/$app/
|
||||||
|
chown -c -R "$app:" "$data_dir"
|
||||||
|
chmod -c o-rwx "$data_dir"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# Redis HELPERS
|
# Redis HELPERS
|
||||||
|
|
|
@ -9,21 +9,6 @@
|
||||||
source ../settings/scripts/_common.sh
|
source ../settings/scripts/_common.sh
|
||||||
source /usr/share/yunohost/helpers
|
source /usr/share/yunohost/helpers
|
||||||
|
|
||||||
ynh_abort_if_errors
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# LOAD SETTINGS
|
|
||||||
#=================================================
|
|
||||||
ynh_print_info --message="Loading installation settings..."
|
|
||||||
|
|
||||||
app=$YNH_APP_INSTANCE_NAME
|
|
||||||
|
|
||||||
public_path=$(ynh_app_setting_get --app="$app" --key=public_path)
|
|
||||||
final_path=$(ynh_app_setting_get --app="$app" --key=final_path)
|
|
||||||
db_name=$(ynh_app_setting_get --app="$app" --key=db_name)
|
|
||||||
|
|
||||||
domain=$(ynh_app_setting_get --app="$app" --key=domain)
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# DECLARE DATA AND CONF FILES TO BACKUP
|
# DECLARE DATA AND CONF FILES TO BACKUP
|
||||||
#=================================================
|
#=================================================
|
||||||
|
@ -33,8 +18,11 @@ ynh_print_info --message="Declaring files to be backed up..."
|
||||||
# BACKUP THE APP MAIN DIR
|
# BACKUP THE APP MAIN DIR
|
||||||
#=================================================
|
#=================================================
|
||||||
|
|
||||||
ynh_backup --src_path="$final_path"
|
# /var/www/$app/
|
||||||
ynh_backup --src_path="$public_path"
|
ynh_backup --src_path="$install_dir"
|
||||||
|
|
||||||
|
# /home/yunohost.app/$app/
|
||||||
|
ynh_backup --src_path="$data_dir"
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# BACKUP THE NGINX CONFIGURATION
|
# BACKUP THE NGINX CONFIGURATION
|
||||||
|
|
|
@ -6,81 +6,9 @@
|
||||||
# IMPORT GENERIC HELPERS
|
# IMPORT GENERIC HELPERS
|
||||||
#=================================================
|
#=================================================
|
||||||
|
|
||||||
YNH_APP_ARG_DOMAIN=$YNH_APP_NEW_DOMAIN
|
|
||||||
YNH_APP_ARG_PATH=$YNH_APP_NEW_PATH
|
|
||||||
|
|
||||||
source _common.sh
|
source _common.sh
|
||||||
source /usr/share/yunohost/helpers
|
source /usr/share/yunohost/helpers
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# RETRIEVE ARGUMENTS
|
|
||||||
#=================================================
|
|
||||||
|
|
||||||
old_domain=$YNH_APP_OLD_DOMAIN
|
|
||||||
old_path=$YNH_APP_OLD_PATH
|
|
||||||
|
|
||||||
new_domain=$YNH_APP_NEW_DOMAIN
|
|
||||||
new_path=$YNH_APP_NEW_PATH
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# LOAD SETTINGS
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Loading installation settings..."
|
|
||||||
|
|
||||||
admin=$(ynh_app_setting_get --app="$app" --key=admin)
|
|
||||||
public_path=$(ynh_app_setting_get --app="$app" --key=public_path)
|
|
||||||
final_path=$(ynh_app_setting_get --app="$app" --key=final_path)
|
|
||||||
log_path=$(ynh_app_setting_get --app="$app" --key=log_path)
|
|
||||||
|
|
||||||
port=$(ynh_app_setting_get --app="$app" --key=port)
|
|
||||||
|
|
||||||
db_pwd=$(ynh_app_setting_get --app="$app" --key=psqlpwd)
|
|
||||||
db_name=$(ynh_sanitize_dbid --db_name="$app")
|
|
||||||
db_user=$db_name
|
|
||||||
|
|
||||||
redis_db=$(ynh_app_setting_get --app="$app" --key=redis_db)
|
|
||||||
|
|
||||||
#-------------------------------------------------
|
|
||||||
# config_panel.toml settings:
|
|
||||||
|
|
||||||
debug_enabled=$(ynh_app_setting_get --app="$app" --key=debug_enabled)
|
|
||||||
log_level=$(ynh_app_setting_get --app="$app" --key=log_level)
|
|
||||||
admin_email=$(ynh_app_setting_get --app="$app" --key=admin_email)
|
|
||||||
default_from_email=$(ynh_app_setting_get --app="$app" --key=default_from_email)
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# BACKUP BEFORE UPGRADE THEN ACTIVE TRAP
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Backing up the app before changing its URL (may take a while)..." --weight=40
|
|
||||||
|
|
||||||
# Backup the current version of the app
|
|
||||||
ynh_backup_before_upgrade
|
|
||||||
ynh_clean_setup () {
|
|
||||||
# Remove the new domain config file, the remove script won't do it as it doesn't know yet its location.
|
|
||||||
ynh_secure_remove --file="/etc/nginx/conf.d/$new_domain.d/$app.conf"
|
|
||||||
|
|
||||||
# restore it if the upgrade fails
|
|
||||||
ynh_restore_upgradebackup
|
|
||||||
}
|
|
||||||
# Exit if an error occurs during the execution of the script
|
|
||||||
ynh_abort_if_errors
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# CHECK WHICH PARTS SHOULD BE CHANGED
|
|
||||||
#=================================================
|
|
||||||
|
|
||||||
change_domain=0
|
|
||||||
if [ "$old_domain" != "$new_domain" ]
|
|
||||||
then
|
|
||||||
change_domain=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
change_path=0
|
|
||||||
if [ "$old_path" != "$new_path" ]
|
|
||||||
then
|
|
||||||
change_path=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# STANDARD MODIFICATIONS
|
# STANDARD MODIFICATIONS
|
||||||
#=================================================
|
#=================================================
|
||||||
|
@ -88,66 +16,31 @@ fi
|
||||||
#=================================================
|
#=================================================
|
||||||
ynh_script_progression --message="Stopping systemd service '$app'..."
|
ynh_script_progression --message="Stopping systemd service '$app'..."
|
||||||
|
|
||||||
ynh_systemd_action --service_name="$app" --action="stop"
|
ynh_systemd_action --service_name=$app --action="stop" --log_path="$log_file"
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# STANDARD MODIFICATIONS
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# MODIFY URL IN NGINX CONF
|
# MODIFY URL IN NGINX CONF
|
||||||
#=================================================
|
#=================================================
|
||||||
ynh_script_progression --message="Updating nginx web server configuration..."
|
ynh_script_progression --message="Updating nginx web server configuration..."
|
||||||
|
|
||||||
nginx_conf_path=/etc/nginx/conf.d/$old_domain.d/$app.conf
|
ynh_change_url_nginx_config
|
||||||
|
|
||||||
# Change the path in the nginx config file
|
|
||||||
if [ $change_path -eq 1 ]
|
|
||||||
then
|
|
||||||
# Make a backup of the original nginx config file if modified
|
|
||||||
ynh_backup_if_checksum_is_different --file="$nginx_conf_path"
|
|
||||||
# Set global variables for nginx helper
|
|
||||||
domain="$old_domain"
|
|
||||||
path_url="$new_path"
|
|
||||||
# Create a dedicated nginx config
|
|
||||||
ynh_add_nginx_config "public_path" "port"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Change the domain for nginx
|
|
||||||
if [ $change_domain -eq 1 ]
|
|
||||||
then
|
|
||||||
# Delete file checksum for the old conf file location
|
|
||||||
ynh_delete_file_checksum --file="$nginx_conf_path"
|
|
||||||
mv $nginx_conf_path /etc/nginx/conf.d/$new_domain.d/$app.conf
|
|
||||||
# Store file checksum for the new config file location
|
|
||||||
ynh_store_file_checksum --file="/etc/nginx/conf.d/$new_domain.d/$app.conf"
|
|
||||||
fi
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# SPECIFIC MODIFICATIONS
|
# UPDATE DJANGO SETTINGS
|
||||||
#=================================================
|
#=================================================
|
||||||
# MODIFY SETTINGS
|
ynh_script_progression --message="Update $app settings file..." --weight=1
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Modify $app config file..."
|
|
||||||
|
|
||||||
domain=$YNH_APP_NEW_DOMAIN
|
path=$new_path
|
||||||
path_url=$YNH_APP_NEW_PATH
|
domain=$new_domain
|
||||||
|
|
||||||
ynh_add_config --template="settings.py" --destination="$final_path/settings.py"
|
ynh_add_config --template="settings.py" --destination="$data_dir/settings.py"
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# GENERIC FINALISATION
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# START SYSTEMD SERVICE
|
# START SYSTEMD SERVICE
|
||||||
#=================================================
|
#=================================================
|
||||||
ynh_script_progression --message="Starting systemd service '$app'..." --weight=5
|
ynh_script_progression --message="Starting systemd service '$app'..." --weight=5
|
||||||
|
|
||||||
ynh_systemd_action --service_name="$app" --action="start"
|
ynh_systemd_action --service_name=$app --action="start" --log_path="$log_file"
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# RELOAD NGINX
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Reloading nginx web server..."
|
|
||||||
|
|
||||||
ynh_systemd_action --service_name=nginx --action=reload
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# END OF SCRIPT
|
# END OF SCRIPT
|
||||||
|
|
315
scripts/install
315
scripts/install
|
@ -7,88 +7,137 @@
|
||||||
source _common.sh
|
source _common.sh
|
||||||
source /usr/share/yunohost/helpers
|
source /usr/share/yunohost/helpers
|
||||||
|
|
||||||
#=================================================
|
# Install parameters are automatically saved as settings
|
||||||
# MANAGE SCRIPT FAILURE
|
#
|
||||||
#=================================================
|
# Settings are automatically loaded as bash variables
|
||||||
|
# in every app script context, therefore typically these will exist:
|
||||||
|
# - $domain
|
||||||
|
# - $path
|
||||||
|
# - $language
|
||||||
|
# ... etc
|
||||||
|
#
|
||||||
|
# Resources defined in the manifest are provisioned prior to this script
|
||||||
|
# and corresponding settings are also available, such as:
|
||||||
|
# - $install_dir
|
||||||
|
# - $port
|
||||||
|
# - $db_name
|
||||||
|
# ...
|
||||||
|
|
||||||
# Exit if an error occurs during the execution of the script
|
#
|
||||||
ynh_abort_if_errors
|
# $app is the app id (i.e. 'example' for first install,
|
||||||
|
# or 'example__2', '__3', ... for multi-instance installs)
|
||||||
|
#
|
||||||
|
|
||||||
|
#=================================================
|
||||||
|
# SETTINGS
|
||||||
|
#=================================================
|
||||||
|
ynh_script_progression --message="Storing installation settings..."
|
||||||
|
|
||||||
|
# Logging:
|
||||||
|
log_file="/var/log/$app/$app.log"
|
||||||
|
ynh_app_setting_set --app=$app --key=log_file --value="$log_file"
|
||||||
|
|
||||||
|
# Redis:
|
||||||
|
redis_db=$(ynh_redis_get_free_db)
|
||||||
|
ynh_app_setting_set --app=$app --key=redis_db --value="$redis_db"
|
||||||
|
|
||||||
|
# App settings:
|
||||||
|
ynh_app_setting_set --app=$app --key=default_from_email --value="$default_from_email"
|
||||||
|
ynh_app_setting_set --app=$app --key=admin_email --value="$admin_email"
|
||||||
|
ynh_app_setting_set --app=$app --key=debug_enabled --value="$debug_enabled"
|
||||||
|
ynh_app_setting_set --app=$app --key=log_level --value="$log_level"
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# CHECK IF THE APP CAN BE INSTALLED WITH THESE ARGS
|
# CHECK IF THE APP CAN BE INSTALLED WITH THESE ARGS
|
||||||
#=================================================
|
#=================================================
|
||||||
ynh_script_progression --message="Validating installation parameters..."
|
ynh_script_progression --message="Validating installation parameters..."
|
||||||
|
|
||||||
# Path for e.g. "static" files, served by nginx:
|
mkdir -p "$install_dir/media" "$install_dir/static"
|
||||||
test ! -e "$public_path" || ynh_die --message="This path already contains a folder"
|
|
||||||
|
|
||||||
# Path for own config files, e.g.: Django's settings.py:
|
|
||||||
test ! -e "$final_path" || ynh_die --message="This path already contains a folder"
|
|
||||||
|
|
||||||
# Register (book) web path
|
|
||||||
ynh_webpath_register --app="$app" --domain="$domain" --path_url="$path_url"
|
|
||||||
|
|
||||||
mkdir -p "$public_path/media" "$public_path/static"
|
|
||||||
mkdir -p "$final_path"
|
|
||||||
|
|
||||||
mkdir -p "$log_path"
|
|
||||||
touch "${log_file}"
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# STORE SETTINGS FROM MANIFEST
|
# SETUP LOG FILE
|
||||||
#=================================================
|
#=================================================
|
||||||
ynh_script_progression --message="Storing installation settings..."
|
ynh_script_progression --message="Setup logging..."
|
||||||
|
|
||||||
ynh_app_setting_set --app="$app" --key=admin --value="$admin"
|
myynh_setup_log_file
|
||||||
ynh_app_setting_set --app="$app" --key=public_path --value="$public_path"
|
|
||||||
ynh_app_setting_set --app="$app" --key=final_path --value="$final_path"
|
|
||||||
ynh_app_setting_set --app="$app" --key=log_path --value="$log_file"
|
|
||||||
|
|
||||||
ynh_app_setting_set --app="$app" --key=domain --value="$domain"
|
# Use logrotate to manage application logfile(s)
|
||||||
ynh_app_setting_set --app="$app" --key=path --value="$path_url"
|
ynh_use_logrotate --logfile="$log_file" --specific_user=$app
|
||||||
|
|
||||||
# Find a free port
|
|
||||||
port=$(ynh_find_port --port=8000)
|
|
||||||
# Set port as application setting
|
|
||||||
# https://yunohost.org/en/contribute/packaging_apps/helpers
|
|
||||||
# https://github.com/YunoHost/yunohost/blob/dev/helpers/setting
|
|
||||||
ynh_app_setting_set --app="$app" --key=port --value="$port"
|
|
||||||
|
|
||||||
db_pwd=$(ynh_app_setting_get --app="$app" --key=psqlpwd)
|
|
||||||
|
|
||||||
redis_db=$(ynh_redis_get_free_db)
|
|
||||||
ynh_app_setting_set --app="$app" --key=redis_db --value="$redis_db"
|
|
||||||
|
|
||||||
#-------------------------------------------------
|
|
||||||
# config_panel.toml settings:
|
|
||||||
|
|
||||||
ynh_app_setting_set --app="$app" --key=debug_enabled --value="$debug_enabled"
|
|
||||||
ynh_app_setting_set --app="$app" --key=log_level --value="$log_level"
|
|
||||||
ynh_app_setting_set --app="$app" --key=admin_email --value="$admin_email"
|
|
||||||
ynh_app_setting_set --app="$app" --key=default_from_email --value="$default_from_email"
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# STANDARD MODIFICATIONS
|
# PYTHON VIRTUALENV
|
||||||
#=================================================
|
#=================================================
|
||||||
# INSTALL DEPENDENCIES
|
ynh_script_progression --message="Create and setup Python virtualenv..." --weight=45
|
||||||
#=================================================
|
cp ../conf/requirements.txt "$data_dir/requirements.txt"
|
||||||
ynh_script_progression --message="Installing $app dependencies..." --weight=20
|
myynh_setup_python_venv
|
||||||
|
|
||||||
ynh_exec_warn_less ynh_install_app_dependencies "$pkg_dependencies"
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# CREATE A PostgreSQL DATABASE
|
# copy config files
|
||||||
|
# ================================================
|
||||||
|
ynh_script_progression --message="Create $app configuration files..."
|
||||||
|
|
||||||
|
ynh_add_config --template="gunicorn.conf.py" --destination="$data_dir/gunicorn.conf.py"
|
||||||
|
|
||||||
|
ynh_add_config --template="manage.py" --destination="$data_dir/manage.py"
|
||||||
|
chmod -c +x "$data_dir/manage.py"
|
||||||
|
|
||||||
|
ynh_add_config --template="settings.py" --destination="$data_dir/settings.py"
|
||||||
|
ynh_add_config --template="setup_user.py" --destination="$data_dir/setup_user.py"
|
||||||
|
ynh_add_config --template="urls.py" --destination="$data_dir/urls.py"
|
||||||
|
ynh_add_config --template="wsgi.py" --destination="$data_dir/wsgi.py"
|
||||||
|
|
||||||
|
touch "$data_dir/local_settings.py"
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
ynh_script_progression --message="Creating a PostgreSQL database..."
|
# MIGRATE / COLLECTSTATIC / CREATEADMIN
|
||||||
|
#=================================================
|
||||||
|
ynh_script_progression --message="migrate/collectstatic/createadmin..." --weight=10
|
||||||
|
|
||||||
db_name=$(ynh_sanitize_dbid --db_name="$app")
|
cd "$data_dir" || exit
|
||||||
db_user=$db_name
|
|
||||||
ynh_app_setting_set --app="$app" --key=db_name --value="$db_name"
|
|
||||||
|
|
||||||
ynh_psql_test_if_first_run
|
# Just for debugging:
|
||||||
|
./manage.py diffsettings
|
||||||
|
|
||||||
# Initialize database and store postgres password for upgrade
|
./manage.py migrate --no-input
|
||||||
ynh_psql_setup_db --db_user="$db_user" --db_name="$db_name"
|
./manage.py collectstatic --no-input
|
||||||
|
|
||||||
|
# Create/update Django superuser (set unusable password, because auth done via SSOwat):
|
||||||
|
./manage.py create_superuser --username="$admin" --email="$(ynh_user_get_info "$admin" mail)"
|
||||||
|
|
||||||
|
# Check the configuration
|
||||||
|
# This may fail in some cases with errors, etc., but the app works and the user can fix issues later.
|
||||||
|
./manage.py check --deploy || true
|
||||||
|
|
||||||
|
#=================================================
|
||||||
|
# INTEGRATE SERVICE IN YUNOHOST
|
||||||
|
#=================================================
|
||||||
|
ynh_script_progression --message="Integrating service in YunoHost..."
|
||||||
|
|
||||||
|
yunohost service add $app
|
||||||
|
|
||||||
|
#=================================================
|
||||||
|
# GENERIC FINALIZATION
|
||||||
|
#=================================================
|
||||||
|
# SECURE FILES AND DIRECTORIES
|
||||||
|
#=================================================
|
||||||
|
ynh_script_progression --message="Set file permissions..."
|
||||||
|
myynh_fix_file_permissions
|
||||||
|
|
||||||
|
#=================================================
|
||||||
|
# SETUP SYSTEMD
|
||||||
|
#=================================================
|
||||||
|
ynh_script_progression --message="Configuring systemd service '$app'..." --weight=5
|
||||||
|
|
||||||
|
# https://yunohost.org/en/packaging_apps_helpers#ynh-add-systemd-config
|
||||||
|
# https://github.com/YunoHost/yunohost/blob/dev/helpers/systemd
|
||||||
|
ynh_add_systemd_config --service=$app --template="systemd.service"
|
||||||
|
|
||||||
|
#=================================================
|
||||||
|
# Start the app server via systemd
|
||||||
|
#=================================================
|
||||||
|
ynh_script_progression --message="Starting systemd service '$app'..." --weight=5
|
||||||
|
|
||||||
|
ynh_systemd_action --service_name=$app --action="start" --log_path="$log_file"
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# NGINX CONFIGURATION
|
# NGINX CONFIGURATION
|
||||||
|
@ -100,150 +149,6 @@ ynh_script_progression --message="Configuring nginx web server..."
|
||||||
# https://github.com/YunoHost/yunohost/blob/dev/helpers/nginx
|
# https://github.com/YunoHost/yunohost/blob/dev/helpers/nginx
|
||||||
ynh_add_nginx_config "public_path" "port"
|
ynh_add_nginx_config "public_path" "port"
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# CREATE DEDICATED USER
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Configuring system user '$app'..."
|
|
||||||
|
|
||||||
# A home directory for venv and settings etc.
|
|
||||||
ynh_system_user_create --username="$app" --home_dir="$final_path" --use_shell
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# PYTHON VIRTUALENV
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Create Python virtualenv..." --weight=5
|
|
||||||
|
|
||||||
# Always recreate everything fresh with current python version
|
|
||||||
ynh_secure_remove "${final_path}/venv"
|
|
||||||
|
|
||||||
# Skip pip because of: https://github.com/YunoHost/issues/issues/1960
|
|
||||||
python3 -m venv --without-pip "${final_path}/venv"
|
|
||||||
|
|
||||||
cp ../conf/requirements.txt "$final_path/requirements.txt"
|
|
||||||
chown -R "$app:" "$final_path"
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# PIP INSTALLATION
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Install project via pip..." --weight=45
|
|
||||||
|
|
||||||
#run source in a 'sub shell'
|
|
||||||
(
|
|
||||||
set +o nounset
|
|
||||||
source "${final_path}/venv/bin/activate"
|
|
||||||
set -o nounset
|
|
||||||
ynh_exec_as $app $final_path/venv/bin/python3 -m ensurepip
|
|
||||||
ynh_exec_as $app $final_path/venv/bin/pip3 install --upgrade wheel pip setuptools
|
|
||||||
ynh_exec_as $app $final_path/venv/bin/pip3 install --no-deps -r "$final_path/requirements.txt"
|
|
||||||
)
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# copy config files
|
|
||||||
# ================================================
|
|
||||||
ynh_script_progression --message="Create $app configuration files..."
|
|
||||||
|
|
||||||
ynh_add_config --template="gunicorn.conf.py" --destination="$final_path/gunicorn.conf.py"
|
|
||||||
|
|
||||||
ynh_add_config --template="manage.py" --destination="$final_path/manage.py"
|
|
||||||
chmod +x "$final_path/manage.py"
|
|
||||||
|
|
||||||
ynh_add_config --template="settings.py" --destination="$final_path/settings.py"
|
|
||||||
ynh_add_config --template="setup_user.py" --destination="$final_path/setup_user.py"
|
|
||||||
ynh_add_config --template="urls.py" --destination="$final_path/urls.py"
|
|
||||||
ynh_add_config --template="wsgi.py" --destination="$final_path/wsgi.py"
|
|
||||||
|
|
||||||
touch "$final_path/local_settings.py"
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# MIGRATE / COLLECTSTATIC / CREATEADMIN
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="migrate/collectstatic/createadmin..." --weight=10
|
|
||||||
|
|
||||||
cd "$final_path" || exit
|
|
||||||
|
|
||||||
# Just for debugging:
|
|
||||||
./manage.py diffsettings
|
|
||||||
|
|
||||||
./manage.py migrate --no-input
|
|
||||||
|
|
||||||
./manage.py fill_basedata # Special from django-for-runners
|
|
||||||
|
|
||||||
./manage.py collectstatic --no-input
|
|
||||||
|
|
||||||
# Create/update Django superuser (set unusable password, because auth done via SSOwat):
|
|
||||||
./manage.py create_superuser --username="$admin" --email="$(ynh_user_get_info "$admin" mail)"
|
|
||||||
|
|
||||||
# Check the configuration
|
|
||||||
# This may fail in some cases with errors, etc., but the app works and the user can fix issues later.
|
|
||||||
./manage.py check --deploy || true
|
|
||||||
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# SETUP LOGROTATE
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Configuring log rotation..."
|
|
||||||
|
|
||||||
# Use logrotate to manage app-specific logfile(s)
|
|
||||||
ynh_use_logrotate "$log_file"
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# INTEGRATE SERVICE IN YUNOHOST
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Integrating service in YunoHost..."
|
|
||||||
|
|
||||||
yunohost service add $app --log="${log_file}"
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# GENERIC FINALIZATION
|
|
||||||
#=================================================
|
|
||||||
# SECURE FILES AND DIRECTORIES
|
|
||||||
#=================================================
|
|
||||||
|
|
||||||
# Set permissions to app files
|
|
||||||
chown -R "$app:" "$log_path"
|
|
||||||
chown -R "$app:www-data" "$public_path"
|
|
||||||
chown -R "$app:" "$final_path"
|
|
||||||
|
|
||||||
chmod o-rwx "$log_path"
|
|
||||||
chmod o-rwx "$public_path"
|
|
||||||
chmod o-rwx "$final_path"
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# SETUP SYSTEMD
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Configuring systemd service '$app'..." --weight=5
|
|
||||||
|
|
||||||
# https://yunohost.org/en/contribute/packaging_apps/helpers
|
|
||||||
# https://github.com/YunoHost/yunohost/blob/dev/helpers/systemd
|
|
||||||
ynh_add_systemd_config --service="$app" --template="systemd.service"
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# SETUP SSOWAT
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Configuring SSOwat..."
|
|
||||||
|
|
||||||
# Make app public if necessary or protect it
|
|
||||||
if [ $is_public -eq 1 ]
|
|
||||||
then
|
|
||||||
# Everyone can access the app.
|
|
||||||
# The "main" permission is automatically created before the install script.
|
|
||||||
ynh_permission_update --permission "main" --add "visitors"
|
|
||||||
fi
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# Start the app server via systemd
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Starting systemd service '$app'..." --weight=5
|
|
||||||
|
|
||||||
ynh_systemd_action --service_name="$app" --action="start"
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# RELOAD NGINX
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Reloading nginx web server..."
|
|
||||||
|
|
||||||
ynh_systemd_action --service_name="nginx" --action="reload"
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# END OF SCRIPT
|
# END OF SCRIPT
|
||||||
#=================================================
|
#=================================================
|
||||||
|
|
|
@ -9,17 +9,6 @@
|
||||||
source _common.sh
|
source _common.sh
|
||||||
source /usr/share/yunohost/helpers
|
source /usr/share/yunohost/helpers
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# LOAD SETTINGS
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Loading installation settings..."
|
|
||||||
|
|
||||||
domain=$(ynh_app_setting_get --app="$app" --key=domain)
|
|
||||||
db_name=$(ynh_app_setting_get --app="$app" --key=db_name)
|
|
||||||
db_user=$db_name
|
|
||||||
public_path=$(ynh_app_setting_get --app="$app" --key=public_path)
|
|
||||||
final_path=$(ynh_app_setting_get --app="$app" --key=final_path)
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# STANDARD REMOVE
|
# STANDARD REMOVE
|
||||||
#=================================================
|
#=================================================
|
||||||
|
@ -27,10 +16,10 @@ final_path=$(ynh_app_setting_get --app="$app" --key=final_path)
|
||||||
#=================================================
|
#=================================================
|
||||||
|
|
||||||
# Remove a service from the admin panel, added by `yunohost service add`
|
# Remove a service from the admin panel, added by `yunohost service add`
|
||||||
if yunohost service status "$app" >/dev/null 2>&1
|
if yunohost service status $app >/dev/null 2>&1
|
||||||
then
|
then
|
||||||
ynh_script_progression --message="Removing $app service integration..."
|
ynh_script_progression --message="Removing $app service integration..."
|
||||||
yunohost service remove "$app"
|
yunohost service remove $app
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
|
@ -38,15 +27,7 @@ fi
|
||||||
#=================================================
|
#=================================================
|
||||||
ynh_script_progression --message="Stopping and removing systemd service '$app'..." --weight=5
|
ynh_script_progression --message="Stopping and removing systemd service '$app'..." --weight=5
|
||||||
|
|
||||||
ynh_remove_systemd_config --service="$app"
|
ynh_remove_systemd_config --service=$app
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# REMOVE THE PostgreSQL DATABASE
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Removing the PostgreSQL database..."
|
|
||||||
|
|
||||||
# Remove a database if it exists, along with the associated user
|
|
||||||
ynh_psql_remove_db --db_user=$db_user --db_name=$db_name
|
|
||||||
|
|
||||||
##=================================================
|
##=================================================
|
||||||
## REMOVE REDIS DB
|
## REMOVE REDIS DB
|
||||||
|
@ -54,22 +35,16 @@ ynh_psql_remove_db --db_user=$db_user --db_name=$db_name
|
||||||
|
|
||||||
ynh_redis_remove_db
|
ynh_redis_remove_db
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# REMOVE DEPENDENCIES
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Removing dependencies..." --weight=10
|
|
||||||
|
|
||||||
# Remove metapackage and its dependencies
|
|
||||||
ynh_exec_warn_less ynh_remove_app_dependencies
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# REMOVE APP MAIN DIR
|
# REMOVE APP MAIN DIR
|
||||||
#=================================================
|
#=================================================
|
||||||
ynh_script_progression --message="Removing app main directory..."
|
ynh_script_progression --message="Removing app main directory..."
|
||||||
|
|
||||||
# Remove the app directory securely
|
# /var/www/$app/
|
||||||
ynh_secure_remove --file="$public_path"
|
ynh_secure_remove --file="$install_dir"
|
||||||
ynh_secure_remove --file="$final_path"
|
|
||||||
|
# /home/yunohost.app/$app/
|
||||||
|
ynh_secure_remove --file="$data_dir"
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# REMOVE NGINX CONFIGURATION
|
# REMOVE NGINX CONFIGURATION
|
||||||
|
@ -87,16 +62,6 @@ ynh_script_progression --message="Removing logrotate configuration..."
|
||||||
# Remove the app-specific logrotate config
|
# Remove the app-specific logrotate config
|
||||||
ynh_remove_logrotate
|
ynh_remove_logrotate
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# GENERIC FINALIZATION
|
|
||||||
#=================================================
|
|
||||||
# REMOVE DEDICATED USER
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Removing the dedicated system user..."
|
|
||||||
|
|
||||||
# Delete a system user
|
|
||||||
ynh_system_user_delete --username="$app"
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# END OF SCRIPT
|
# END OF SCRIPT
|
||||||
#=================================================
|
#=================================================
|
||||||
|
|
106
scripts/restore
106
scripts/restore
|
@ -9,39 +9,12 @@
|
||||||
source ../settings/scripts/_common.sh
|
source ../settings/scripts/_common.sh
|
||||||
source /usr/share/yunohost/helpers
|
source /usr/share/yunohost/helpers
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# MANAGE SCRIPT FAILURE
|
|
||||||
#=================================================
|
|
||||||
|
|
||||||
ynh_abort_if_errors
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# LOAD SETTINGS
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Loading settings..."
|
|
||||||
|
|
||||||
final_path=$(ynh_app_setting_get --app="$app" --key=final_path)
|
|
||||||
public_path=$(ynh_app_setting_get --app="$app" --key=public_path)
|
|
||||||
db_name=$(ynh_app_setting_get --app="$app" --key=db_name)
|
|
||||||
db_user=$db_name
|
|
||||||
db_pwd=$(ynh_app_setting_get --app="$app" --key=psqlpwd)
|
|
||||||
|
|
||||||
domain=$(ynh_app_setting_get --app="$app" --key=domain)
|
|
||||||
path_url=$(ynh_app_setting_get --app="$app" --key=path)
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# CHECK IF THE APP CAN BE RESTORED
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Validating restoration parameters..."
|
|
||||||
|
|
||||||
test ! -d $final_path \
|
|
||||||
|| ynh_die --message="There is already a directory: $final_path "
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# STANDARD RESTORATION STEPS
|
# STANDARD RESTORATION STEPS
|
||||||
#=================================================
|
#=================================================
|
||||||
# RESTORE THE NGINX CONFIGURATION
|
# RESTORE THE NGINX CONFIGURATION
|
||||||
#=================================================
|
#=================================================
|
||||||
|
ynh_script_progression --message="Restoring the NGINX web server configuration..." --weight=1
|
||||||
|
|
||||||
ynh_restore_file --origin_path="/etc/nginx/conf.d/$domain.d/$app.conf"
|
ynh_restore_file --origin_path="/etc/nginx/conf.d/$domain.d/$app.conf"
|
||||||
|
|
||||||
|
@ -50,74 +23,31 @@ ynh_restore_file --origin_path="/etc/nginx/conf.d/$domain.d/$app.conf"
|
||||||
#=================================================
|
#=================================================
|
||||||
ynh_script_progression --message="Restoring $app main directory..."
|
ynh_script_progression --message="Restoring $app main directory..."
|
||||||
|
|
||||||
ynh_restore_file --origin_path="$final_path"
|
ynh_restore_file --origin_path="$install_dir"
|
||||||
ynh_restore_file --origin_path="$public_path"
|
ynh_restore_file --origin_path="$data_dir"
|
||||||
|
|
||||||
#=================================================
|
ynh_script_progression --message="Set file permissions..."
|
||||||
# RECREATE THE DEDICATED USER
|
myynh_fix_file_permissions
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Recreating the dedicated system user..."
|
|
||||||
|
|
||||||
# Create the dedicated user (if not existing)
|
|
||||||
ynh_system_user_create --username=$app --home_dir="$final_path" --use_shell
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# RESTORE USER RIGHTS
|
|
||||||
#=================================================
|
|
||||||
|
|
||||||
# Restore permissions on app files
|
|
||||||
chown -R "$app:www-data" "$public_path"
|
|
||||||
chown -R "$app:" "$final_path"
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# SPECIFIC RESTORATION
|
|
||||||
#=================================================
|
|
||||||
# REINSTALL DEPENDENCIES
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Reinstalling dependencies..." --weight=20
|
|
||||||
|
|
||||||
ynh_exec_warn_less ynh_install_app_dependencies "$pkg_dependencies"
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# PYTHON VIRTUALENV
|
# PYTHON VIRTUALENV
|
||||||
# Maybe the backup contains a other Python version
|
# Maybe the backup contains a other Python version
|
||||||
#=================================================
|
#=================================================
|
||||||
ynh_script_progression --message="Recreate Python virtualenv..." --weight=5
|
ynh_script_progression --message="Create and setup Python virtualenv..." --weight=45
|
||||||
|
|
||||||
# Always recreate everything fresh with current python version
|
myynh_setup_python_venv
|
||||||
ynh_secure_remove "${final_path}/venv"
|
|
||||||
|
|
||||||
# Skip pip because of: https://github.com/YunoHost/issues/issues/1960
|
|
||||||
python3 -m venv --without-pip "${final_path}/venv"
|
|
||||||
chown -R "$app:" "$final_path"
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# PIP INSTALLATION
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Install project via pip..." --weight=45
|
|
||||||
#run source in a 'sub shell'
|
|
||||||
(
|
|
||||||
set +o nounset
|
|
||||||
source "${final_path}/venv/bin/activate"
|
|
||||||
set -o nounset
|
|
||||||
ynh_exec_as $app $final_path/venv/bin/python3 -m ensurepip
|
|
||||||
ynh_exec_as $app $final_path/venv/bin/pip3 install --upgrade wheel pip setuptools
|
|
||||||
ynh_exec_as $app $final_path/venv/bin/pip3 install --no-deps -r "$final_path/requirements.txt"
|
|
||||||
)
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# RESTORE THE PostgreSQL DATABASE
|
# RESTORE THE PostgreSQL DATABASE
|
||||||
#=================================================
|
#=================================================
|
||||||
ynh_script_progression --message="Restoring the PostgreSQL database..." --weight=5
|
ynh_script_progression --message="Restoring the PostgreSQL database..." --weight=5
|
||||||
|
|
||||||
ynh_psql_test_if_first_run
|
|
||||||
ynh_psql_setup_db --db_user="$db_user" --db_name="$db_name" --db_pwd="$db_pwd"
|
|
||||||
ynh_psql_connect_as --user=$db_user --password=$db_pwd --database=$db_name < ./db.sql
|
ynh_psql_connect_as --user=$db_user --password=$db_pwd --database=$db_name < ./db.sql
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# RESTORE SYSTEMD
|
# RESTORE SYSTEMD
|
||||||
#=================================================
|
#=================================================
|
||||||
ynh_script_progression --message="Restoring the systemd configuration..."
|
ynh_script_progression --message="Restoring the systemd $app configuration..."
|
||||||
|
|
||||||
ynh_restore_file --origin_path="/etc/systemd/system/$app.service"
|
ynh_restore_file --origin_path="/etc/systemd/system/$app.service"
|
||||||
systemctl enable $app.service --quiet
|
systemctl enable $app.service --quiet
|
||||||
|
@ -127,15 +57,14 @@ systemctl enable $app.service --quiet
|
||||||
#=================================================
|
#=================================================
|
||||||
ynh_script_progression --message="Integrating service in YunoHost..."
|
ynh_script_progression --message="Integrating service in YunoHost..."
|
||||||
|
|
||||||
yunohost service add $app --log="${log_file}"
|
yunohost service add $app
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# RESTORE THE LOGROTATE CONFIGURATION
|
# RESTORE THE LOGROTATE CONFIGURATION
|
||||||
#=================================================
|
#=================================================
|
||||||
|
ynh_script_progression --message="Setup logging..."
|
||||||
|
|
||||||
mkdir -p "$log_path"
|
myynh_setup_log_file
|
||||||
touch "${log_file}"
|
|
||||||
chown -R "$app:" "$log_path"
|
|
||||||
ynh_restore_file --origin_path="/etc/logrotate.d/$app"
|
ynh_restore_file --origin_path="/etc/logrotate.d/$app"
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
|
@ -143,15 +72,8 @@ ynh_restore_file --origin_path="/etc/logrotate.d/$app"
|
||||||
#=================================================
|
#=================================================
|
||||||
# SECURE FILES AND DIRECTORIES
|
# SECURE FILES AND DIRECTORIES
|
||||||
#=================================================
|
#=================================================
|
||||||
|
ynh_script_progression --message="Set file permissions..."
|
||||||
# Set permissions to app files
|
myynh_fix_file_permissions
|
||||||
chown -R "$app:" "$log_path"
|
|
||||||
chown -R "$app:www-data" "$public_path"
|
|
||||||
chown -R "$app:" "$final_path"
|
|
||||||
|
|
||||||
chmod o-rwx "$log_path"
|
|
||||||
chmod o-rwx "$public_path"
|
|
||||||
chmod o-rwx "$final_path"
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# GENERIC FINALIZATION
|
# GENERIC FINALIZATION
|
||||||
|
@ -160,7 +82,7 @@ chmod o-rwx "$final_path"
|
||||||
#=================================================
|
#=================================================
|
||||||
ynh_script_progression --message="Starting systemd service '$app'..." --weight=5
|
ynh_script_progression --message="Starting systemd service '$app'..." --weight=5
|
||||||
|
|
||||||
ynh_systemd_action --service_name="$app" --action="start"
|
ynh_systemd_action --service_name=$app --action="start" --log_path="$log_file"
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# RELOAD NGINX
|
# RELOAD NGINX
|
||||||
|
|
150
scripts/upgrade
150
scripts/upgrade
|
@ -7,68 +7,29 @@
|
||||||
source _common.sh
|
source _common.sh
|
||||||
source /usr/share/yunohost/helpers
|
source /usr/share/yunohost/helpers
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# LOAD SETTINGS
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Loading installation settings..."
|
|
||||||
|
|
||||||
admin=$(ynh_app_setting_get --app="$app" --key=admin)
|
|
||||||
public_path=$(ynh_app_setting_get --app="$app" --key=public_path)
|
|
||||||
final_path=$(ynh_app_setting_get --app="$app" --key=final_path)
|
|
||||||
log_path=$(ynh_app_setting_get --app="$app" --key=log_path)
|
|
||||||
|
|
||||||
domain=$(ynh_app_setting_get --app="$app" --key=domain)
|
|
||||||
path_url=$(ynh_app_setting_get --app="$app" --key=path)
|
|
||||||
|
|
||||||
port=$(ynh_app_setting_get --app="$app" --key=port)
|
|
||||||
|
|
||||||
db_pwd=$(ynh_app_setting_get --app="$app" --key=psqlpwd)
|
|
||||||
db_name=$(ynh_sanitize_dbid --db_name="$app")
|
|
||||||
db_user=$db_name
|
|
||||||
|
|
||||||
redis_db=$(ynh_app_setting_get --app="$app" --key=redis_db)
|
|
||||||
|
|
||||||
#-------------------------------------------------
|
#-------------------------------------------------
|
||||||
# config_panel.toml settings:
|
# config_panel.toml settings:
|
||||||
|
|
||||||
debug_enabled=$(ynh_app_setting_get --app="$app" --key=debug_enabled)
|
|
||||||
if [ -z "$debug_enabled" ]; then
|
if [ -z "$debug_enabled" ]; then
|
||||||
debug_enabled="0"
|
debug_enabled="0"
|
||||||
ynh_app_setting_set --app="$app" --key=debug_enabled --value="$debug_enabled"
|
ynh_app_setting_set --app=$app --key=debug_enabled --value="$debug_enabled"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
log_level=$(ynh_app_setting_get --app="$app" --key=log_level)
|
|
||||||
if [ -z "$log_level" ]; then
|
if [ -z "$log_level" ]; then
|
||||||
log_level="WARNING"
|
log_level="WARNING"
|
||||||
ynh_app_setting_set --app="$app" --key=log_level --value="$log_level"
|
ynh_app_setting_set --app=$app --key=log_level --value="$log_level"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
admin_email=$(ynh_app_setting_get --app="$app" --key=admin_email)
|
|
||||||
if [ -z "$admin_email" ]; then
|
if [ -z "$admin_email" ]; then
|
||||||
admin_email="${admin}@${domain}"
|
admin_email="${admin}@${domain}"
|
||||||
ynh_app_setting_set --app="$app" --key=admin_email --value="$admin_email"
|
ynh_app_setting_set --app=$app --key=admin_email --value="$admin_email"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
default_from_email=$(ynh_app_setting_get --app="$app" --key=default_from_email)
|
|
||||||
if [ -z "$default_from_email" ]; then
|
if [ -z "$default_from_email" ]; then
|
||||||
default_from_email="${app}@${domain}"
|
default_from_email="${app}@${domain}"
|
||||||
ynh_app_setting_set --app="$app" --key=default_from_email --value="$default_from_email"
|
ynh_app_setting_set --app=$app --key=default_from_email --value="$default_from_email"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# BACKUP BEFORE UPGRADE THEN ACTIVE TRAP
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Backing up $app before upgrading (may take a while)..." --weight=40
|
|
||||||
|
|
||||||
# Backup the current version of the app
|
|
||||||
ynh_backup_before_upgrade
|
|
||||||
ynh_clean_setup () {
|
|
||||||
# restore it if the upgrade fails
|
|
||||||
ynh_restore_upgradebackup
|
|
||||||
}
|
|
||||||
# Exit if an error occurs during the execution of the script
|
|
||||||
ynh_abort_if_errors
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# STANDARD UPGRADE STEPS
|
# STANDARD UPGRADE STEPS
|
||||||
#=================================================
|
#=================================================
|
||||||
|
@ -76,91 +37,44 @@ ynh_abort_if_errors
|
||||||
#=================================================
|
#=================================================
|
||||||
ynh_script_progression --message="Stopping systemd service '$app'..." --weight=5
|
ynh_script_progression --message="Stopping systemd service '$app'..." --weight=5
|
||||||
|
|
||||||
ynh_systemd_action --service_name="$app" --action="stop"
|
ynh_systemd_action --service_name=$app --action="stop" --log_path="$log_file"
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# NGINX CONFIGURATION
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Upgrading nginx web server configuration..."
|
|
||||||
|
|
||||||
# Create a dedicated nginx config
|
|
||||||
# https://yunohost.org/en/contribute/packaging_apps/helpers
|
|
||||||
# https://github.com/YunoHost/yunohost/blob/dev/helpers/nginx
|
|
||||||
ynh_add_nginx_config "public_path" "port"
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# SPECIFIC UPGRADE
|
|
||||||
#=================================================
|
|
||||||
# Update dependencies
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Upgrading dependencies..." --weight=20
|
|
||||||
|
|
||||||
ynh_exec_warn_less ynh_install_app_dependencies "$pkg_dependencies"
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# CREATE DEDICATED USER
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Making sure dedicated system user exists..."
|
|
||||||
|
|
||||||
# Create a system user
|
|
||||||
ynh_system_user_create --username="$app" --home_dir="$final_path" --use_shell
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# SETUP SYSTEMD
|
# SETUP SYSTEMD
|
||||||
#=================================================
|
#=================================================
|
||||||
ynh_script_progression --message="Configuring systemd service '$app'..." --weight=5
|
ynh_script_progression --message="Configuring systemd service '$app'..." --weight=5
|
||||||
|
|
||||||
ynh_add_systemd_config --service="$app" --template="systemd.service"
|
ynh_add_systemd_config --service=$app --template="systemd.service"
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# PYTHON VIRTUALENV
|
# PYTHON VIRTUALENV
|
||||||
#=================================================
|
#=================================================
|
||||||
ynh_script_progression --message="Recreate Python virtualenv..." --weight=5
|
ynh_script_progression --message="Create and setup Python virtualenv..." --weight=45
|
||||||
|
cp ../conf/requirements.txt "$data_dir/requirements.txt"
|
||||||
# Always recreate everything fresh with current python version
|
myynh_setup_python_venv
|
||||||
ynh_secure_remove "${final_path}/venv"
|
|
||||||
|
|
||||||
# Skip pip because of: https://github.com/YunoHost/issues/issues/1960
|
|
||||||
python3 -m venv --without-pip "${final_path}/venv"
|
|
||||||
|
|
||||||
cp ../conf/requirements.txt "$final_path/requirements.txt"
|
|
||||||
chown -R "$app:" "$final_path"
|
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# PIP INSTALLATION
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Install project via pip..." --weight=45
|
|
||||||
#run source in a 'sub shell'
|
|
||||||
(
|
|
||||||
set +o nounset
|
|
||||||
source "${final_path}/venv/bin/activate"
|
|
||||||
set -o nounset
|
|
||||||
ynh_exec_as $app $final_path/venv/bin/python3 -m ensurepip
|
|
||||||
ynh_exec_as $app $final_path/venv/bin/pip3 install --upgrade wheel pip setuptools
|
|
||||||
ynh_exec_as $app $final_path/venv/bin/pip3 install --no-deps -r "$final_path/requirements.txt"
|
|
||||||
)
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# copy config files
|
# copy config files
|
||||||
# ================================================
|
# ================================================
|
||||||
ynh_script_progression --message="Create project configuration files..."
|
ynh_script_progression --message="Create project configuration files..."
|
||||||
|
|
||||||
ynh_add_config --template="gunicorn.conf.py" --destination="$final_path/gunicorn.conf.py"
|
ynh_add_config --template="gunicorn.conf.py" --destination="$data_dir/gunicorn.conf.py"
|
||||||
|
|
||||||
ynh_add_config --template="manage.py" --destination="$final_path/manage.py"
|
ynh_add_config --template="manage.py" --destination="$data_dir/manage.py"
|
||||||
chmod +x "$final_path/manage.py"
|
chmod -c +x "$data_dir/manage.py"
|
||||||
|
|
||||||
ynh_add_config --template="settings.py" --destination="$final_path/settings.py"
|
ynh_add_config --template="settings.py" --destination="$data_dir/settings.py"
|
||||||
ynh_add_config --template="setup_user.py" --destination="$final_path/setup_user.py"
|
ynh_add_config --template="setup_user.py" --destination="$data_dir/setup_user.py"
|
||||||
ynh_add_config --template="urls.py" --destination="$final_path/urls.py"
|
ynh_add_config --template="urls.py" --destination="$data_dir/urls.py"
|
||||||
ynh_add_config --template="wsgi.py" --destination="$final_path/wsgi.py"
|
ynh_add_config --template="wsgi.py" --destination="$data_dir/wsgi.py"
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# MIGRATE PYINVENTORY
|
# MIGRATE PYINVENTORY
|
||||||
#=================================================
|
#=================================================
|
||||||
ynh_script_progression --message="migrate/collectstatic/createadmin..." --weight=10
|
ynh_script_progression --message="migrate/collectstatic/createadmin..." --weight=10
|
||||||
|
|
||||||
cd "$final_path" || exit
|
cd "$data_dir" || exit
|
||||||
|
|
||||||
# Just for debugging:
|
# Just for debugging:
|
||||||
./manage.py diffsettings
|
./manage.py diffsettings
|
||||||
|
@ -182,43 +96,23 @@ cd "$final_path" || exit
|
||||||
ynh_script_progression --message="Upgrading logrotate configuration..."
|
ynh_script_progression --message="Upgrading logrotate configuration..."
|
||||||
|
|
||||||
# Use logrotate to manage app-specific logfile(s)
|
# Use logrotate to manage app-specific logfile(s)
|
||||||
ynh_use_logrotate --non-append
|
ynh_use_logrotate --logfile="$log_file" --specific_user=$app --non-append
|
||||||
|
|
||||||
#=================================================
|
|
||||||
# INTEGRATE SERVICE IN YUNOHOST
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Integrating service in YunoHost..."
|
|
||||||
|
|
||||||
yunohost service add $app --log="${log_file}"
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# GENERIC FINALIZATION
|
# GENERIC FINALIZATION
|
||||||
#=================================================
|
#=================================================
|
||||||
# SECURE FILES AND DIRECTORIES
|
# SECURE FILES AND DIRECTORIES
|
||||||
#=================================================
|
#=================================================
|
||||||
|
ynh_script_progression --message="Set file permissions..."
|
||||||
# Set permissions to app files
|
myynh_fix_file_permissions
|
||||||
chown -R "$app:" "$log_path"
|
|
||||||
chown -R "$app:www-data" "$public_path"
|
|
||||||
chown -R "$app:" "$final_path"
|
|
||||||
|
|
||||||
chmod o-rwx "$log_path"
|
|
||||||
chmod o-rwx "$public_path"
|
|
||||||
chmod o-rwx "$final_path"
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# Start the app server via systemd
|
# Start the app server via systemd
|
||||||
#=================================================
|
#=================================================
|
||||||
ynh_script_progression --message="Starting systemd service '$app'..." --weight=5
|
ynh_script_progression --message="Starting systemd service '$app'..." --weight=5
|
||||||
|
|
||||||
ynh_systemd_action --service_name="$app" --action="start"
|
yunohost service add $app
|
||||||
|
ynh_systemd_action --service_name=$app --action="start" --log_path="$log_file"
|
||||||
#=================================================
|
|
||||||
# RELOAD NGINX
|
|
||||||
#=================================================
|
|
||||||
ynh_script_progression --message="Reloading nginx web server..."
|
|
||||||
|
|
||||||
ynh_systemd_action --service_name=nginx --action=reload
|
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# END OF SCRIPT
|
# END OF SCRIPT
|
||||||
|
|
31
tests.toml
Normal file
31
tests.toml
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
test_format = 1.0
|
||||||
|
|
||||||
|
[default]
|
||||||
|
|
||||||
|
# ------------
|
||||||
|
# Tests to run
|
||||||
|
# ------------
|
||||||
|
|
||||||
|
# NB: the tests to run are automatically deduced by the CI script according to the
|
||||||
|
# content of the app's manifest. The declarations below allow to customize which
|
||||||
|
# tests are ran, possibly add special test suite to test special args, or
|
||||||
|
# declare which commits to test upgrade from.
|
||||||
|
#
|
||||||
|
# You can also decide (though this is discouraged!) to ban/ignore some tests,
|
||||||
|
|
||||||
|
# The test IDs to be used in only/exclude statements are:
|
||||||
|
# install.root, install.subdir, install.nourl, install.multi, backup_restore, upgrade, upgrade.someCommitId change_url
|
||||||
|
#exclude = ["install.private", "install.multi"]
|
||||||
|
|
||||||
|
# -------------------------------
|
||||||
|
# Default args to use for install
|
||||||
|
# -------------------------------
|
||||||
|
|
||||||
|
# By default, the CI will automagically fill the 'standard' args
|
||||||
|
# such as domain, path, admin, is_public and password with relevant values
|
||||||
|
# and also install args with a "default" provided in the manifest..
|
||||||
|
# It should only make sense to declare custom args here for args with no default values
|
||||||
|
|
||||||
|
args.default_from_email = "default_from_email@example.tld"
|
||||||
|
args.admin_email = "admin_email@example.tld"
|
||||||
|
|
|
@ -11,7 +11,7 @@ import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import django
|
import django
|
||||||
from django_yunohost_integration.local_test import create_local_test
|
from django_yunohost_integration.local_test import CreateResults, create_local_test
|
||||||
|
|
||||||
|
|
||||||
BASE_PATH = Path(__file__).parent.parent
|
BASE_PATH = Path(__file__).parent.parent
|
||||||
|
@ -21,23 +21,23 @@ os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
|
||||||
|
|
||||||
def pytest_configure():
|
def pytest_configure():
|
||||||
print('Compile YunoHost files...')
|
print('Compile YunoHost files...')
|
||||||
final_path = create_local_test(
|
result: CreateResults = create_local_test(
|
||||||
django_settings_path=BASE_PATH / 'conf' / 'settings.py',
|
django_settings_path=BASE_PATH / 'conf' / 'settings.py',
|
||||||
destination=BASE_PATH / 'local_test',
|
destination=BASE_PATH / 'local_test',
|
||||||
runserver=False,
|
runserver=False,
|
||||||
extra_replacements={
|
extra_replacements={
|
||||||
'__DEBUG_ENABLED__': '0',
|
'__DEBUG_ENABLED__': 'NO', # "YES" or "NO" string
|
||||||
'__LOG_LEVEL__': 'INFO',
|
'__LOG_LEVEL__': 'INFO',
|
||||||
'__ADMIN_EMAIL__': 'foo-bar@test.tld',
|
'__ADMIN_EMAIL__': 'foo-bar@test.tld',
|
||||||
'__DEFAULT_FROM_EMAIL__': 'django_app@test.tld',
|
'__DEFAULT_FROM_EMAIL__': 'django_app@test.tld',
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
print('Local test files created here:')
|
print('Local test files created:')
|
||||||
print(f'"{final_path}"')
|
print(result)
|
||||||
|
|
||||||
os.chdir(final_path)
|
os.chdir(result.data_dir_path)
|
||||||
final_home_str = str(final_path)
|
data_dir = str(result.data_dir_path)
|
||||||
if final_home_str not in sys.path:
|
if data_dir not in sys.path:
|
||||||
sys.path.insert(0, final_home_str)
|
sys.path.insert(0, data_dir)
|
||||||
|
|
||||||
django.setup()
|
django.setup()
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import for_runners
|
||||||
from axes.models import AccessLog
|
from axes.models import AccessLog
|
||||||
from bx_django_utils.test_utils.html_assertion import HtmlAssertionMixin
|
from bx_django_utils.test_utils.html_assertion import HtmlAssertionMixin, assert_html_response_snapshot
|
||||||
from django.conf import LazySettings, settings
|
from django.conf import LazySettings, settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.template.defaulttags import CsrfTokenNode
|
||||||
from django.test import override_settings
|
from django.test import override_settings
|
||||||
from django.test.testcases import TestCase
|
from django.test.testcases import TestCase
|
||||||
from django.urls.base import reverse
|
from django.urls.base import reverse
|
||||||
from django_yunohost_integration.test_utils import generate_basic_auth
|
from django_yunohost_integration.test_utils import generate_basic_auth
|
||||||
|
|
||||||
import for_runners
|
|
||||||
|
|
||||||
|
|
||||||
@override_settings(DEBUG=False)
|
@override_settings(DEBUG=False)
|
||||||
class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
|
class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
|
||||||
|
@ -24,15 +26,15 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
|
||||||
|
|
||||||
assert settings.PATH_URL == 'app_path'
|
assert settings.PATH_URL == 'app_path'
|
||||||
|
|
||||||
assert str(settings.FINALPATH).endswith('/local_test/opt_yunohost')
|
assert str(settings.DATA_DIR_PATH).endswith('/local_test/opt_yunohost')
|
||||||
assert str(settings.PUBLIC_PATH).endswith('/local_test/var_www')
|
assert str(settings.INSTALL_DIR_PATH).endswith('/local_test/var_www')
|
||||||
assert str(settings.LOG_FILE).endswith('/local_test/var_log_django-for-runners.log')
|
assert str(settings.LOG_FILE_PATH).endswith('/local_test/var_log_django-for-runners.log')
|
||||||
|
|
||||||
assert settings.ROOT_URLCONF == 'urls'
|
assert settings.ROOT_URLCONF == 'urls'
|
||||||
|
|
||||||
def test_config_panel_settings(self):
|
def test_config_panel_settings(self):
|
||||||
# config_panel.toml settings, set via tests.conftest.pytest_configure():
|
# config_panel.toml settings, set via tests.conftest.pytest_configure():
|
||||||
assert settings.DEBUG_ENABLED == '0' and settings.DEBUG is False
|
assert settings.DEBUG_ENABLED == 'NO' and settings.DEBUG is False
|
||||||
assert settings.LOG_LEVEL == 'INFO'
|
assert settings.LOG_LEVEL == 'INFO'
|
||||||
assert settings.ADMIN_EMAIL == 'foo-bar@test.tld'
|
assert settings.ADMIN_EMAIL == 'foo-bar@test.tld'
|
||||||
assert settings.DEFAULT_FROM_EMAIL == 'django_app@test.tld'
|
assert settings.DEFAULT_FROM_EMAIL == 'django_app@test.tld'
|
||||||
|
@ -71,13 +73,14 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
|
||||||
|
|
||||||
self.client.cookies['SSOwAuthUser'] = 'test'
|
self.client.cookies['SSOwAuthUser'] = 'test'
|
||||||
|
|
||||||
response = self.client.get(
|
with patch.object(CsrfTokenNode, 'render', return_value='MockedCsrfTokenNode'):
|
||||||
path='/app_path/',
|
response = self.client.get(
|
||||||
HTTP_REMOTE_USER='test',
|
path='/app_path/',
|
||||||
HTTP_AUTH_USER='test',
|
HTTP_REMOTE_USER='test',
|
||||||
HTTP_AUTHORIZATION='basic dGVzdDp0ZXN0MTIz',
|
HTTP_AUTH_USER='test',
|
||||||
secure=True,
|
HTTP_AUTHORIZATION='basic dGVzdDp0ZXN0MTIz',
|
||||||
)
|
secure=True,
|
||||||
|
)
|
||||||
|
|
||||||
assert User.objects.count() == 1
|
assert User.objects.count() == 1
|
||||||
user = User.objects.first()
|
user = User.objects.first()
|
||||||
|
@ -93,6 +96,7 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
|
||||||
'<strong>test</strong>',
|
'<strong>test</strong>',
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
assert_html_response_snapshot(response, query_selector='#container', validate=False)
|
||||||
|
|
||||||
def test_wrong_auth_user(self):
|
def test_wrong_auth_user(self):
|
||||||
assert User.objects.count() == 0
|
assert User.objects.count() == 0
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
<div id="container">
|
||||||
|
<!-- Header -->
|
||||||
|
<div id="header">
|
||||||
|
<div id="branding">
|
||||||
|
<h1 id="site-name">
|
||||||
|
<a href="/app_path/">
|
||||||
|
<img alt="Logo" height="40px" src="/app_path/static/Django-ForRunners.svg"/>
|
||||||
|
Django-ForRunners v0.17.4
|
||||||
|
</a>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<div id="user-tools">
|
||||||
|
Welcome,
|
||||||
|
<strong>
|
||||||
|
test
|
||||||
|
</strong>
|
||||||
|
.
|
||||||
|
<a href="/">
|
||||||
|
View site
|
||||||
|
</a>
|
||||||
|
/
|
||||||
|
<a href="/app_path/password_change/">
|
||||||
|
Change password
|
||||||
|
</a>
|
||||||
|
/
|
||||||
|
<form action="/app_path/logout/" id="logout-form" method="post">
|
||||||
|
MockedCsrfTokenNode
|
||||||
|
<button type="submit">
|
||||||
|
Log out
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
<button class="theme-toggle">
|
||||||
|
<div class="visually-hidden theme-label-when-auto">
|
||||||
|
Toggle theme (current theme: auto)
|
||||||
|
</div>
|
||||||
|
<div class="visually-hidden theme-label-when-light">
|
||||||
|
Toggle theme (current theme: light)
|
||||||
|
</div>
|
||||||
|
<div class="visually-hidden theme-label-when-dark">
|
||||||
|
Toggle theme (current theme: dark)
|
||||||
|
</div>
|
||||||
|
<svg aria-hidden="true" class="theme-icon-when-auto">
|
||||||
|
<use xlink:href="#icon-auto">
|
||||||
|
</use>
|
||||||
|
</svg>
|
||||||
|
<svg aria-hidden="true" class="theme-icon-when-dark">
|
||||||
|
<use xlink:href="#icon-moon">
|
||||||
|
</use>
|
||||||
|
</svg>
|
||||||
|
<svg aria-hidden="true" class="theme-icon-when-light">
|
||||||
|
<use xlink:href="#icon-sun">
|
||||||
|
</use>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- END Header -->
|
||||||
|
<div class="main" id="main">
|
||||||
|
<div class="content" id="content-start" tabindex="-1">
|
||||||
|
<!-- Content -->
|
||||||
|
<div class="colMS" id="content">
|
||||||
|
<h1>
|
||||||
|
Site administration
|
||||||
|
</h1>
|
||||||
|
<div id="content-main">
|
||||||
|
<p>
|
||||||
|
You don’t have permission to view or edit anything.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div id="content-related">
|
||||||
|
<div class="module" id="recent-actions-module">
|
||||||
|
<h2>
|
||||||
|
Recent actions
|
||||||
|
</h2>
|
||||||
|
<h3>
|
||||||
|
My actions
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
None available
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br class="clear"/>
|
||||||
|
</div>
|
||||||
|
<!-- END Content -->
|
||||||
|
<div id="footer">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -1,7 +1,4 @@
|
||||||
import difflib
|
|
||||||
import os
|
import os
|
||||||
import shutil
|
|
||||||
import subprocess
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
|
@ -15,8 +12,9 @@ from bx_django_utils.filename import clean_filename
|
||||||
from bx_py_utils.path import assert_is_dir, assert_is_file
|
from bx_py_utils.path import assert_is_dir, assert_is_file
|
||||||
from django_tools.unittest_utils.project_setup import check_editor_config
|
from django_tools.unittest_utils.project_setup import check_editor_config
|
||||||
from django_yunohost_integration.test_utils import assert_project_version
|
from django_yunohost_integration.test_utils import assert_project_version
|
||||||
|
from for_runners import __version__ as upstream_version
|
||||||
|
|
||||||
from for_runners import __version__
|
from for_runners_ynh import __version__
|
||||||
|
|
||||||
|
|
||||||
PACKAGE_ROOT = Path(__file__).parent.parent
|
PACKAGE_ROOT = Path(__file__).parent.parent
|
||||||
|
@ -31,6 +29,18 @@ def assert_file_contains_string(file_path, string):
|
||||||
|
|
||||||
|
|
||||||
def test_version():
|
def test_version():
|
||||||
|
assert '+ynh' in __version__, f'{__version__!r} does not contain "+ynh"'
|
||||||
|
assert upstream_version in __version__, f'{__version__!r} does not contain {upstream_version!r}'
|
||||||
|
|
||||||
|
# pyproject.toml needs a PEP 440 conform version and used "+ynh"
|
||||||
|
# the YunoHost syntax is: "~ynh", just "convert this:
|
||||||
|
manifest_version = __version__.replace('+', '~')
|
||||||
|
|
||||||
|
assert_file_contains_string(
|
||||||
|
file_path=Path(PACKAGE_ROOT, 'manifest.toml'),
|
||||||
|
string=f'version = "{manifest_version}"',
|
||||||
|
)
|
||||||
|
|
||||||
if 'GITHUB_ACTION' not in os.environ:
|
if 'GITHUB_ACTION' not in os.environ:
|
||||||
# Github has a rate-limiting... So don't fetch the API if we run as GitHub action
|
# Github has a rate-limiting... So don't fetch the API if we run as GitHub action
|
||||||
assert_project_version(
|
assert_project_version(
|
||||||
|
@ -38,62 +48,6 @@ def test_version():
|
||||||
github_project_url='https://github.com/jedie/django-for-runners',
|
github_project_url='https://github.com/jedie/django-for-runners',
|
||||||
)
|
)
|
||||||
|
|
||||||
pyproject_toml_path = Path(PACKAGE_ROOT, 'pyproject.toml')
|
|
||||||
pyproject_toml = tomllib.loads(pyproject_toml_path.read_text(encoding='UTF-8'))
|
|
||||||
pyproject_version = pyproject_toml['tool']['poetry']['version']
|
|
||||||
assert pyproject_version.startswith(
|
|
||||||
f'{__version__}+ynh'
|
|
||||||
), f'{pyproject_version!r} does not start with "{__version__}+ynh"'
|
|
||||||
|
|
||||||
# pyproject.toml needs a PEP 440 conform version and used "+ynh"
|
|
||||||
# the YunoHost syntax is: "~ynh", just "convert this:
|
|
||||||
manifest_version = pyproject_version.replace('+', '~')
|
|
||||||
|
|
||||||
assert_file_contains_string(
|
|
||||||
file_path=Path(PACKAGE_ROOT, 'manifest.json'),
|
|
||||||
string=f'"version": "{manifest_version}"',
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def poetry_check_output(*args):
|
|
||||||
poerty_bin = shutil.which('poetry')
|
|
||||||
|
|
||||||
output = subprocess.check_output(
|
|
||||||
(poerty_bin,) + args,
|
|
||||||
text=True,
|
|
||||||
env=os.environ,
|
|
||||||
stderr=subprocess.STDOUT,
|
|
||||||
cwd=str(PACKAGE_ROOT),
|
|
||||||
)
|
|
||||||
print(output)
|
|
||||||
return output
|
|
||||||
|
|
||||||
|
|
||||||
def test_poetry_check():
|
|
||||||
output = poetry_check_output('check')
|
|
||||||
assert output == 'All set!\n'
|
|
||||||
|
|
||||||
|
|
||||||
def test_requirements_txt():
|
|
||||||
requirements_txt = PACKAGE_ROOT / 'conf' / 'requirements.txt'
|
|
||||||
assert_is_file(requirements_txt)
|
|
||||||
|
|
||||||
output = poetry_check_output('export', '-f', 'requirements.txt')
|
|
||||||
assert 'Warning' not in output
|
|
||||||
|
|
||||||
current_content = requirements_txt.read_text()
|
|
||||||
|
|
||||||
diff = '\n'.join(
|
|
||||||
difflib.unified_diff(
|
|
||||||
current_content.splitlines(),
|
|
||||||
output.splitlines(),
|
|
||||||
fromfile=str(requirements_txt),
|
|
||||||
tofile='FRESH EXPORT',
|
|
||||||
)
|
|
||||||
)
|
|
||||||
print(diff)
|
|
||||||
assert diff == '', f'{requirements_txt} is not up-to-date! (Hint: call: "make update")'
|
|
||||||
|
|
||||||
|
|
||||||
def test_screenshot_filenames():
|
def test_screenshot_filenames():
|
||||||
"""
|
"""
|
||||||
|
@ -118,40 +72,36 @@ def test_check_editor_config():
|
||||||
check_editor_config(package_root=PACKAGE_ROOT)
|
check_editor_config(package_root=PACKAGE_ROOT)
|
||||||
|
|
||||||
|
|
||||||
def _call_make(*args):
|
class ManifestTestCase(TestCase):
|
||||||
make_bin = shutil.which('make')
|
def test_manifest_toml(self):
|
||||||
assert make_bin
|
manifest_path = PACKAGE_ROOT / 'manifest.toml'
|
||||||
return subprocess.check_output(
|
assert_is_file(manifest_path)
|
||||||
(make_bin,) + args,
|
|
||||||
text=True,
|
|
||||||
env=dict(PATH=os.environ['PATH']),
|
|
||||||
stderr=subprocess.STDOUT,
|
|
||||||
cwd=str(PACKAGE_ROOT),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
cfg = tomllib.loads(manifest_path.read_text(encoding='UTF-8'))
|
||||||
|
|
||||||
def test_check_code_style():
|
self.assertEqual(cfg['packaging_format'], 2)
|
||||||
# First try:
|
|
||||||
try:
|
|
||||||
_call_make('lint')
|
|
||||||
except subprocess.CalledProcessError:
|
|
||||||
# Fix and test again:
|
|
||||||
try:
|
|
||||||
_call_make('fix-code-style')
|
|
||||||
_call_make('lint')
|
|
||||||
except subprocess.CalledProcessError as err:
|
|
||||||
raise AssertionError(f'Linting error:\n{"-"*100}\n{err.stdout}\n{"-"*100}')
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigPanelTestCase(TestCase):
|
|
||||||
def test_config_panel_toml(self):
|
|
||||||
config_panel_path = PACKAGE_ROOT / 'config_panel.toml'
|
|
||||||
assert_is_file(config_panel_path)
|
|
||||||
|
|
||||||
cfg = tomllib.loads(config_panel_path.read_text(encoding='UTF-8'))
|
|
||||||
|
|
||||||
self.assertEqual(cfg['version'], '1.0')
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
set(cfg['main']['config'].keys()),
|
set(cfg['install'].keys()),
|
||||||
{'name', 'default_from_email', 'admin_email', 'debug_enabled', 'log_level'},
|
{
|
||||||
|
'admin',
|
||||||
|
'admin_email',
|
||||||
|
'debug_enabled',
|
||||||
|
'default_from_email',
|
||||||
|
'domain',
|
||||||
|
'init_main_permission',
|
||||||
|
'log_level',
|
||||||
|
'path',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
set(cfg['resources'].keys()),
|
||||||
|
{
|
||||||
|
'apt',
|
||||||
|
'data_dir',
|
||||||
|
'database',
|
||||||
|
'install_dir',
|
||||||
|
'permissions',
|
||||||
|
'ports',
|
||||||
|
'system_user',
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue