From f00bdccfdb27512136b14adfee2151c9e4626621 Mon Sep 17 00:00:00 2001 From: Jonathan Moss Date: Fri, 1 Dec 2023 16:16:59 +1100 Subject: [PATCH] Make the template project compatible with startproject Adds the necessary place holders for ensuring the `template` project can be used with the Django `startproject` command. Also adds a Github workflow for the repository itself that ensure the repository can be used to create a valid Django project. --- .github/workflows/startproject.yml | 90 +++++++++++++++++++ README.md | 30 ++++++- template/Dockerfile | 8 +- template/example.env | 2 +- template/mkdocs.yml | 4 +- template/pyproject.toml | 10 +-- .../__init__.py | 0 .../main/__init__.py | 0 .../main/asgi.py | 4 +- .../main/settings.py | 4 +- .../main/urls.py | 0 .../main/views.py | 0 .../main/wsgi.py | 4 +- .../manage.py | 2 +- .../templates/pages/humans.txt | 0 template/src/tests/system/main/test_views.py | 2 +- template/tasks.py | 5 +- 17 files changed, 142 insertions(+), 23 deletions(-) create mode 100644 .github/workflows/startproject.yml rename template/src/{django_template => project_name}/__init__.py (100%) rename template/src/{django_template => project_name}/main/__init__.py (100%) rename template/src/{django_template => project_name}/main/asgi.py (69%) rename template/src/{django_template => project_name}/main/settings.py (96%) rename template/src/{django_template => project_name}/main/urls.py (100%) rename template/src/{django_template => project_name}/main/views.py (100%) rename template/src/{django_template => project_name}/main/wsgi.py (69%) rename template/src/{django_template => project_name}/manage.py (87%) rename template/src/{django_template => project_name}/templates/pages/humans.txt (100%) diff --git a/.github/workflows/startproject.yml b/.github/workflows/startproject.yml new file mode 100644 index 0000000..99aae53 --- /dev/null +++ b/.github/workflows/startproject.yml @@ -0,0 +1,90 @@ +name: Start Project + +on: + pull_request: + push: + branches: [main] + +# Restrict jobs in this workflow to have no permissions by default; permissions +# should be granted per job as needed using a dedicated `permissions` block +permissions: {} + +jobs: + creates-valid-project: + permissions: + contents: read + runs-on: ubuntu-latest + + services: + postgres: + image: postgres:14 + env: + POSTGRES_USER: dev + POSTGRES_PASSWORD: dev_password + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + # Allows us to use the same env config used locally by mapping to port to + # the test runner container. + - 5432:5432 + + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - uses: actions/setup-python@v4 + with: + python-version: "3.12" + + - name: Install Dependencies + run: | + sudo apt-get update + + # Project System Dependencies + sudo apt-get install -y \ + build-essential \ + libffi-dev \ + libpq-dev + + # Playwright System Dependencies + sudo apt-get install -y \ + libnss3\ + libnspr4\ + libatk1.0-0\ + libatk-bridge2.0-0\ + libcups2\ + libdrm2\ + libxkbcommon0\ + libatspi2.0-0\ + libxcomposite1\ + libxdamage1\ + libxfixes3\ + libxrandr2\ + libgbm1\ + libasound2 + + # Base Python tooling + pip install poetry django + + - name: Create test project + run: | + django-admin startproject \ + --template template/ \ + --extension py,Dockerfile,env,toml,yml \ + test_project + + - name: Install test project + run: | + cd test_project + poetry install + poetry run playwright install + + - name: Check test project is valid + run: | + cd test_project + cp example.env .env + poetry run invoke check diff --git a/README.md b/README.md index f74411f..fb720fc 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,36 @@ This project is intended as: - a place where we can document decisions that have been made about practices - e.g.: why X was picked, why Y was avoided (+ pros & cons) +## Usage + +To create a new project from this template, you must have the most recent stable version +of Django installed in order to run the `startproject` command. The simplest way to do +this is with [pipx][pipx]: + +```shell +pipx install django +``` + +This will ensure that the `django-admin` command is available in your shell. From there +you can create a new project with the following command: + +```shell +django-admin startproject --template path/to/django-template/template/ --extension py,env,toml,yml +``` + +!!! warn + The name of your project _must_ be a valid Python package name - that means + underscores (`_`) not hyphens (`-`) for name separators please. + +Running the Django admin command will create a new project in the folder specified in +with ``. + ## Contributing -If you have ideas for improvements, open a PR with your idea or propose it in the guild channel +If you have ideas for improvements, open a PR with your idea or propose it in the guild +channel Feature branches are encouraged, and merging should on consensus from guild + + +[pipx]: https://pypa.github.io/pipx/ diff --git a/template/Dockerfile b/template/Dockerfile index c717396..d99df83 100644 --- a/template/Dockerfile +++ b/template/Dockerfile @@ -1,7 +1,7 @@ # Packaging Stage # =============== -FROM python:3.11.2-slim-bullseye as packager +FROM python:3.12.0-slim-bullseye as packager ENV PYTHONUNBUFFERED=1 RUN pip install -U pip && pip install poetry COPY README.md pyproject.toml poetry.lock /source/ @@ -13,7 +13,7 @@ RUN rm -rf dist && poetry build # Building Stage # ============== -FROM python:3.11.2-slim-bullseye as builder +FROM python:3.12.0-bullseye as builder ENV PYTHONUNBUFFERED=1 RUN apt-get update && apt-get install -y \ @@ -22,7 +22,7 @@ RUN apt-get update && apt-get install -y \ libpq-dev \ && rm -rf /var/lib/apt/lists/* -COPY --from=packager /source/dist/django_template*.whl / +COPY --from=packager /source/dist/*.whl / RUN python -m venv /venv/ # _activate_ the virtual environment @@ -34,7 +34,7 @@ RUN pip install -U pip && pip install *.whl # Final Runtime # ============= -FROM python:3.11.2-slim-bullseye as runtime +FROM python:3.12.0-slim-bullseye as runtime ENV PYTHONUNBUFFERED=1 ARG GIT_COMMIT_HASH diff --git a/template/example.env b/template/example.env index ae4365e..5fa08c4 100644 --- a/template/example.env +++ b/template/example.env @@ -1,4 +1,4 @@ -SECRET_KEY="00c#jblr9b+s-^ulqj&8r8u1(-av#^!+e6czoz&(k4b3q1pacx" +SECRET_KEY={{ secret_key }} ALLOWED_HOSTS=* DEBUG=True diff --git a/template/mkdocs.yml b/template/mkdocs.yml index 8c8b3a8..31005cb 100644 --- a/template/mkdocs.yml +++ b/template/mkdocs.yml @@ -1,4 +1,4 @@ -site_name: django_template +site_name: "{{ project_name }}" watch: - src/ - docs/ @@ -37,6 +37,6 @@ plugins: setup_commands: - import os, sys - sys.path.append("src") - - os.environ["DJANGO_SETTINGS_MODULE"] = "{package_name}.main.settings" + - os.environ["DJANGO_SETTINGS_MODULE"] = "{{ project_name }}.main.settings" - tags: tags_file: tags.md diff --git a/template/pyproject.toml b/template/pyproject.toml index 7755e8c..094bdc3 100644 --- a/template/pyproject.toml +++ b/template/pyproject.toml @@ -1,13 +1,13 @@ [tool.poetry] authors = ["Jonathan Moss "] description = "" -name = "django-template" -packages = [{include = "django_template", from = "src"}] +name = "{{ project_name }}" +packages = [{include = "{{ project_name }}", from = "src"}] readme = "README.md" version = "0.1.0" [tool.poetry.scripts] -manage = "django_template.manage:main" +manage = "{{ project_name }}.manage:main" [tool.poetry.dependencies] django = "^4.2.7" @@ -67,13 +67,13 @@ ignore_missing_imports = true module = "environ" [tool.django-stubs] -django_settings_module = "django_template.main.settings" +django_settings_module = "{{ project_name }}.main.settings" [tool.isort] profile = "black" [tool.pytest.ini_options] -DJANGO_SETTINGS_MODULE = "django_template.main.settings" +DJANGO_SETTINGS_MODULE = "{{ project_name }}.main.settings" addopts = "--rootdir src --spec" norecursedirs = ".git .venv docs data" spec_header_format = "{test_case} [{module_path}]:" diff --git a/template/src/django_template/__init__.py b/template/src/project_name/__init__.py similarity index 100% rename from template/src/django_template/__init__.py rename to template/src/project_name/__init__.py diff --git a/template/src/django_template/main/__init__.py b/template/src/project_name/main/__init__.py similarity index 100% rename from template/src/django_template/main/__init__.py rename to template/src/project_name/main/__init__.py diff --git a/template/src/django_template/main/asgi.py b/template/src/project_name/main/asgi.py similarity index 69% rename from template/src/django_template/main/asgi.py rename to template/src/project_name/main/asgi.py index f0c2e3c..3e706ca 100644 --- a/template/src/django_template/main/asgi.py +++ b/template/src/project_name/main/asgi.py @@ -1,5 +1,5 @@ """ -ASGI config for django_template project. +ASGI config for {{ project_name }} project. It exposes the ASGI callable as a module-level variable named ``application``. @@ -11,6 +11,6 @@ from django.core.asgi import get_asgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_template.main.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.main.settings") application = get_asgi_application() diff --git a/template/src/django_template/main/settings.py b/template/src/project_name/main/settings.py similarity index 96% rename from template/src/django_template/main/settings.py rename to template/src/project_name/main/settings.py index db20482..5860db0 100644 --- a/template/src/django_template/main/settings.py +++ b/template/src/project_name/main/settings.py @@ -45,7 +45,7 @@ "django.middleware.clickjacking.XFrameOptionsMiddleware", ] -ROOT_URLCONF = "django_template.main.urls" +ROOT_URLCONF = "{{ project_name }}.main.urls" TEMPLATES = [ { @@ -63,7 +63,7 @@ }, ] -WSGI_APPLICATION = "django_template.main.wsgi.application" +WSGI_APPLICATION = "{{ project_name }}.main.wsgi.application" # Database diff --git a/template/src/django_template/main/urls.py b/template/src/project_name/main/urls.py similarity index 100% rename from template/src/django_template/main/urls.py rename to template/src/project_name/main/urls.py diff --git a/template/src/django_template/main/views.py b/template/src/project_name/main/views.py similarity index 100% rename from template/src/django_template/main/views.py rename to template/src/project_name/main/views.py diff --git a/template/src/django_template/main/wsgi.py b/template/src/project_name/main/wsgi.py similarity index 69% rename from template/src/django_template/main/wsgi.py rename to template/src/project_name/main/wsgi.py index 5434c9c..7d968ee 100644 --- a/template/src/django_template/main/wsgi.py +++ b/template/src/project_name/main/wsgi.py @@ -1,5 +1,5 @@ """ -WSGI config for django_template project. +WSGI config for {{ project_name }} project. It exposes the WSGI callable as a module-level variable named ``application``. @@ -11,6 +11,6 @@ from django.core.wsgi import get_wsgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_template.main.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.main.settings") application = get_wsgi_application() diff --git a/template/src/django_template/manage.py b/template/src/project_name/manage.py similarity index 87% rename from template/src/django_template/manage.py rename to template/src/project_name/manage.py index 4b07c43..1cc462f 100755 --- a/template/src/django_template/manage.py +++ b/template/src/project_name/manage.py @@ -6,7 +6,7 @@ def main() -> None: """Run administrative tasks.""" - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_template.main.settings") + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.main.settings") try: from django.core.management import execute_from_command_line except ImportError as exc: diff --git a/template/src/django_template/templates/pages/humans.txt b/template/src/project_name/templates/pages/humans.txt similarity index 100% rename from template/src/django_template/templates/pages/humans.txt rename to template/src/project_name/templates/pages/humans.txt diff --git a/template/src/tests/system/main/test_views.py b/template/src/tests/system/main/test_views.py index 0755de1..514cc1b 100644 --- a/template/src/tests/system/main/test_views.py +++ b/template/src/tests/system/main/test_views.py @@ -1,6 +1,6 @@ import json -from django_template.main import views +from {{ project_name }}.main import views def test_releases_view_includes_revision_details(settings, rf): diff --git a/template/tasks.py b/template/tasks.py index d3e053b..efc6750 100644 --- a/template/tasks.py +++ b/template/tasks.py @@ -7,7 +7,7 @@ # CONSTANTS # ############# -PACKAGE = "django_template" +PACKAGE = "{{ project_name }}" @invoke.task @@ -39,7 +39,8 @@ def typing(ctx): Check type annotations """ _title("Type checking") - # PYTHONPATH must include the `src` folder for django-stubs to find the settings module + # PYTHONPATH must include the `src` folder for django-stubs to find the settings + # module src_path = str((pathlib.Path() / "src").absolute()) with ctx.prefix(f"export PYTHONPATH=${{PYTHONPATH}}:{src_path}"): try: