mirror of
https://github.com/YunoHost-Apps/django-for-runners_ynh.git
synced 2024-09-03 18:26:16 +02:00
commit
65656fe5a1
40 changed files with 3655 additions and 4370 deletions
16
.github/workflows/package_linter.yml
vendored
16
.github/workflows/package_linter.yml
vendored
|
@ -15,24 +15,24 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
# https://github.com/marketplace/actions/checkout
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/cache@v3
|
||||
# https://github.com/marketplace/actions/cache
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
path: ~/.cache/
|
||||
key: dot-cache-files
|
||||
python-version: '3.9'
|
||||
|
||||
- name: 'Install dependencies'
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install toml
|
||||
|
||||
- name: 'Clone YunoHost apps package linter'
|
||||
run: |
|
||||
git clone --depth=1 https://github.com/YunoHost/package_linter ~/package_linter
|
||||
|
||||
- name: 'Install requirements'
|
||||
run: pip3 install toml
|
||||
|
||||
- name: 'Run linter'
|
||||
run: |
|
||||
~/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
|
||||
!.editorconfig
|
||||
!.flake8
|
||||
!.gitignore
|
||||
!.gitkeep
|
||||
!/doc/screenshots/.gitkeep
|
||||
__pycache__
|
||||
|
||||
secret.txt
|
||||
/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
|
|
@ -34,7 +34,7 @@ This package for YunoHost used [django-yunohost-integration](https://github.com/
|
|||
More screenshots are here: [jedie.github.io/tree/master/screenshots/django-for-runners](https://github.com/jedie/jedie.github.io/tree/master/screenshots/django-for-runners/README.creole)
|
||||
|
||||
|
||||
**Shipped version:** 0.17.3~ynh3
|
||||
**Shipped version:** 0.17.4~ynh1
|
||||
|
||||
## Screenshots
|
||||
|
||||
|
@ -200,9 +200,10 @@ Notes:
|
|||
|
||||
## Documentation and resources
|
||||
|
||||
* Official app website: <https://github.com/YunoHost-Apps/django-for-runners_ynh>
|
||||
* Official user documentation: <https://github.com/jedie/django-for-runners>
|
||||
* Official admin documentation: <https://github.com/YunoHost-Apps/django-for-runners_ynh>
|
||||
* Upstream app code repository: <https://github.com/jedie/django-for-runners>
|
||||
* Upstream app code repository: <https://github.com/YunoHost-Apps/django-for-runners_ynh>
|
||||
* YunoHost Store: <https://apps.yunohost.org/app/django-for-runners>
|
||||
* Report a bug: <https://github.com/YunoHost-Apps/django-for-runners_ynh/issues>
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ This package for YunoHost used [django-yunohost-integration](https://github.com/
|
|||
More screenshots are here: [jedie.github.io/tree/master/screenshots/django-for-runners](https://github.com/jedie/jedie.github.io/tree/master/screenshots/django-for-runners/README.creole)
|
||||
|
||||
|
||||
**Version incluse :** 0.17.3~ynh3
|
||||
**Version incluse :** 0.17.4~ynh1
|
||||
|
||||
## Captures d’écran
|
||||
|
||||
|
@ -200,9 +200,10 @@ Notes:
|
|||
|
||||
## Documentations et ressources
|
||||
|
||||
* Site officiel de l’app : <https://github.com/YunoHost-Apps/django-for-runners_ynh>
|
||||
* Documentation officielle utilisateur : <https://github.com/jedie/django-for-runners>
|
||||
* Documentation officielle de l’admin : <https://github.com/YunoHost-Apps/django-for-runners_ynh>
|
||||
* Dépôt de code officiel de l’app : <https://github.com/jedie/django-for-runners>
|
||||
* Dépôt de code officiel de l’app : <https://github.com/YunoHost-Apps/django-for-runners_ynh>
|
||||
* YunoHost Store: <https://apps.yunohost.org/app/django-for-runners>
|
||||
* Signaler un bug : <https://github.com/YunoHost-Apps/django-for-runners_ynh/issues>
|
||||
|
||||
|
|
|
@ -17,4 +17,4 @@ accesslog = '__LOG_FILE__'
|
|||
errorlog = '__LOG_FILE__'
|
||||
|
||||
# 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 sys
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
|
||||
location __PATH__/static/ {
|
||||
# Service static files by nginx
|
||||
# e.g.: /var/www/$app/static
|
||||
alias __PUBLIC_PATH__/static/;
|
||||
# e.g.: /var/www/$app/static/
|
||||
alias __INSTALL_DIR__/static/;
|
||||
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.
|
||||
# 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,
|
||||
# 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
|
||||
|
||||
|
||||
FINALPATH = __Path('__FINALPATH__') # /opt/yunohost/$app
|
||||
assert FINALPATH.is_dir(), f'Directory not exists: {FINALPATH}'
|
||||
DATA_DIR_PATH = __Path('__DATA_DIR__') # /home/yunohost.app/$app/
|
||||
assert DATA_DIR_PATH.is_dir(), f'Directory not exists: {DATA_DIR_PATH}'
|
||||
|
||||
PUBLIC_PATH = __Path('__PUBLIC_PATH__') # /var/www/$app
|
||||
assert PUBLIC_PATH.is_dir(), f'Directory not exists: {PUBLIC_PATH}'
|
||||
INSTALL_DIR_PATH = __Path('__INSTALL_DIR__') # /var/www/$app/
|
||||
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
|
||||
assert LOG_FILE.is_file(), f'File not exists: {LOG_FILE}'
|
||||
LOG_FILE_PATH = __Path('__LOG_FILE__') # /var/log/$app/for_runners_ynh.log
|
||||
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('/')
|
||||
|
||||
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:
|
||||
|
||||
DEBUG_ENABLED = '__DEBUG_ENABLED__'
|
||||
DEBUG = bool(int(DEBUG_ENABLED))
|
||||
DEBUG = DEBUG_ENABLED == 'YES'
|
||||
|
||||
LOG_LEVEL = '__LOG_LEVEL__'
|
||||
ADMIN_EMAIL = '__ADMIN_EMAIL__'
|
||||
|
@ -52,8 +52,6 @@ DEFAULT_FROM_EMAIL = '__DEFAULT_FROM_EMAIL__'
|
|||
# Function that will be called to finalize a user profile:
|
||||
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:
|
||||
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')
|
||||
|
||||
|
||||
SECRET_KEY = __get_or_create_secret(DATA_DIR_PATH / 'secret.txt') # /home/yunohost.app/$app/secret.txt
|
||||
|
||||
|
||||
MIDDLEWARE.insert(
|
||||
MIDDLEWARE.index('django.contrib.auth.middleware.AuthenticationMiddleware') + 1,
|
||||
# login a user via HTTP_REMOTE_USER header from SSOwat:
|
||||
|
@ -154,14 +155,14 @@ else:
|
|||
STATIC_URL = '/static/'
|
||||
MEDIA_URL = '/media/'
|
||||
|
||||
STATIC_ROOT = str(PUBLIC_PATH / 'static')
|
||||
MEDIA_ROOT = str(PUBLIC_PATH / 'media')
|
||||
STATIC_ROOT = str(INSTALL_DIR_PATH / 'static')
|
||||
MEDIA_ROOT = str(INSTALL_DIR_PATH / 'media')
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# 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:
|
||||
LOGGING['loggers']['for_runners'] = {
|
||||
|
|
|
@ -5,9 +5,9 @@ After=redis.service postgresql.service
|
|||
[Service]
|
||||
User=__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
|
||||
StandardError=syslog
|
||||
|
|
|
@ -6,7 +6,7 @@ from for_runners.views.media_files import UserMediaView
|
|||
|
||||
|
||||
if settings.PATH_URL:
|
||||
# settings.PATH_URL is the $YNH_APP_ARG_PATH
|
||||
# settings.PATH_URL is __PATH__
|
||||
# Prefix all urls with "PATH_URL":
|
||||
urlpatterns = [
|
||||
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
|
||||
|
||||
version = "1.0"
|
||||
|
@ -14,13 +15,16 @@ services = ["__APP__"]
|
|||
ask = "from email"
|
||||
type = "email"
|
||||
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]
|
||||
ask = "ADMIN email"
|
||||
type = "email"
|
||||
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]
|
||||
ask = "DEBUG mode"
|
||||
|
@ -28,11 +32,11 @@ services = ["__APP__"]
|
|||
yes = "1"
|
||||
no = "0"
|
||||
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]
|
||||
type = "string"
|
||||
ask = "Log Level"
|
||||
choices = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
||||
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
135
pyproject.toml
135
pyproject.toml
|
@ -1,61 +1,87 @@
|
|||
[tool.poetry]
|
||||
[project]
|
||||
name = "for_runners_ynh"
|
||||
version = "0.17.3+ynh3"
|
||||
dynamic = ["version"]
|
||||
description = "YunoHost app package for https://github.com/jedie/django-for-runners"
|
||||
authors = ["Jens Diemer <git@jensdiemer.de>"]
|
||||
homepage = "https://github.com/YunoHost-Apps/django-for-runners_ynh"
|
||||
license = "GPL-3.0-or-later"
|
||||
readme = 'README.md'
|
||||
|
||||
[tool.poetry.urls]
|
||||
"Bug Tracker" = "https://github.com/jedie/django-for-runners/issues"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.9,<4.0.0" # Stay with 3.9 until YunoHost used >=Debian 11 (Bullseye)
|
||||
#
|
||||
django_for_runners = ">=0.17.3" # https://github.com/jedie/django-for-runners
|
||||
license = {text = "GPL-3.0-or-later"}
|
||||
readme = "README.md"
|
||||
authors = [
|
||||
{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 = {version = ">=0.5.1", extras = ["ynh"]} # https://github.com/YunoHost-Apps/django_yunohost_integration
|
||||
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
bx_py_utils = "*" # https://github.com/boxine/bx_py_utils
|
||||
bx_django_utils = "*" # https://github.com/boxine/bx_django_utils
|
||||
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/
|
||||
"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
|
||||
|
||||
# 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"] }
|
||||
"darker[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
|
||||
# indirect depencies added because of bug:
|
||||
# https://github.com/pypa/pip/issues/9644 / https://github.com/jazzband/pip-tools/issues/1866
|
||||
# to avoid errors like:
|
||||
# In --require-hashes mode, all requirements must have their versions pinned with ==. These do not: ...
|
||||
"tomli", # Only needed for Python <3.11
|
||||
"exceptiongroup", # needed by pytest
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Documentation = "https://github.com/YunoHost-Apps/django-for-runners_ynh"
|
||||
Source = "https://github.com/YunoHost-Apps/django-for-runners_ynh"
|
||||
|
||||
[project.scripts]
|
||||
for_runners_ynh_app = "for_runners_ynh.__main__:main"
|
||||
for_runners_ynh_dev = "for_runners_ynh.cli.dev:main"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
requires = ["setuptools>=61.0", "setuptools_scm>=7.1"]
|
||||
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]
|
||||
src = ['.']
|
||||
# YunoHost apps still use "master" istead of "main", isn't it?
|
||||
revision = "origin/master..."
|
||||
line_length = 119
|
||||
verbose = true
|
||||
|
@ -77,7 +103,7 @@ log_level = "INFO"
|
|||
atomic=true
|
||||
profile='black'
|
||||
skip_glob=[".*", "*/htmlcov/*","*/migrations/*","*/local_test/*"]
|
||||
known_first_party=['for_runners']
|
||||
known_first_party=['django_for_runners', 'for_runners_ynh']
|
||||
line_length=119
|
||||
lines_after_imports=2
|
||||
|
||||
|
@ -114,6 +140,10 @@ branch = true
|
|||
parallel = true
|
||||
concurrency = ["multiprocessing"]
|
||||
source = ['.']
|
||||
# TODO: pytest -> Django unitests:
|
||||
#command_line = '-m unittest --verbose --locals --buffer'
|
||||
command_line = '-m pytest'
|
||||
disable_warnings = ["couldnt-parse"]
|
||||
|
||||
[tool.coverage.report]
|
||||
omit = ['.*', '*/tests/*']
|
||||
|
@ -132,18 +162,32 @@ exclude_lines = [
|
|||
legacy_tox_ini = """
|
||||
[tox]
|
||||
isolated_build = True
|
||||
envlist = py{311,310,39}
|
||||
envlist = py{312,311,310,39}
|
||||
skip_missing_interpreters = True
|
||||
|
||||
[testenv]
|
||||
passenv = *
|
||||
skip_install = true
|
||||
allowlist_externals = make
|
||||
commands_pre =
|
||||
pip install -U pip-tools
|
||||
pip-sync requirements.dev.txt
|
||||
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
|
||||
initial_revision = "2281f4b"
|
||||
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"
|
||||
applied_migrations = [
|
||||
"183124a", # 2023-04-04T12:26:15+02:00
|
||||
"3383cb0", # 2023-11-09T20:14:05+01:00
|
||||
]
|
||||
|
||||
[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
|
||||
#=================================================
|
||||
|
||||
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:
|
||||
ynh_current_host=$(cat /etc/yunohost/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="0"
|
||||
debug_enabled="NO" # "YES" or "NO" string
|
||||
|
||||
# 'log_level' -> '__LOG_LEVEL__' -> settings.LOG_LEVEL
|
||||
log_level="WARNING"
|
||||
|
@ -35,26 +28,62 @@ default_from_email="${app}@${domain}"
|
|||
# SET CONSTANTS
|
||||
#=================================================
|
||||
|
||||
public_path=/var/www/$app
|
||||
final_path=/opt/yunohost/$app
|
||||
# e.g.: point pip cache to: /home/yunohost.app/$app/.cache/
|
||||
XDG_CACHE_HOME="$data_dir/.cache/"
|
||||
|
||||
log_path=/var/log/$app
|
||||
log_file="${log_path}/${app}.log"
|
||||
|
||||
#=================================================
|
||||
# COMMON VARIABLES
|
||||
# HELPERS
|
||||
#=================================================
|
||||
|
||||
# Needed base dependencies:
|
||||
pkg_dependencies="build-essential python3-dev python3-pip python3-venv git"
|
||||
myynh_setup_python_venv() {
|
||||
# Always recreate everything fresh with current python version
|
||||
ynh_secure_remove "$data_dir/venv"
|
||||
|
||||
# For pillow:
|
||||
pkg_dependencies="${pkg_dependencies} libjpeg-dev"
|
||||
# Skip pip because of: https://github.com/YunoHost/issues/issues/1960
|
||||
python3 -m venv --without-pip "$data_dir/venv"
|
||||
|
||||
# Postgres and Python's "psycopg2":
|
||||
pkg_dependencies="${pkg_dependencies} libpq-dev postgresql postgresql-contrib"
|
||||
chown -c -R "$app:" "$data_dir"
|
||||
|
||||
# Needed for lxml: https://lxml.de/installation.html#requirements
|
||||
pkg_dependencies="${pkg_dependencies} libxml2-dev libxslt-dev"
|
||||
# run source in a 'sub shell'
|
||||
(
|
||||
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
|
||||
|
|
|
@ -9,21 +9,6 @@
|
|||
source ../settings/scripts/_common.sh
|
||||
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
|
||||
#=================================================
|
||||
|
@ -33,8 +18,11 @@ ynh_print_info --message="Declaring files to be backed up..."
|
|||
# BACKUP THE APP MAIN DIR
|
||||
#=================================================
|
||||
|
||||
ynh_backup --src_path="$final_path"
|
||||
ynh_backup --src_path="$public_path"
|
||||
# /var/www/$app/
|
||||
ynh_backup --src_path="$install_dir"
|
||||
|
||||
# /home/yunohost.app/$app/
|
||||
ynh_backup --src_path="$data_dir"
|
||||
|
||||
#=================================================
|
||||
# BACKUP THE NGINX CONFIGURATION
|
||||
|
|
|
@ -6,81 +6,9 @@
|
|||
# IMPORT GENERIC HELPERS
|
||||
#=================================================
|
||||
|
||||
YNH_APP_ARG_DOMAIN=$YNH_APP_NEW_DOMAIN
|
||||
YNH_APP_ARG_PATH=$YNH_APP_NEW_PATH
|
||||
|
||||
source _common.sh
|
||||
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
|
||||
#=================================================
|
||||
|
@ -88,66 +16,31 @@ fi
|
|||
#=================================================
|
||||
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
|
||||
#=================================================
|
||||
ynh_script_progression --message="Updating nginx web server configuration..."
|
||||
|
||||
nginx_conf_path=/etc/nginx/conf.d/$old_domain.d/$app.conf
|
||||
|
||||
# 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
|
||||
ynh_change_url_nginx_config
|
||||
|
||||
#=================================================
|
||||
# SPECIFIC MODIFICATIONS
|
||||
# UPDATE DJANGO SETTINGS
|
||||
#=================================================
|
||||
# MODIFY SETTINGS
|
||||
#=================================================
|
||||
ynh_script_progression --message="Modify $app config file..."
|
||||
ynh_script_progression --message="Update $app settings file..." --weight=1
|
||||
|
||||
domain=$YNH_APP_NEW_DOMAIN
|
||||
path_url=$YNH_APP_NEW_PATH
|
||||
path=$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
|
||||
#=================================================
|
||||
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
|
||||
ynh_systemd_action --service_name=$app --action="start" --log_path="$log_file"
|
||||
|
||||
#=================================================
|
||||
# END OF SCRIPT
|
||||
|
|
315
scripts/install
315
scripts/install
|
@ -7,88 +7,137 @@
|
|||
source _common.sh
|
||||
source /usr/share/yunohost/helpers
|
||||
|
||||
#=================================================
|
||||
# MANAGE SCRIPT FAILURE
|
||||
#=================================================
|
||||
# Install parameters are automatically saved as settings
|
||||
#
|
||||
# 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
|
||||
#=================================================
|
||||
ynh_script_progression --message="Validating installation parameters..."
|
||||
|
||||
# Path for e.g. "static" files, served by nginx:
|
||||
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}"
|
||||
mkdir -p "$install_dir/media" "$install_dir/static"
|
||||
|
||||
#=================================================
|
||||
# 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"
|
||||
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"
|
||||
myynh_setup_log_file
|
||||
|
||||
ynh_app_setting_set --app="$app" --key=domain --value="$domain"
|
||||
ynh_app_setting_set --app="$app" --key=path --value="$path_url"
|
||||
|
||||
# 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"
|
||||
# Use logrotate to manage application logfile(s)
|
||||
ynh_use_logrotate --logfile="$log_file" --specific_user=$app
|
||||
|
||||
#=================================================
|
||||
# STANDARD MODIFICATIONS
|
||||
# PYTHON VIRTUALENV
|
||||
#=================================================
|
||||
# INSTALL DEPENDENCIES
|
||||
#=================================================
|
||||
ynh_script_progression --message="Installing $app dependencies..." --weight=20
|
||||
|
||||
ynh_exec_warn_less ynh_install_app_dependencies "$pkg_dependencies"
|
||||
ynh_script_progression --message="Create and setup Python virtualenv..." --weight=45
|
||||
cp ../conf/requirements.txt "$data_dir/requirements.txt"
|
||||
myynh_setup_python_venv
|
||||
|
||||
#=================================================
|
||||
# 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")
|
||||
db_user=$db_name
|
||||
ynh_app_setting_set --app="$app" --key=db_name --value="$db_name"
|
||||
cd "$data_dir" || exit
|
||||
|
||||
ynh_psql_test_if_first_run
|
||||
# Just for debugging:
|
||||
./manage.py diffsettings
|
||||
|
||||
# Initialize database and store postgres password for upgrade
|
||||
ynh_psql_setup_db --db_user="$db_user" --db_name="$db_name"
|
||||
./manage.py migrate --no-input
|
||||
./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
|
||||
|
@ -100,150 +149,6 @@ ynh_script_progression --message="Configuring nginx web server..."
|
|||
# https://github.com/YunoHost/yunohost/blob/dev/helpers/nginx
|
||||
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
|
||||
#=================================================
|
||||
|
|
|
@ -9,17 +9,6 @@
|
|||
source _common.sh
|
||||
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
|
||||
#=================================================
|
||||
|
@ -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`
|
||||
if yunohost service status "$app" >/dev/null 2>&1
|
||||
if yunohost service status $app >/dev/null 2>&1
|
||||
then
|
||||
ynh_script_progression --message="Removing $app service integration..."
|
||||
yunohost service remove "$app"
|
||||
yunohost service remove $app
|
||||
fi
|
||||
|
||||
#=================================================
|
||||
|
@ -38,15 +27,7 @@ fi
|
|||
#=================================================
|
||||
ynh_script_progression --message="Stopping and removing systemd service '$app'..." --weight=5
|
||||
|
||||
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
|
||||
ynh_remove_systemd_config --service=$app
|
||||
|
||||
##=================================================
|
||||
## REMOVE REDIS DB
|
||||
|
@ -54,22 +35,16 @@ ynh_psql_remove_db --db_user=$db_user --db_name=$db_name
|
|||
|
||||
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
|
||||
#=================================================
|
||||
ynh_script_progression --message="Removing app main directory..."
|
||||
|
||||
# Remove the app directory securely
|
||||
ynh_secure_remove --file="$public_path"
|
||||
ynh_secure_remove --file="$final_path"
|
||||
# /var/www/$app/
|
||||
ynh_secure_remove --file="$install_dir"
|
||||
|
||||
# /home/yunohost.app/$app/
|
||||
ynh_secure_remove --file="$data_dir"
|
||||
|
||||
#=================================================
|
||||
# REMOVE NGINX CONFIGURATION
|
||||
|
@ -87,16 +62,6 @@ ynh_script_progression --message="Removing logrotate configuration..."
|
|||
# Remove the app-specific logrotate config
|
||||
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
|
||||
#=================================================
|
||||
|
|
106
scripts/restore
106
scripts/restore
|
@ -9,39 +9,12 @@
|
|||
source ../settings/scripts/_common.sh
|
||||
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
|
||||
#=================================================
|
||||
# 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"
|
||||
|
||||
|
@ -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_restore_file --origin_path="$final_path"
|
||||
ynh_restore_file --origin_path="$public_path"
|
||||
ynh_restore_file --origin_path="$install_dir"
|
||||
ynh_restore_file --origin_path="$data_dir"
|
||||
|
||||
#=================================================
|
||||
# RECREATE THE DEDICATED USER
|
||||
#=================================================
|
||||
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"
|
||||
ynh_script_progression --message="Set file permissions..."
|
||||
myynh_fix_file_permissions
|
||||
|
||||
#=================================================
|
||||
# PYTHON VIRTUALENV
|
||||
# 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
|
||||
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"
|
||||
)
|
||||
myynh_setup_python_venv
|
||||
|
||||
#=================================================
|
||||
# RESTORE THE PostgreSQL DATABASE
|
||||
#=================================================
|
||||
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
|
||||
|
||||
#=================================================
|
||||
# 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"
|
||||
systemctl enable $app.service --quiet
|
||||
|
@ -127,15 +57,14 @@ systemctl enable $app.service --quiet
|
|||
#=================================================
|
||||
ynh_script_progression --message="Integrating service in YunoHost..."
|
||||
|
||||
yunohost service add $app --log="${log_file}"
|
||||
yunohost service add $app
|
||||
|
||||
#=================================================
|
||||
# RESTORE THE LOGROTATE CONFIGURATION
|
||||
#=================================================
|
||||
ynh_script_progression --message="Setup logging..."
|
||||
|
||||
mkdir -p "$log_path"
|
||||
touch "${log_file}"
|
||||
chown -R "$app:" "$log_path"
|
||||
myynh_setup_log_file
|
||||
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
|
||||
#=================================================
|
||||
|
||||
# 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"
|
||||
ynh_script_progression --message="Set file permissions..."
|
||||
myynh_fix_file_permissions
|
||||
|
||||
#=================================================
|
||||
# GENERIC FINALIZATION
|
||||
|
@ -160,7 +82,7 @@ chmod o-rwx "$final_path"
|
|||
#=================================================
|
||||
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
|
||||
|
|
150
scripts/upgrade
150
scripts/upgrade
|
@ -7,68 +7,29 @@
|
|||
source _common.sh
|
||||
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:
|
||||
|
||||
debug_enabled=$(ynh_app_setting_get --app="$app" --key=debug_enabled)
|
||||
if [ -z "$debug_enabled" ]; then
|
||||
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
|
||||
|
||||
log_level=$(ynh_app_setting_get --app="$app" --key=log_level)
|
||||
if [ -z "$log_level" ]; then
|
||||
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
|
||||
|
||||
admin_email=$(ynh_app_setting_get --app="$app" --key=admin_email)
|
||||
if [ -z "$admin_email" ]; then
|
||||
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
|
||||
|
||||
default_from_email=$(ynh_app_setting_get --app="$app" --key=default_from_email)
|
||||
if [ -z "$default_from_email" ]; then
|
||||
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
|
||||
|
||||
#=================================================
|
||||
# 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
|
||||
#=================================================
|
||||
|
@ -76,91 +37,44 @@ ynh_abort_if_errors
|
|||
#=================================================
|
||||
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
|
||||
#=================================================
|
||||
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
|
||||
#=================================================
|
||||
ynh_script_progression --message="Recreate 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"
|
||||
)
|
||||
ynh_script_progression --message="Create and setup Python virtualenv..." --weight=45
|
||||
cp ../conf/requirements.txt "$data_dir/requirements.txt"
|
||||
myynh_setup_python_venv
|
||||
|
||||
#=================================================
|
||||
# copy config 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"
|
||||
chmod +x "$final_path/manage.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="$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"
|
||||
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"
|
||||
|
||||
#=================================================
|
||||
# MIGRATE PYINVENTORY
|
||||
#=================================================
|
||||
ynh_script_progression --message="migrate/collectstatic/createadmin..." --weight=10
|
||||
|
||||
cd "$final_path" || exit
|
||||
cd "$data_dir" || exit
|
||||
|
||||
# Just for debugging:
|
||||
./manage.py diffsettings
|
||||
|
@ -182,43 +96,23 @@ cd "$final_path" || exit
|
|||
ynh_script_progression --message="Upgrading logrotate configuration..."
|
||||
|
||||
# Use logrotate to manage app-specific logfile(s)
|
||||
ynh_use_logrotate --non-append
|
||||
|
||||
#=================================================
|
||||
# INTEGRATE SERVICE IN YUNOHOST
|
||||
#=================================================
|
||||
ynh_script_progression --message="Integrating service in YunoHost..."
|
||||
|
||||
yunohost service add $app --log="${log_file}"
|
||||
ynh_use_logrotate --logfile="$log_file" --specific_user=$app --non-append
|
||||
|
||||
#=================================================
|
||||
# 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"
|
||||
ynh_script_progression --message="Set file permissions..."
|
||||
myynh_fix_file_permissions
|
||||
|
||||
#=================================================
|
||||
# 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
|
||||
yunohost service add $app
|
||||
ynh_systemd_action --service_name=$app --action="start" --log_path="$log_file"
|
||||
|
||||
#=================================================
|
||||
# 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
|
||||
|
||||
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
|
||||
|
@ -21,23 +21,23 @@ os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
|
|||
|
||||
def pytest_configure():
|
||||
print('Compile YunoHost files...')
|
||||
final_path = create_local_test(
|
||||
result: CreateResults = create_local_test(
|
||||
django_settings_path=BASE_PATH / 'conf' / 'settings.py',
|
||||
destination=BASE_PATH / 'local_test',
|
||||
runserver=False,
|
||||
extra_replacements={
|
||||
'__DEBUG_ENABLED__': '0',
|
||||
'__DEBUG_ENABLED__': 'NO', # "YES" or "NO" string
|
||||
'__LOG_LEVEL__': 'INFO',
|
||||
'__ADMIN_EMAIL__': 'foo-bar@test.tld',
|
||||
'__DEFAULT_FROM_EMAIL__': 'django_app@test.tld',
|
||||
},
|
||||
)
|
||||
print('Local test files created here:')
|
||||
print(f'"{final_path}"')
|
||||
print('Local test files created:')
|
||||
print(result)
|
||||
|
||||
os.chdir(final_path)
|
||||
final_home_str = str(final_path)
|
||||
if final_home_str not in sys.path:
|
||||
sys.path.insert(0, final_home_str)
|
||||
os.chdir(result.data_dir_path)
|
||||
data_dir = str(result.data_dir_path)
|
||||
if data_dir not in sys.path:
|
||||
sys.path.insert(0, data_dir)
|
||||
|
||||
django.setup()
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
from unittest.mock import patch
|
||||
|
||||
import for_runners
|
||||
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.contrib.auth.models import User
|
||||
from django.template.defaulttags import CsrfTokenNode
|
||||
from django.test import override_settings
|
||||
from django.test.testcases import TestCase
|
||||
from django.urls.base import reverse
|
||||
from django_yunohost_integration.test_utils import generate_basic_auth
|
||||
|
||||
import for_runners
|
||||
|
||||
|
||||
@override_settings(DEBUG=False)
|
||||
class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
|
||||
|
@ -24,15 +26,15 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
|
|||
|
||||
assert settings.PATH_URL == 'app_path'
|
||||
|
||||
assert str(settings.FINALPATH).endswith('/local_test/opt_yunohost')
|
||||
assert str(settings.PUBLIC_PATH).endswith('/local_test/var_www')
|
||||
assert str(settings.LOG_FILE).endswith('/local_test/var_log_django-for-runners.log')
|
||||
assert str(settings.DATA_DIR_PATH).endswith('/local_test/opt_yunohost')
|
||||
assert str(settings.INSTALL_DIR_PATH).endswith('/local_test/var_www')
|
||||
assert str(settings.LOG_FILE_PATH).endswith('/local_test/var_log_django-for-runners.log')
|
||||
|
||||
assert settings.ROOT_URLCONF == 'urls'
|
||||
|
||||
def test_config_panel_settings(self):
|
||||
# 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.ADMIN_EMAIL == 'foo-bar@test.tld'
|
||||
assert settings.DEFAULT_FROM_EMAIL == 'django_app@test.tld'
|
||||
|
@ -71,6 +73,7 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
|
|||
|
||||
self.client.cookies['SSOwAuthUser'] = 'test'
|
||||
|
||||
with patch.object(CsrfTokenNode, 'render', return_value='MockedCsrfTokenNode'):
|
||||
response = self.client.get(
|
||||
path='/app_path/',
|
||||
HTTP_REMOTE_USER='test',
|
||||
|
@ -93,6 +96,7 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
|
|||
'<strong>test</strong>',
|
||||
),
|
||||
)
|
||||
assert_html_response_snapshot(response, query_selector='#container', validate=False)
|
||||
|
||||
def test_wrong_auth_user(self):
|
||||
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 shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
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 django_tools.unittest_utils.project_setup import check_editor_config
|
||||
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
|
||||
|
@ -31,6 +29,18 @@ def assert_file_contains_string(file_path, string):
|
|||
|
||||
|
||||
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:
|
||||
# Github has a rate-limiting... So don't fetch the API if we run as GitHub action
|
||||
assert_project_version(
|
||||
|
@ -38,62 +48,6 @@ def test_version():
|
|||
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():
|
||||
"""
|
||||
|
@ -118,40 +72,36 @@ def test_check_editor_config():
|
|||
check_editor_config(package_root=PACKAGE_ROOT)
|
||||
|
||||
|
||||
def _call_make(*args):
|
||||
make_bin = shutil.which('make')
|
||||
assert make_bin
|
||||
return subprocess.check_output(
|
||||
(make_bin,) + args,
|
||||
text=True,
|
||||
env=dict(PATH=os.environ['PATH']),
|
||||
stderr=subprocess.STDOUT,
|
||||
cwd=str(PACKAGE_ROOT),
|
||||
)
|
||||
class ManifestTestCase(TestCase):
|
||||
def test_manifest_toml(self):
|
||||
manifest_path = PACKAGE_ROOT / 'manifest.toml'
|
||||
assert_is_file(manifest_path)
|
||||
|
||||
cfg = tomllib.loads(manifest_path.read_text(encoding='UTF-8'))
|
||||
|
||||
def test_check_code_style():
|
||||
# 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(cfg['packaging_format'], 2)
|
||||
self.assertEqual(
|
||||
set(cfg['main']['config'].keys()),
|
||||
{'name', 'default_from_email', 'admin_email', 'debug_enabled', 'log_level'},
|
||||
set(cfg['install'].keys()),
|
||||
{
|
||||
'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