diff --git a/.dockerignore b/.dockerignore index 0475918c..1661d7f8 100644 --- a/.dockerignore +++ b/.dockerignore @@ -73,7 +73,6 @@ storefront/.nuxt storefront/Dockerfile docker-compose.yml backups/ -services_data/ static/ media/ !engine/core/static diff --git a/.gitignore b/.gitignore index 6b0e7bd1..2f13695e 100644 --- a/.gitignore +++ b/.gitignore @@ -117,14 +117,6 @@ media/ # Webassets .webassets-cache/ -# ────────────────────────────────────────────────────────────────────────── -# Docker & service data -# ────────────────────────────────────────────────────────────────────────── -# Local volume mounts -services_data/ -services_data/postgres/ -services_data/redis/ - # ────────────────────────────────────────────────────────────────────────── # Node dependencies # ────────────────────────────────────────────────────────────────────────── diff --git a/docker-compose.yml b/docker-compose.yml index d5d6d8f7..4d34efe7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -31,7 +31,7 @@ services: image: postgis/postgis:17-3.5 restart: always volumes: - - ./services_data/postgres:/var/lib/postgresql/data/ + - postgres-data:/var/lib/postgresql/data/ ports: - "5432:5432" env_file: @@ -63,7 +63,7 @@ services: restart: always command: redis-server --save "" --appendonly no --slave-read-only no --requirepass "$REDIS_PASSWORD" volumes: - - ./services_data/redis:/data + - redis-data:/data env_file: - .env logging: *default-logging @@ -242,5 +242,7 @@ services: volumes: + postgres-data: + redis-data: es-data: prometheus-data: diff --git a/engine/blog/tests/__init__.py b/engine/blog/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/engine/blog/tests/test_drf.py b/engine/blog/tests/test_drf.py index e69de29b..3fd85c2e 100644 --- a/engine/blog/tests/test_drf.py +++ b/engine/blog/tests/test_drf.py @@ -0,0 +1,8 @@ +from django.test import TestCase +from rest_framework.test import APIClient + + +class DRFBlogViewsTests(TestCase): + def setUp(self): + super().setUp() + self.client = APIClient() diff --git a/engine/blog/tests/test_graphene.py b/engine/blog/tests/test_graphene.py index e69de29b..d5a7ae72 100644 --- a/engine/blog/tests/test_graphene.py +++ b/engine/blog/tests/test_graphene.py @@ -0,0 +1,15 @@ +from typing import Any + +from django.test import TestCase +from django.urls import reverse + + +class GraphQLBlogTests(TestCase): + def graphql(self, query: str, variables: dict | None = None): + url = reverse("graphql-platform") + payload: dict[str, Any] = {"query": query} + if variables: + payload["variables"] = variables + response = self.client.post(url, data=payload, content_type="application/json") + self.assertEqual(response.status_code, 200, response.json()) + return response.json() diff --git a/engine/core/tasks.py b/engine/core/tasks.py index 5fa3a9f1..1dc435a9 100644 --- a/engine/core/tasks.py +++ b/engine/core/tasks.py @@ -12,6 +12,7 @@ from celery.app import shared_task from constance import config from django.conf import settings from django.core.cache import cache +from django.core.management import call_command from engine.core.models import Product, Promotion from engine.core.utils.caching import set_default_cache @@ -21,6 +22,12 @@ from engine.core.vendors import AbstractVendor, VendorInactiveError, delete_stal logger = logging.getLogger(__name__) +@shared_task(queue="default") +def backup_task(): + call_command("dbbackup", clean=True) + call_command("mediabackup", clean=True) + + @shared_task(queue="stock_updater") def update_products_task() -> tuple[bool, str]: """ diff --git a/engine/core/tests/__init__.py b/engine/core/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/engine/core/tests/test_drf.py b/engine/core/tests/test_drf.py index e69de29b..1580a9dc 100644 --- a/engine/core/tests/test_drf.py +++ b/engine/core/tests/test_drf.py @@ -0,0 +1,8 @@ +from django.test import TestCase +from rest_framework.test import APIClient + + +class DRFCoreViewsTests(TestCase): + def setUp(self): + super().setUp() + self.client = APIClient() diff --git a/engine/core/tests/test_graphene.py b/engine/core/tests/test_graphene.py index e69de29b..f95d4c41 100644 --- a/engine/core/tests/test_graphene.py +++ b/engine/core/tests/test_graphene.py @@ -0,0 +1,15 @@ +from typing import Any + +from django.test import TestCase +from django.urls import reverse + + +class GraphQLCoreTests(TestCase): + def graphql(self, query: str, variables: dict | None = None): + url = reverse("graphql-platform") + payload: dict[str, Any] = {"query": query} + if variables: + payload["variables"] = variables + response = self.client.post(url, data=payload, content_type="application/json") + self.assertEqual(response.status_code, 200, response.json()) + return response.json() diff --git a/engine/payments/tests/__init__.py b/engine/payments/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/engine/payments/tests/test_drf.py b/engine/payments/tests/test_drf.py index e69de29b..cddebe43 100644 --- a/engine/payments/tests/test_drf.py +++ b/engine/payments/tests/test_drf.py @@ -0,0 +1,8 @@ +from django.test import TestCase +from rest_framework.test import APIClient + + +class DRFPaymentsViewsTests(TestCase): + def setUp(self): + super().setUp() + self.client = APIClient() diff --git a/engine/payments/tests/test_graphene.py b/engine/payments/tests/test_graphene.py index e69de29b..df90bc42 100644 --- a/engine/payments/tests/test_graphene.py +++ b/engine/payments/tests/test_graphene.py @@ -0,0 +1,15 @@ +from typing import Any + +from django.test import TestCase +from django.urls import reverse + + +class GraphQLPaymentsTests(TestCase): + def graphql(self, query: str, variables: dict | None = None): + url = reverse("graphql-platform") + payload: dict[str, Any] = {"query": query} + if variables: + payload["variables"] = variables + response = self.client.post(url, data=payload, content_type="application/json") + self.assertEqual(response.status_code, 200, response.json()) + return response.json() diff --git a/engine/vibes_auth/tests/test_drf.py b/engine/vibes_auth/tests/test_drf.py index 4acf4913..abce8d55 100644 --- a/engine/vibes_auth/tests/test_drf.py +++ b/engine/vibes_auth/tests/test_drf.py @@ -13,7 +13,7 @@ from rest_framework_simplejwt.tokens import RefreshToken from engine.vibes_auth.models import User -class DRFViewsTests(TestCase): +class DRFAuthViewsTests(TestCase): def setUp(self): super().setUp() self.client = APIClient() diff --git a/engine/vibes_auth/tests/test_messaging.py b/engine/vibes_auth/tests/test_messaging.py index ad38b12b..3b450fce 100644 --- a/engine/vibes_auth/tests/test_messaging.py +++ b/engine/vibes_auth/tests/test_messaging.py @@ -8,7 +8,7 @@ from engine.vibes_auth.models import User from engine.vibes_auth.messaging import auth as auth_module -class MessagingAuthTests(TestCase): +class MessagingTests(TestCase): def test_extract_jwt_from_subprotocols_cases(self): fn = auth_module._extract_jwt_from_subprotocols self.assertIsNone(fn(None)) diff --git a/engine/vibes_auth/views.py b/engine/vibes_auth/views.py index 2d888076..5a81aa2d 100644 --- a/engine/vibes_auth/views.py +++ b/engine/vibes_auth/views.py @@ -1,7 +1,6 @@ import logging from typing import Any, Type -from django.conf import settings from django.utils.decorators import method_decorator from django.utils.translation import gettext_lazy as _ from django_ratelimit.decorators import ratelimit diff --git a/evibes/middleware.py b/evibes/middleware.py index b23022c2..fad393cc 100644 --- a/evibes/middleware.py +++ b/evibes/middleware.py @@ -109,7 +109,6 @@ class GrapheneLoggingErrorsDebugMiddleware: class RateLimitMiddleware: - def __init__(self, get_response): self.get_response = get_response diff --git a/evibes/settings/celery.py b/evibes/settings/celery.py index 433383c0..9ff31529 100644 --- a/evibes/settings/celery.py +++ b/evibes/settings/celery.py @@ -25,6 +25,11 @@ CELERY_RESULT_BACKEND = CELERY_BROKER_URL CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers.DatabaseScheduler" CELERY_BEAT_SCHEDULE = { + "backup_task": { + "task": "engine.core.tasks.backup_task", + "schedule": timedelta(days=7), + "options": {"queue": "default"}, + }, "update_products_task": { "task": "engine.core.tasks.update_products_task", "schedule": timedelta(minutes=60), diff --git a/evibes/settings/dbbackup.py b/evibes/settings/dbbackup.py index a8225a2f..3f032818 100644 --- a/evibes/settings/dbbackup.py +++ b/evibes/settings/dbbackup.py @@ -5,3 +5,6 @@ DBBACKUP_CONNECTORS = { "RESTORE_SUFFIX": "--set ON_ERROR_STOP=off", } } + +DBBACKUP_CLEANUP_KEEP = 2 +DBBACKUP_CLEANUP_KEEP_MEDIA = 2 diff --git a/evibes/settings/jazzmin.py b/evibes/settings/jazzmin.py index 42e4bf8f..1556ce3c 100644 --- a/evibes/settings/jazzmin.py +++ b/evibes/settings/jazzmin.py @@ -29,7 +29,11 @@ JAZZMIN_SETTINGS = { "url": f"https://api.{BASE_DOMAIN}/docs/swagger", # type: ignore [index] "new_window": True, }, - {"name": _("Taskboard"), "url": "https://plane.wiseless.xyz/spaces/issues/dd33cb0ab9b04ef08a10f7eefae6d90c/?board=kanban", "new_window": True}, + { + "name": _("Taskboard"), + "url": "https://plane.wiseless.xyz/spaces/issues/dd33cb0ab9b04ef08a10f7eefae6d90c/?board=kanban", + "new_window": True, + }, {"name": "GitLab", "url": "https://gitlab.com/wiseless/evibes", "new_window": True}, {"name": _("Support"), "url": "https://t.me/fureunoir", "new_window": True}, ], diff --git a/evibes/utils/misc.py b/evibes/utils/misc.py index 83f73ea0..2a1351db 100644 --- a/evibes/utils/misc.py +++ b/evibes/utils/misc.py @@ -2,8 +2,6 @@ from enum import Enum from importlib import import_module from typing import Any -from django.core.exceptions import PermissionDenied - def create_object(module_name: str, class_name: str, *args: list[Any], **kwargs: dict[Any, Any]) -> Any: module = import_module(module_name) @@ -27,7 +25,6 @@ class LogLevel(Enum): class RatelimitedError(Exception): - default_detail = "Rate limit exceeded. Please try again later." default_code = "rate_limited" status_code = 429 diff --git a/scripts/Docker/app-entrypoint.sh b/scripts/Docker/app-entrypoint.sh index da7f11f5..f4bd28fe 100644 --- a/scripts/Docker/app-entrypoint.sh +++ b/scripts/Docker/app-entrypoint.sh @@ -1,7 +1,7 @@ #!/usr/bin/bash set -e -uv run python manage.py await_services +uv run manage.py await_services if [ "${DEBUG:-0}" = "1" ]; then uv run uvicorn --host 0.0.0.0 --port 8000 --reload --log-level debug --ws-ping-interval 20 --ws-ping-timeout 20 evibes.asgi:application diff --git a/scripts/Docker/beat-entrypoint.sh b/scripts/Docker/beat-entrypoint.sh index e1a029f6..5dbfd4e7 100644 --- a/scripts/Docker/beat-entrypoint.sh +++ b/scripts/Docker/beat-entrypoint.sh @@ -1,6 +1,6 @@ #!/usr/bin/bash set -e -uv run python manage.py await_services +uv run manage.py await_services uv run celery -A evibes beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler diff --git a/scripts/Docker/stock-updater-entrypoint.sh b/scripts/Docker/stock-updater-entrypoint.sh index a66707d9..cc874d0e 100644 --- a/scripts/Docker/stock-updater-entrypoint.sh +++ b/scripts/Docker/stock-updater-entrypoint.sh @@ -1,6 +1,6 @@ #!/usr/bin/bash set -e -uv run python manage.py await_services +uv run manage.py await_services uv run celery -A evibes worker --pool=prefork --concurrency=1 --queues=stock_updater --loglevel=info --max-tasks-per-child=1 diff --git a/scripts/Docker/worker-entrypoint.sh b/scripts/Docker/worker-entrypoint.sh index 97081280..7c69a80c 100644 --- a/scripts/Docker/worker-entrypoint.sh +++ b/scripts/Docker/worker-entrypoint.sh @@ -1,6 +1,6 @@ #!/usr/bin/bash set -e -uv run python manage.py await_services +uv run manage.py await_services uv run celery -A evibes worker --pool=prefork --concurrency=8 --loglevel=info -E --queues=default --prefetch-multiplier=1 --max-tasks-per-child=100 --max-memory-per-child=512000 --soft-time-limit=3600 --time-limit=7200 & /opt/evibes-python/bin/celery-prometheus-exporter diff --git a/scripts/Unix/backup.sh b/scripts/Unix/backup.sh index 39d57b17..0f7c497c 100644 --- a/scripts/Unix/backup.sh +++ b/scripts/Unix/backup.sh @@ -4,9 +4,9 @@ set -euo pipefail source ./scripts/Unix/starter.sh echo "Starting database backup process..." -docker compose exec app uv run python manage.py dbbackup +docker compose exec app uv run manage.py dbbackup echo "Database backup created under ./dbbackup" echo "Starting media backup process..." -docker compose exec app uv run python manage.py mediabackup +docker compose exec app uv run manage.py mediabackup echo "Media backup created under ./dbbackup" diff --git a/scripts/Unix/reboot.sh b/scripts/Unix/reboot.sh index 2499628f..83b97565 100755 --- a/scripts/Unix/reboot.sh +++ b/scripts/Unix/reboot.sh @@ -12,11 +12,11 @@ docker compose up -d --build --wait echo "Services are up and healthy!" echo "Completing pre-run tasks..." -docker compose exec app uv run python manage.py migrate --no-input --verbosity 0 -docker compose exec app uv run python manage.py initialize -docker compose exec app uv run python manage.py set_default_caches -docker compose exec app uv run python manage.py search_index --rebuild -f -docker compose exec app uv run python manage.py collectstatic --clear --no-input --verbosity 0 +docker compose exec app uv run manage.py migrate --no-input --verbosity 0 +docker compose exec app uv run manage.py initialize +docker compose exec app uv run manage.py set_default_caches +docker compose exec app uv run manage.py search_index --rebuild -f +docker compose exec app uv run manage.py collectstatic --clear --no-input --verbosity 0 echo "Pre-run tasks completed successfully!" echo "Cleaning up unused Docker data..." diff --git a/scripts/Unix/run.sh b/scripts/Unix/run.sh index ce6d5af4..c6246678 100755 --- a/scripts/Unix/run.sh +++ b/scripts/Unix/run.sh @@ -24,11 +24,11 @@ docker compose up --no-build --detach --wait echo "Services are up and healthy!" echo "Completing pre-run tasks..." -docker compose exec app uv run python manage.py migrate --no-input --verbosity 0 -docker compose exec app uv run python manage.py initialize -docker compose exec app uv run python manage.py set_default_caches -docker compose exec app uv run python manage.py search_index --rebuild -f -docker compose exec app uv run python manage.py collectstatic --clear --no-input --verbosity 0 +docker compose exec app uv run manage.py migrate --no-input --verbosity 0 +docker compose exec app uv run manage.py initialize +docker compose exec app uv run manage.py set_default_caches +docker compose exec app uv run manage.py search_index --rebuild -f +docker compose exec app uv run manage.py collectstatic --clear --no-input --verbosity 0 echo "Pre-run tasks completed successfully!" echo "Cleaning unused Docker data..." diff --git a/scripts/Unix/test.sh b/scripts/Unix/test.sh new file mode 100644 index 00000000..f955dc39 --- /dev/null +++ b/scripts/Unix/test.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -euo pipefail + +source ./scripts/Unix/starter.sh + +report="" + +while [ "$#" -gt 0 ]; do + case "$1" in + --report|-r) + if [ "${2-}" = "" ]; then + echo "Error: --report/-r requires an argument: xml or html" >&2 + exit 1 + fi + report="$2" + shift 2 + ;; + --report=*) + report="${1#*=}" + shift + ;; + -r=*) + report="${1#*=}" + shift + ;; + *) + echo "Unknown argument: $1" >&2 + echo "Usage: $0 [--report|-r xml|html]" >&2 + exit 1 + ;; + esac +done + +case "${report:-}" in + "") + docker compose exec app uv run coverage erase + docker compose exec app uv run coverage run --source='.' --omit='storefront/*,monitoring/*,Dockerfiles/*,*/__init__.py,*/tests/*,*/migrations/*,manage.py,evibes/*' manage.py test + docker compose exec app uv run coverage report -m + ;; + xml) + docker compose exec app uv run coverage xml --omit='storefront/*,monitoring/*,Dockerfiles/*,*/__init__.py,*/tests/*,*/migrations/*,manage.py,evibes/*' + ;; + html) + docker compose exec app uv run coverage html --omit='storefront/*,monitoring/*,Dockerfiles/*,*/__init__.py,*/tests/*,*/migrations/*,manage.py,evibes/*' + ;; + *) + echo "Invalid report type: $report (expected xml or html)" >&2 + exit 1 + ;; +esac diff --git a/scripts/Unix/uninstall.sh b/scripts/Unix/uninstall.sh index e3c97daf..0c68de65 100644 --- a/scripts/Unix/uninstall.sh +++ b/scripts/Unix/uninstall.sh @@ -17,7 +17,7 @@ docker system prune -a -f --volumes echo "Unused Docker data cleaned successfully!" echo "Removing related files..." -rm -rf ./services_data ./media ./static +rm -rf ./media ./static echo "Related files removed successfully!" echo "Bye-bye, hope you return later!" diff --git a/scripts/Windows/backup.ps1 b/scripts/Windows/backup.ps1 index f7254d5f..d98c27c4 100644 --- a/scripts/Windows/backup.ps1 +++ b/scripts/Windows/backup.ps1 @@ -8,14 +8,14 @@ if ($LASTEXITCODE -ne 0) { } Write-Host "Starting database backup process..." -ForegroundColor Magenta -docker compose exec app uv run python manage.py dbbackup +docker compose exec app uv run manage.py dbbackup if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } Write-Host "Database backup created under ./dbbackup" -ForegroundColor Green Write-Host "Starting media backup process..." -ForegroundColor Magenta -docker compose exec app uv run python manage.py mediabackup +docker compose exec app uv run manage.py mediabackup if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } diff --git a/scripts/Windows/compile-messages.ps1 b/scripts/Windows/compile-messages.ps1 index 54bb4f4f..ea0b5516 100644 --- a/scripts/Windows/compile-messages.ps1 +++ b/scripts/Windows/compile-messages.ps1 @@ -13,14 +13,14 @@ if (-not (Test-Path '.env')) } Write-Host "Checking placeholders in PO files..." -ForegroundColor Magenta -docker compose exec app uv run python manage.py check_translated -l ALL -a ALL +docker compose exec app uv run manage.py check_translated -l ALL -a ALL if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } Write-Host "PO files have no placeholder issues!" -ForegroundColor Green Write-Host "Compiling PO files into MO files..." -ForegroundColor Magenta -docker compose exec app uv run python manage.py compilemessages -l ar_AR -l cs_CZ -l da_DK -l de_DE -l en_GB -l en_US -l es_ES -l fa_IR -l fr_FR -l he_IL -l hi_IN -l hr_HR -l id_ID -l it_IT -l ja_JP -l kk_KZ -l ko_KR -l nl_NL -l no_NO -l pl_PL -l pt_BR -l ro_RO -l ru_RU -l sv_SE -l th_TH -l tr_TR -l vi_VN -l zh_Hans +docker compose exec app uv run manage.py compilemessages -l ar_AR -l cs_CZ -l da_DK -l de_DE -l en_GB -l en_US -l es_ES -l fa_IR -l fr_FR -l he_IL -l hi_IN -l hr_HR -l id_ID -l it_IT -l ja_JP -l kk_KZ -l ko_KR -l nl_NL -l no_NO -l pl_PL -l pt_BR -l ro_RO -l ru_RU -l sv_SE -l th_TH -l tr_TR -l vi_VN -l zh_Hans if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } diff --git a/scripts/Windows/make-messages.ps1 b/scripts/Windows/make-messages.ps1 index 3807433f..2d91de00 100644 --- a/scripts/Windows/make-messages.ps1 +++ b/scripts/Windows/make-messages.ps1 @@ -13,28 +13,28 @@ if (-not (Test-Path '.env')) } Write-Host "Remove old fuzzy entries..." -ForegroundColor Magenta -docker compose exec app uv run python manage.py fix_fuzzy +docker compose exec app uv run manage.py fix_fuzzy if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } Write-Host "Old fuzzy entries removed successfully!" -ForegroundColor Green Write-Host "Updating PO files..." -ForegroundColor Magenta -docker compose exec app uv run python manage.py makemessages -l ar_AR -l cs_CZ -l da_DK -l de_DE -l en_GB -l en_US -l es_ES -l fa_IR -l fr_FR -l he_IL -l hi_IN -l hr_HR -l id_ID -l it_IT -l ja_JP -l kk_KZ -l ko_KR -l nl_NL -l no_NO -l pl_PL -l pt_BR -l ro_RO -l ru_RU -l sv_SE -l th_TH -l tr_TR -l vi_VN -l zh_Hans +docker compose exec app uv run manage.py makemessages -l ar_AR -l cs_CZ -l da_DK -l de_DE -l en_GB -l en_US -l es_ES -l fa_IR -l fr_FR -l he_IL -l hi_IN -l hr_HR -l id_ID -l it_IT -l ja_JP -l kk_KZ -l ko_KR -l nl_NL -l no_NO -l pl_PL -l pt_BR -l ro_RO -l ru_RU -l sv_SE -l th_TH -l tr_TR -l vi_VN -l zh_Hans if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } Write-Host "PO files updated successfully!" -ForegroundColor Green Write-Host "Fixing new fuzzy entries..." -ForegroundColor Magenta -docker compose exec app uv run python manage.py fix_fuzzy +docker compose exec app uv run manage.py fix_fuzzy if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } Write-Host "New fuzzy entries fixed successfully!" -ForegroundColor Green Write-Host "Translating with DeepL..." -ForegroundColor Magenta -docker compose exec app uv run python manage.py deepl_translate -l ALL -a ALL +docker compose exec app uv run manage.py deepl_translate -l ALL -a ALL if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } diff --git a/scripts/Windows/reboot.ps1 b/scripts/Windows/reboot.ps1 index 43d37708..e5fcedeb 100644 --- a/scripts/Windows/reboot.ps1 +++ b/scripts/Windows/reboot.ps1 @@ -22,23 +22,23 @@ if ($LASTEXITCODE -ne 0) { Write-Host "Services are up and healthy!" -ForegroundColor Green Write-Host "Completing pre-run tasks..." -ForegroundColor Magenta -docker compose exec app uv run python manage.py migrate --no-input +docker compose exec app uv run manage.py migrate --no-input if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } -docker compose exec app uv run python manage.py initialize +docker compose exec app uv run manage.py initialize if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } -docker compose exec app uv run python manage.py set_default_caches +docker compose exec app uv run manage.py set_default_caches if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } -docker compose exec app uv run python manage.py search_index --rebuild -f +docker compose exec app uv run manage.py search_index --rebuild -f if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } -docker compose exec app uv run python manage.py collectstatic --clear --no-input +docker compose exec app uv run manage.py collectstatic --clear --no-input if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } diff --git a/scripts/Windows/run.ps1 b/scripts/Windows/run.ps1 index 1834df01..adf0914b 100644 --- a/scripts/Windows/run.ps1 +++ b/scripts/Windows/run.ps1 @@ -38,23 +38,23 @@ if ($LASTEXITCODE -ne 0) { Write-Host "Services are up and healthy!" -ForegroundColor Green Write-Host "Completing pre-run tasks..." -ForegroundColor Magenta -docker compose exec app uv run python manage.py migrate --no-input +docker compose exec app uv run manage.py migrate --no-input if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } -docker compose exec app uv run python manage.py initialize +docker compose exec app uv run manage.py initialize if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } -docker compose exec app uv run python manage.py set_default_caches +docker compose exec app uv run manage.py set_default_caches if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } -docker compose exec app uv run python manage.py search_index --rebuild -f +docker compose exec app uv run manage.py search_index --rebuild -f if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } -docker compose exec app uv run python manage.py collectstatic --clear --no-input +docker compose exec app uv run manage.py collectstatic --clear --no-input if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } diff --git a/scripts/Windows/test.ps1 b/scripts/Windows/test.ps1 new file mode 100644 index 00000000..4836104b --- /dev/null +++ b/scripts/Windows/test.ps1 @@ -0,0 +1,38 @@ +param( + [Alias('r')] + [string]$Report = '' +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +& .\scripts\Windows\starter.ps1 +if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE +} + +if (-not $PSBoundParameters.ContainsKey('Report') -or [string]::IsNullOrWhiteSpace($Report)) { + docker compose exec app uv run coverage erase + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + + docker compose exec app uv run coverage run --source='.' --omit='storefront/*,monitoring/*,Dockerfiles/*,*/__init__.py,*/tests/*,*/migrations/*,manage.py,evibes/*' manage.py test + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + + docker compose exec app uv run coverage report -m + exit $LASTEXITCODE +} + +switch ($Report.ToLowerInvariant()) { + 'xml' { + docker compose exec app uv run coverage xml --omit='storefront/*,monitoring/*,Dockerfiles/*,*/__init__.py,*/tests/*,*/migrations/*,manage.py,evibes/*' + exit $LASTEXITCODE + } + 'html' { + docker compose exec app uv run coverage html --omit='storefront/*,monitoring/*,Dockerfiles/*,*/__init__.py,*/tests/*,*/migrations/*,manage.py,evibes/*' + exit $LASTEXITCODE + } + default { + Write-Error "Invalid -Report/-r value '$Report'. Expected 'xml' or 'html'." + exit 1 + } +} diff --git a/scripts/Windows/uninstall.ps1 b/scripts/Windows/uninstall.ps1 index 2ef36b9f..b7491eb1 100644 --- a/scripts/Windows/uninstall.ps1 +++ b/scripts/Windows/uninstall.ps1 @@ -32,7 +32,6 @@ if ($LASTEXITCODE -ne 0) { Write-Host "Unused Docker data cleaned successfully!" -ForegroundColor Green Write-Host "Removing related files..." -ForegroundColor Magenta -Remove-Item -Recurse -Force -ErrorAction SilentlyContinue ./services_data Remove-Item -Recurse -Force -ErrorAction SilentlyContinue ./media Remove-Item -Recurse -Force -ErrorAction SilentlyContinue ./static Write-Host "Related files removed successfully!" -ForegroundColor Green