diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 5668144..61bb013 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -9,7 +9,7 @@ services: - ..:/workspace:cached working_dir: /workspace/src env_file: - - ../.env + - ../.env_files/.env command: sleep infinity depends_on: @@ -22,7 +22,7 @@ services: - ..:/workspace:cached working_dir: /workspace/src env_file: - - ../.env + - ../.env_files/.env command: celery -A backend worker --loglevel=info depends_on: @@ -37,7 +37,7 @@ services: - ..:/workspace:cached working_dir: /workspace/src env_file: - - ../.env + - ../.env_files/.env command: celery -A backend beat --loglevel=info --scheduler django_celery_beat.schedulers:DatabaseScheduler depends_on: - redis @@ -57,7 +57,7 @@ services: ports: - "5432:5432" env_file: - - ../.env + - ../.env_files/.env volumes: postgres-data: diff --git a/.env_files/.env.ci b/.env_files/.env.ci new file mode 100644 index 0000000..809588b --- /dev/null +++ b/.env_files/.env.ci @@ -0,0 +1,18 @@ +# Database +DATABASE_URI=postgresql://postgres:postgres@localhost:5432/web_test +DATABASE_URI_TEST=postgresql://postgres:postgres@localhost:5432/web_test + +# Django +SECRET_KEY=ci-secret-key +DEBUG=False +ALLOWED_HOSTS=localhost,127.0.0.1 +CORS_ALLOWED_ORIGINS=http://localhost:3000,http://127.0.0.1:3000 + +# Celery / Redis +CELERY_BROKER_URL=redis://localhost:6379/0 +CELERY_RESULT_BACKEND=redis://localhost:6379/1 + +# Postgres +POSTGRES_USER=postgres +POSTGRES_PASSWORD=postgres +POSTGRES_DB=postgres \ No newline at end of file diff --git a/.sample_env b/.env_files/.env.sample similarity index 100% rename from .sample_env rename to .env_files/.env.sample diff --git a/.github/workflows/django-ci.yml b/.github/workflows/django-ci.yml new file mode 100644 index 0000000..95bd350 --- /dev/null +++ b/.github/workflows/django-ci.yml @@ -0,0 +1,54 @@ +name: Django CI (Postgres) + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + test: + runs-on: ubuntu-latest + services: + postgres: + image: postgres:15 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: web_test + ports: ["5432:5432"] + options: >- + --health-cmd="pg_isready -U postgres" + --health-interval=10s + --health-timeout=5s + --health-retries=5 + redis: + image: redis:7 + ports: ["6379:6379"] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install dependencies + run: pip install -r requirements.txt + + - name: Run migrations + working-directory: src + run: | + set -o allexport + source ../.env_files/.env.ci + python manage.py migrate + set +o allexport + + - name: Run tests + working-directory: src + run: | + set -o allexport + source ../.env_files/.env.ci + pytest + set +o allexport \ No newline at end of file diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..3a400e3 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,25 @@ +name: Lint & Format + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + - name: Install dependencies + run: pip install -r requirements.txt + - name: Run Black + run: black --check . + - name: Run isort + run: isort --check-only . + - name: Run flake8 + run: flake8 . \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index e88c9ce..80182b5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -22,7 +22,8 @@ "python.testing.pytestEnabled": true, "editor.formatOnSave": true, "editor.codeActionsOnSave": { - "source.organizeImports": "always" + "source.organizeImports": "always", + "source.fixAll": "always" }, "editor.rulers": [ 88 diff --git a/docker-compose.yml b/docker-compose.yml index 86d0c04..3a54711 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: volumes: - ./:/workspace:cached env_file: - - .env + - .env_files/.env command: ["/bin/sh", "/workspace/scripts/django/start.sh"] ports: - "8000:8000" @@ -25,7 +25,7 @@ services: volumes: - ./:/workspace:cached env_file: - - .env + - .env_files/.env command: ["/bin/sh", "/workspace/scripts/celery/worker.sh"] depends_on: db: @@ -43,7 +43,7 @@ services: - ./:/workspace:cached working_dir: /workspace/src env_file: - - .env + - .env_files/.env command: ["/bin/sh", "/workspace/scripts/celery/beat.sh"] depends_on: db: @@ -74,7 +74,7 @@ services: ports: - "5432:5432" env_file: - - .env + - .env_files/.env networks: - backend healthcheck: diff --git a/setup.cfg b/setup.cfg index e17bcee..6c99721 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,18 +1,33 @@ [black] -line-length = 88 # Set line length to 88 +line-length = 88 -[pylint] -disable = C0114 # Disable missing module docstring warning +[isort] +profile = black +multi_line_output = 3 +include_trailing_comma = true +force_grid_wrap = 0 +use_parentheses = true +ensure_newline_before_comments = true +line_length = 88 +remove_redundant_aliases = true [flake8] -max-line-length = 88 # Set line length to 88 -extend-ignore = E203, W503 # Ignore specific warnings +max-line-length = 88 +extend-ignore = E203, W503 +exclude = .git,__pycache__,migrations,venv +per-file-ignores = + src/backend/settings_test.py: F405 -[isort] -multi_line_output = 3 # Vertical hanging indent for imports -include_trailing_comma = true # Add trailing comma -force_grid_wrap = 0 # Disable wrapping -use_parentheses = true # Use parentheses for wrapping -ensure_newline_before_comments = true # Newline before comments in imports -line_length = 88 # Set line length to 88 -remove_redundant_aliases = true # Remove redundant aliases \ No newline at end of file +[pylint] +disable = C0114 + +[mypy] +plugins = mypy_django_plugin.main +ignore_missing_imports = True + +[mypy-tests.*] +ignore_errors = True + +[mypy.plugins.django-stubs] +django_settings_module = "backend.settings" +strict_settings = True \ No newline at end of file diff --git a/src/backend/settings.py b/src/backend/settings.py index cc55764..1cc45ce 100644 --- a/src/backend/settings.py +++ b/src/backend/settings.py @@ -44,7 +44,7 @@ "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.common.CommonMiddleware", - "corsheaders.middleware.CorsMiddleware", # CORS middleware should be high in the order + "corsheaders.middleware.CorsMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", @@ -80,11 +80,13 @@ # Password validation AUTH_PASSWORD_VALIDATORS = [ { - "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" + "NAME": ( + "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" + ) }, - {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"}, - {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"}, - {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"}, + {"NAME": ("django.contrib.auth.password_validation.MinimumLengthValidator")}, + {"NAME": ("django.contrib.auth.password_validation.CommonPasswordValidator")}, + {"NAME": ("django.contrib.auth.password_validation.NumericPasswordValidator")}, ] # Internationalization settings diff --git a/src/backend/settings_test.py b/src/backend/settings_test.py index e98e7b0..8aeae3a 100644 --- a/src/backend/settings_test.py +++ b/src/backend/settings_test.py @@ -1,3 +1,3 @@ -from backend.settings import * # noqa: F401,F403 +from backend.settings import * # noqa: F401,F403,F405 DATABASES = {"default": env.db("DATABASE_URI")} diff --git a/src/items/apps.py b/src/items/apps.py index f6e4373..f3a05b1 100644 --- a/src/items/apps.py +++ b/src/items/apps.py @@ -6,4 +6,4 @@ class ItemsConfig(AppConfig): name = "items" def ready(self): - import items.signals + pass diff --git a/src/items/migrations/0002_item_external_price.py b/src/items/migrations/0002_item_external_price.py index da7af5e..17450f4 100644 --- a/src/items/migrations/0002_item_external_price.py +++ b/src/items/migrations/0002_item_external_price.py @@ -1,6 +1,7 @@ # Generated by Django 5.1.7 on 2025-08-01 11:09 from decimal import Decimal + from django.db import migrations, models