From 0dcc4c4b4cfb8b3a3a7e59c6f7cc5b2794baa943 Mon Sep 17 00:00:00 2001 From: Bruno Alla Date: Sat, 15 Apr 2023 12:15:15 +0100 Subject: [PATCH] Add more pre-commit hooks (#4266) * Add more hooks from pre-commit-hooks repo * Add pre-commit hook for prettier * Format with prettier * Remove check-docstring-first hook * Run prettier in the template * Tweak formatting of dependabot file * Fix formatting of GitHub files for prettier * More format fixes of ci.yml --- .github/CONTRIBUTORS-template.md | 10 +- .github/ISSUE_TEMPLATE/bug.md | 68 ++++---- .github/ISSUE_TEMPLATE/paid-support.md | 6 +- .github/PULL_REQUEST_TEMPLATE.md | 1 - .github/changelog-template.md | 9 +- .github/dependabot.yml | 12 +- .github/workflows/ci.yml | 2 +- .github/workflows/pre-commit-autoupdate.yml | 4 +- .github/workflows/update-contributors.yml | 2 +- .pre-commit-config.yaml | 16 +- CONTRIBUTORS.md | 10 +- README.md | 113 ++++++------- cookiecutter.json | 29 +--- docs/generate-project-block.rst | 1 - .../.github/dependabot.yml | 78 +++++---- .../.github/workflows/ci.yml | 28 ++-- .../.pre-commit-config.yaml | 19 ++- .../.readthedocs.yml | 2 +- {{cookiecutter.project_slug}}/README.md | 14 +- .../compose/production/traefik/traefik.yml | 20 +-- {{cookiecutter.project_slug}}/gulpfile.js | 158 +++++++++--------- {{cookiecutter.project_slug}}/local.yml | 10 +- {{cookiecutter.project_slug}}/production.yml | 6 +- .../webpack/common.config.js | 21 +-- .../webpack/prod.config.js | 6 +- .../static/js/project.js | 4 +- .../static/sass/project.scss | 17 +- 27 files changed, 343 insertions(+), 323 deletions(-) diff --git a/.github/CONTRIBUTORS-template.md b/.github/CONTRIBUTORS-template.md index d8ba28c6..bc092847 100644 --- a/.github/CONTRIBUTORS-template.md +++ b/.github/CONTRIBUTORS-template.md @@ -22,8 +22,8 @@ accept and merge pull requests. {%- endfor %} -*Audrey is also the creator of Cookiecutter. Audrey and Daniel are on -the Cookiecutter core team.* +_Audrey is also the creator of Cookiecutter. Audrey and Daniel are on +the Cookiecutter core team._ ## Other Contributors @@ -51,6 +51,6 @@ Listed in alphabetical order. The following haven't provided code directly, but have provided guidance and advice. -- Jannis Leidel -- Nate Aune -- Barry Morrison +- Jannis Leidel +- Nate Aune +- Barry Morrison diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index e984493d..0e5ec12c 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -12,41 +12,47 @@ labels: bug -* Host system configuration: - * Version of cookiecutter CLI (get it with `cookiecutter --version`): - * OS name and version: +- Host system configuration: - On Linux, run - ```bash - lsb_release -a 2> /dev/null || cat /etc/redhat-release 2> /dev/null || cat /etc/*-release 2> /dev/null || cat /etc/issue 2> /dev/null - ``` + - Version of cookiecutter CLI (get it with `cookiecutter --version`): + - OS name and version: - On MacOs, run - ```bash - sw_vers - ``` + On Linux, run - On Windows, via CMD, run - ``` - systeminfo | findstr /B /C:"OS Name" /C:"OS Version" - ``` - - - ```bash - # Insert here the OS name and version - - ``` - - * Python version, run `python3 -V`: - * Docker version (if using Docker), run `docker --version`: - * docker-compose version (if using Docker), run `docker-compose --version`: - * ... -* Options selected and/or [replay file](https://cookiecutter.readthedocs.io/en/latest/advanced/replay.html): - On Linux and MacOS: `cat ${HOME}/.cookiecutter_replay/cookiecutter-django.json` - (Please, take care to remove sensitive information) - ```json - # Insert here the replay file content + ```bash + lsb_release -a 2> /dev/null || cat /etc/redhat-release 2> /dev/null || cat /etc/*-release 2> /dev/null || cat /etc/issue 2> /dev/null ``` + + On MacOs, run + + ```bash + sw_vers + ``` + + On Windows, via CMD, run + + ``` + systeminfo | findstr /B /C:"OS Name" /C:"OS Version" + ``` + + ```bash + # Insert here the OS name and version + + ``` + + - Python version, run `python3 -V`: + - Docker version (if using Docker), run `docker --version`: + - docker-compose version (if using Docker), run `docker-compose --version`: + - ... + +- Options selected and/or [replay file](https://cookiecutter.readthedocs.io/en/latest/advanced/replay.html): + On Linux and macOS: `cat ${HOME}/.cookiecutter_replay/cookiecutter-django.json` + (Please, take care to remove sensitive information) + +```json + +``` + Logs:
diff --git a/.github/ISSUE_TEMPLATE/paid-support.md b/.github/ISSUE_TEMPLATE/paid-support.md index 9f997a8c..f4e7578a 100644 --- a/.github/ISSUE_TEMPLATE/paid-support.md +++ b/.github/ISSUE_TEMPLATE/paid-support.md @@ -5,8 +5,8 @@ about: Ask Core Team members to help you out Provided your question goes beyond [regular support](https://github.com/cookiecutter/cookiecutter-django/issues/new?template=question.md), and/or the task at hand is of timely/high priority nature use the below information to reach out for contributors directly. -* Daniel Roy Greenfeld, Project Lead ([GitHub](https://github.com/pydanny), [Patreon](https://www.patreon.com/danielroygreenfeld)): expertise in Django and AWS ELB. +- Bruno Alla, Core Developer ([GitHub](https://github.com/sponsors/browniebroke)). -* Nikita Shupeyko, Core Developer ([GitHub](https://github.com/webyneter)): expertise in Python/Django, hands-on DevOps and frontend experience. +- Daniel Roy Greenfeld, Project Lead ([GitHub](https://github.com/pydanny), [Patreon](https://www.patreon.com/danielroygreenfeld)): expertise in Django and AWS ELB. -* Bruno Alla, Core Developer ([GitHub](https://github.com/sponsors/browniebroke)). +- Nikita Shupeyko, Core Developer ([GitHub](https://github.com/webyneter)): expertise in Python/Django, hands-on DevOps and frontend experience. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 10b66e26..2b197873 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,5 @@ - ## Description diff --git a/.github/changelog-template.md b/.github/changelog-template.md index 50aab38e..64bb7179 100644 --- a/.github/changelog-template.md +++ b/.github/changelog-template.md @@ -1,8 +1,11 @@ {%- for change_type, pulls in grouped_pulls.items() %} {%- if pulls %} + ### {{ change_type }} + {%- for pull_request in pulls %} + - {{ pull_request.title }} ([#{{ pull_request.number }}]({{ pull_request.html_url }})) -{%- endfor -%} -{% endif -%} -{% endfor -%} + {%- endfor -%} + {% endif -%} + {% endfor -%} diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d308ff96..7642a3f2 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -29,7 +29,9 @@ updates: interval: "daily" ignore: - dependency-name: "*" - update-types: ["version-update:semver-major", "version-update:semver-minor"] + update-types: + - "version-update:semver-major" + - "version-update:semver-minor" labels: - "update" @@ -39,7 +41,9 @@ updates: interval: "daily" ignore: - dependency-name: "*" - update-types: ["version-update:semver-major", "version-update:semver-minor"] + update-types: + - "version-update:semver-major" + - "version-update:semver-minor" labels: - "update" @@ -63,7 +67,9 @@ updates: interval: "daily" ignore: - dependency-name: "*" - update-types: ["version-update:semver-major", "version-update:semver-minor"] + update-types: + - "version-update:semver-major" + - "version-update:semver-minor" labels: - "update" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8100270b..c7cdda63 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: CI on: push: - branches: [ "master", "main" ] + branches: ["master", "main"] pull_request: concurrency: diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index 9e5232dc..75bfe0a2 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -16,8 +16,8 @@ jobs: # Disables this workflow from running in a repository that is not part of the indicated organization/user if: github.repository_owner == 'cookiecutter' permissions: - contents: write # for peter-evans/create-pull-request to create branch - pull-requests: write # for peter-evans/create-pull-request to create a PR + contents: write # for peter-evans/create-pull-request to create branch + pull-requests: write # for peter-evans/create-pull-request to create a PR runs-on: ubuntu-latest steps: diff --git a/.github/workflows/update-contributors.yml b/.github/workflows/update-contributors.yml index 2aea8003..78d72c24 100644 --- a/.github/workflows/update-contributors.yml +++ b/.github/workflows/update-contributors.yml @@ -13,7 +13,7 @@ jobs: # Disables this workflow from running in a repository that is not part of the indicated organization/user if: github.repository_owner == 'cookiecutter' permissions: - contents: write # for stefanzweifel/git-auto-commit-action to push code in repo + contents: write # for stefanzweifel/git-auto-commit-action to push code in repo runs-on: ubuntu-latest steps: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 34bcc6a2..d0b2f16b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -exclude: "{{cookiecutter.project_slug}}" +exclude: "{{cookiecutter.project_slug}}|.github/contributors.json|CHANGELOG.md" default_stages: [commit] repos: @@ -6,7 +6,21 @@ repos: rev: v4.4.0 hooks: - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-json + - id: check-toml + - id: check-xml - id: check-yaml + - id: debug-statements + - id: check-builtin-literals + - id: check-case-conflict + - id: detect-private-key + + - repo: https://github.com/pre-commit/mirrors-prettier + rev: "v3.0.0-alpha.6" + hooks: + - id: prettier + args: ["--tab-width", "2"] - repo: https://github.com/asottile/pyupgrade rev: v3.3.1 diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 7d9ee775..c821674f 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -76,8 +76,8 @@ accept and merge pull requests. -*Audrey is also the creator of Cookiecutter. Audrey and Daniel are on -the Cookiecutter core team.* +_Audrey is also the creator of Cookiecutter. Audrey and Daniel are on +the Cookiecutter core team._ ## Other Contributors @@ -1965,6 +1965,6 @@ Listed in alphabetical order. The following haven't provided code directly, but have provided guidance and advice. -- Jannis Leidel -- Nate Aune -- Barry Morrison \ No newline at end of file +- Jannis Leidel +- Nate Aune +- Barry Morrison diff --git a/README.md b/README.md index 4216c2d4..90cbe337 100644 --- a/README.md +++ b/README.md @@ -12,58 +12,58 @@ Powered by [Cookiecutter](https://github.com/cookiecutter/cookiecutter), Cookiecutter Django is a framework for jumpstarting production-ready Django projects quickly. -- Documentation: -- See [Troubleshooting](https://cookiecutter-django.readthedocs.io/en/latest/troubleshooting.html) for common errors and obstacles -- If you have problems with Cookiecutter Django, please open [issues](https://github.com/cookiecutter/cookiecutter-django/issues/new) don't send - emails to the maintainers. +- Documentation: +- See [Troubleshooting](https://cookiecutter-django.readthedocs.io/en/latest/troubleshooting.html) for common errors and obstacles +- If you have problems with Cookiecutter Django, please open [issues](https://github.com/cookiecutter/cookiecutter-django/issues/new) don't send + emails to the maintainers. ## Features -- For Django 4.1 -- Works with Python 3.11 -- Renders Django projects with 100% starting test coverage -- Twitter [Bootstrap](https://github.com/twbs/bootstrap) v5 -- [12-Factor](http://12factor.net/) based settings via [django-environ](https://github.com/joke2k/django-environ) -- Secure by default. We believe in SSL. -- Optimized development and production settings -- Registration via [django-allauth](https://github.com/pennersr/django-allauth) -- Comes with custom user model ready to go -- Optional basic ASGI setup for Websockets -- Optional custom static build using Gulp or Webpack -- Send emails via [Anymail](https://github.com/anymail/django-anymail) (using [Mailgun](http://www.mailgun.com/) by default or Amazon SES if AWS is selected cloud provider, but switchable) -- Media storage using Amazon S3, Google Cloud Storage, Azure Storage or nginx -- Docker support using [docker-compose](https://github.com/docker/compose) for development and production (using [Traefik](https://traefik.io/) with [LetsEncrypt](https://letsencrypt.org/) support) -- [Procfile](https://devcenter.heroku.com/articles/procfile) for deploying to Heroku -- Instructions for deploying to [PythonAnywhere](https://www.pythonanywhere.com/) -- Run tests with unittest or pytest -- Customizable PostgreSQL version -- Default integration with [pre-commit](https://github.com/pre-commit/pre-commit) for identifying simple issues before submission to code review +- For Django 4.1 +- Works with Python 3.11 +- Renders Django projects with 100% starting test coverage +- Twitter [Bootstrap](https://github.com/twbs/bootstrap) v5 +- [12-Factor](http://12factor.net/) based settings via [django-environ](https://github.com/joke2k/django-environ) +- Secure by default. We believe in SSL. +- Optimized development and production settings +- Registration via [django-allauth](https://github.com/pennersr/django-allauth) +- Comes with custom user model ready to go +- Optional basic ASGI setup for Websockets +- Optional custom static build using Gulp or Webpack +- Send emails via [Anymail](https://github.com/anymail/django-anymail) (using [Mailgun](http://www.mailgun.com/) by default or Amazon SES if AWS is selected cloud provider, but switchable) +- Media storage using Amazon S3, Google Cloud Storage, Azure Storage or nginx +- Docker support using [docker-compose](https://github.com/docker/compose) for development and production (using [Traefik](https://traefik.io/) with [LetsEncrypt](https://letsencrypt.org/) support) +- [Procfile](https://devcenter.heroku.com/articles/procfile) for deploying to Heroku +- Instructions for deploying to [PythonAnywhere](https://www.pythonanywhere.com/) +- Run tests with unittest or pytest +- Customizable PostgreSQL version +- Default integration with [pre-commit](https://github.com/pre-commit/pre-commit) for identifying simple issues before submission to code review ## Optional Integrations -*These features can be enabled during initial project setup.* +_These features can be enabled during initial project setup._ -- Serve static files from Amazon S3, Google Cloud Storage, Azure Storage or [Whitenoise](https://whitenoise.readthedocs.io/) -- Configuration for [Celery](https://docs.celeryq.dev) and [Flower](https://github.com/mher/flower) (the latter in Docker setup only) -- Integration with [MailHog](https://github.com/mailhog/MailHog) for local email testing -- Integration with [Sentry](https://sentry.io/welcome/) for error logging +- Serve static files from Amazon S3, Google Cloud Storage, Azure Storage or [Whitenoise](https://whitenoise.readthedocs.io/) +- Configuration for [Celery](https://docs.celeryq.dev) and [Flower](https://github.com/mher/flower) (the latter in Docker setup only) +- Integration with [MailHog](https://github.com/mailhog/MailHog) for local email testing +- Integration with [Sentry](https://sentry.io/welcome/) for error logging ## Constraints -- Only maintained 3rd party libraries are used. -- Uses PostgreSQL everywhere: 10.19 - 14.1 ([MySQL fork](https://github.com/mabdullahadeel/cookiecutter-django-mysql) also available). -- Environment variables for configuration (This won't work with Apache/mod_wsgi). +- Only maintained 3rd party libraries are used. +- Uses PostgreSQL everywhere: 10.19 - 14.1 ([MySQL fork](https://github.com/mabdullahadeel/cookiecutter-django-mysql) also available). +- Environment variables for configuration (This won't work with Apache/mod_wsgi). ## Support this Project! This project is run by volunteers. Please support them in their efforts to maintain and improve Cookiecutter Django: -- Daniel Roy Greenfeld, Project Lead ([GitHub](https://github.com/pydanny), [Patreon](https://www.patreon.com/danielroygreenfeld)): expertise in Django and AWS ELB. -- Nikita Shupeyko, Core Developer ([GitHub](https://github.com/webyneter)): expertise in Python/Django, hands-on DevOps and frontend experience. +- Daniel Roy Greenfeld, Project Lead ([GitHub](https://github.com/pydanny), [Patreon](https://www.patreon.com/danielroygreenfeld)): expertise in Django and AWS ELB. +- Nikita Shupeyko, Core Developer ([GitHub](https://github.com/webyneter)): expertise in Python/Django, hands-on DevOps and frontend experience. Projects that provide financial support to the maintainers: ------------------------------------------------------------------------- +---

@@ -188,14 +188,14 @@ Now take a look at your repo. Don't forget to carefully look at the generated RE For local development, see the following: -- [Developing locally](http://cookiecutter-django.readthedocs.io/en/latest/developing-locally.html) -- [Developing locally using docker](http://cookiecutter-django.readthedocs.io/en/latest/developing-locally-docker.html) +- [Developing locally](http://cookiecutter-django.readthedocs.io/en/latest/developing-locally.html) +- [Developing locally using docker](http://cookiecutter-django.readthedocs.io/en/latest/developing-locally-docker.html) ## Community -- Have questions? **Before you ask questions anywhere else**, please post your question on [Stack Overflow](http://stackoverflow.com/questions/tagged/cookiecutter-django) under the *cookiecutter-django* tag. We check there periodically for questions. -- If you think you found a bug or want to request a feature, please open an [issue](https://github.com/cookiecutter/cookiecutter-django/issues). -- For anything else, you can chat with us on [Discord](https://discord.gg/uFXweDQc5a). +- Have questions? **Before you ask questions anywhere else**, please post your question on [Stack Overflow](http://stackoverflow.com/questions/tagged/cookiecutter-django) under the _cookiecutter-django_ tag. We check there periodically for questions. +- If you think you found a bug or want to request a feature, please open an [issue](https://github.com/cookiecutter/cookiecutter-django/issues). +- For anything else, you can chat with us on [Discord](https://discord.gg/uFXweDQc5a). ## For Readers of Two Scoops of Django @@ -203,13 +203,14 @@ You may notice that some elements of this project do not exactly match what we d ## For PyUp Users -If you are using [PyUp](https://pyup.io) to keep your dependencies updated and secure, use the code *cookiecutter* during checkout to get 15% off every month. +If you are using [PyUp](https://pyup.io) to keep your dependencies updated and secure, use the code _cookiecutter_ during checkout to get 15% off every month. ## "Your Stuff" Scattered throughout the Python and HTML of this project are places marked with "your stuff". This is where third-party libraries are to be integrated with your project. ## For MySQL users + To get full MySQL support in addition to the default Postgresql, you can use this fork of the cookiecutter-django: https://github.com/mabdullahadeel/cookiecutter-django-mysql @@ -219,18 +220,18 @@ Need a stable release? You can find them at `. - diff --git a/{{cookiecutter.project_slug}}/.github/dependabot.yml b/{{cookiecutter.project_slug}}/.github/dependabot.yml index 3f4eefe9..be52c68d 100644 --- a/{{cookiecutter.project_slug}}/.github/dependabot.yml +++ b/{{cookiecutter.project_slug}}/.github/dependabot.yml @@ -4,11 +4,11 @@ version: 2 updates: # Update GitHub actions in workflows - - package-ecosystem: "github-actions" - directory: "/" + - package-ecosystem: 'github-actions' + directory: '/' # Every weekday schedule: - interval: "daily" + interval: 'daily' {%- if cookiecutter.use_docker == 'y' %} @@ -16,86 +16,92 @@ updates: # We need to specify each Dockerfile in a separate entry because Dependabot doesn't # support wildcards or recursively checking subdirectories. Check this issue for updates: # https://github.com/dependabot/dependabot-core/issues/2178 - - package-ecosystem: "docker" + - package-ecosystem: 'docker' # Look for a `Dockerfile` in the `compose/local/django` directory - directory: "compose/local/django/" + directory: 'compose/local/django/' # Every weekday schedule: - interval: "daily" + interval: 'daily' # Ignore minor version updates (3.10 -> 3.11) but update patch versions ignore: - - dependency-name: "*" - update-types: ["version-update:semver-major", "version-update:semver-minor"] + - dependency-name: '*' + update-types: + - 'version-update:semver-major' + - 'version-update:semver-minor' - - package-ecosystem: "docker" + - package-ecosystem: 'docker' # Look for a `Dockerfile` in the `compose/local/docs` directory - directory: "compose/local/docs/" + directory: 'compose/local/docs/' # Every weekday schedule: - interval: "daily" + interval: 'daily' # Ignore minor version updates (3.10 -> 3.11) but update patch versions ignore: - - dependency-name: "*" - update-types: ["version-update:semver-major", "version-update:semver-minor"] + - dependency-name: '*' + update-types: + - 'version-update:semver-major' + - 'version-update:semver-minor' - - package-ecosystem: "docker" + - package-ecosystem: 'docker' # Look for a `Dockerfile` in the `compose/local/node` directory - directory: "compose/local/node/" + directory: 'compose/local/node/' # Every weekday schedule: - interval: "daily" + interval: 'daily' - - package-ecosystem: "docker" + - package-ecosystem: 'docker' # Look for a `Dockerfile` in the `compose/production/aws` directory - directory: "compose/production/aws/" + directory: 'compose/production/aws/' # Every weekday schedule: - interval: "daily" + interval: 'daily' - - package-ecosystem: "docker" + - package-ecosystem: 'docker' # Look for a `Dockerfile` in the `compose/production/django` directory - directory: "compose/production/django/" + directory: 'compose/production/django/' # Every weekday schedule: - interval: "daily" + interval: 'daily' # Ignore minor version updates (3.10 -> 3.11) but update patch versions ignore: - - dependency-name: "*" - update-types: ["version-update:semver-major", "version-update:semver-minor"] + - dependency-name: '*' + update-types: + - 'version-update:semver-major' + - 'version-update:semver-minor' - - package-ecosystem: "docker" + - package-ecosystem: 'docker' # Look for a `Dockerfile` in the `compose/production/postgres` directory - directory: "compose/production/postgres/" + directory: 'compose/production/postgres/' # Every weekday schedule: - interval: "daily" + interval: 'daily' - - package-ecosystem: "docker" + - package-ecosystem: 'docker' # Look for a `Dockerfile` in the `compose/production/traefik` directory - directory: "compose/production/traefik/" + directory: 'compose/production/traefik/' # Every weekday schedule: - interval: "daily" + interval: 'daily' {%- endif %} # Enable version updates for Python/Pip - Production - - package-ecosystem: "pip" + - package-ecosystem: 'pip' # Look for a `requirements.txt` in the `root` directory # also 'setup.cfg', 'runtime.txt' and 'requirements/*.txt' - directory: "/" + directory: '/' # Every weekday schedule: - interval: "daily" + interval: 'daily' {%- if cookiecutter.frontend_pipeline == 'Gulp' %} # Enable version updates for javascript/npm - - package-ecosystem: "npm" + - package-ecosystem: 'npm' # Look for a `packages.json` in the `root` directory - directory: "/" + directory: '/' # Every weekday schedule: - interval: "daily" + interval: 'daily' {%- endif %} diff --git a/{{cookiecutter.project_slug}}/.github/workflows/ci.yml b/{{cookiecutter.project_slug}}/.github/workflows/ci.yml index 497d0dd2..ac231ee7 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/ci.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/ci.yml @@ -7,12 +7,12 @@ env: on: pull_request: - branches: [ "master", "main" ] - paths-ignore: [ "docs/**" ] + branches: ['master', 'main'] + paths-ignore: ['docs/**'] push: - branches: [ "master", "main" ] - paths-ignore: [ "docs/**" ] + branches: ['master', 'main'] + paths-ignore: ['docs/**'] concurrency: group: {% raw %}${{ github.head_ref || github.run_id }}{% endraw %} @@ -22,14 +22,13 @@ jobs: linter: runs-on: ubuntu-latest steps: - - name: Checkout Code Repository uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: - python-version: "3.11" + python-version: '3.11' {%- if cookiecutter.open_source_license != 'Not open source' %} # Consider using pre-commit.ci for open source project @@ -58,35 +57,34 @@ jobs: env: {%- if cookiecutter.use_celery == 'y' %} - CELERY_BROKER_URL: "redis://localhost:6379/0" + CELERY_BROKER_URL: 'redis://localhost:6379/0' {%- endif %} # postgres://user:password@host:port/database - DATABASE_URL: "postgres://postgres:postgres@localhost:5432/postgres" + DATABASE_URL: 'postgres://postgres:postgres@localhost:5432/postgres' {%- endif %} steps: - - name: Checkout Code Repository uses: actions/checkout@v3 {%- if cookiecutter.use_docker == 'y' %} - name: Build the Stack - run: docker-compose -f local.yml build + run: docker-compose -f local.yml build - name: Run DB Migrations - run: docker-compose -f local.yml run --rm django python manage.py migrate + run: docker-compose -f local.yml run --rm django python manage.py migrate - name: Run Django Tests - run: docker-compose -f local.yml run django pytest + run: docker-compose -f local.yml run django pytest - name: Tear down the Stack - run: docker-compose -f local.yml down + run: docker-compose -f local.yml down {%- else %} - name: Set up Python uses: actions/setup-python@v4 with: - python-version: "3.11" + python-version: '3.11' cache: pip cache-dependency-path: | requirements/base.txt @@ -98,5 +96,5 @@ jobs: pip install -r requirements/local.txt - name: Test with pytest - run: pytest + run: pytest {%- endif %} diff --git a/{{cookiecutter.project_slug}}/.pre-commit-config.yaml b/{{cookiecutter.project_slug}}/.pre-commit-config.yaml index 54218742..a7c8fa58 100644 --- a/{{cookiecutter.project_slug}}/.pre-commit-config.yaml +++ b/{{cookiecutter.project_slug}}/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -exclude: "^docs/|/migrations/" +exclude: '^docs/|/migrations/' default_stages: [commit] repos: @@ -7,7 +7,22 @@ repos: hooks: - id: trailing-whitespace - id: end-of-file-fixer + - id: check-json + - id: check-toml + - id: check-xml - id: check-yaml + - id: debug-statements + - id: check-builtin-literals + - id: check-case-conflict + - id: check-docstring-first + - id: detect-private-key + + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v3.0.0-alpha.6 + hooks: + - id: prettier + args: ['--tab-width', '2', '--single-quote'] + exclude: {{cookiecutter.project_slug}}/templates/ - repo: https://github.com/asottile/pyupgrade rev: v3.3.1 @@ -29,7 +44,7 @@ repos: rev: 6.0.0 hooks: - id: flake8 - args: ["--config=setup.cfg"] + args: ['--config=setup.cfg'] additional_dependencies: [flake8-isort] # sets up .pre-commit-ci.yaml to ensure pre-commit dependencies stay up to date diff --git a/{{cookiecutter.project_slug}}/.readthedocs.yml b/{{cookiecutter.project_slug}}/.readthedocs.yml index 44512245..d5a8ef66 100644 --- a/{{cookiecutter.project_slug}}/.readthedocs.yml +++ b/{{cookiecutter.project_slug}}/.readthedocs.yml @@ -8,7 +8,7 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.11" + python: '3.11' # Build documentation in the docs/ directory with Sphinx sphinx: diff --git a/{{cookiecutter.project_slug}}/README.md b/{{cookiecutter.project_slug}}/README.md index 83f9a7e4..56853f8f 100644 --- a/{{cookiecutter.project_slug}}/README.md +++ b/{{cookiecutter.project_slug}}/README.md @@ -18,11 +18,11 @@ Moved to [settings](http://cookiecutter-django.readthedocs.io/en/latest/settings ### Setting Up Your Users -- To create a **normal user account**, just go to Sign Up and fill out the form. Once you submit it, you'll see a "Verify Your E-mail Address" page. Go to your console to see a simulated email verification message. Copy the link into your browser. Now the user's email should be verified and ready to go. +- To create a **normal user account**, just go to Sign Up and fill out the form. Once you submit it, you'll see a "Verify Your E-mail Address" page. Go to your console to see a simulated email verification message. Copy the link into your browser. Now the user's email should be verified and ready to go. -- To create a **superuser account**, use this command: +- To create a **superuser account**, use this command: - $ python manage.py createsuperuser + $ python manage.py createsuperuser For convenience, you can keep your normal user logged in on Chrome and your superuser logged in on Firefox (or similar), so that you can see how the site behaves for both kinds of users. @@ -56,23 +56,23 @@ This app comes with Celery. To run a celery worker: -``` bash +```bash cd {{cookiecutter.project_slug}} celery -A config.celery_app worker -l info ``` -Please note: For Celery's import magic to work, it is important *where* the celery commands are run. If you are in the same folder with *manage.py*, you should be right. +Please note: For Celery's import magic to work, it is important _where_ the celery commands are run. If you are in the same folder with _manage.py_, you should be right. To run [periodic tasks](https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html), you'll need to start the celery beat scheduler service. You can start it as a standalone process: -``` bash +```bash cd {{cookiecutter.project_slug}} celery -A config.celery_app beat ``` or you can embed the beat service inside a worker with the `-B` option (not recommended for production use): -``` bash +```bash cd {{cookiecutter.project_slug}} celery -A config.celery_app worker -B -l info ``` diff --git a/{{cookiecutter.project_slug}}/compose/production/traefik/traefik.yml b/{{cookiecutter.project_slug}}/compose/production/traefik/traefik.yml index 85d9572b..724c95cd 100644 --- a/{{cookiecutter.project_slug}}/compose/production/traefik/traefik.yml +++ b/{{cookiecutter.project_slug}}/compose/production/traefik/traefik.yml @@ -4,7 +4,7 @@ log: entryPoints: web: # http - address: ":80" + address: ':80' http: # https://docs.traefik.io/routing/entrypoints/#entrypoint redirections: @@ -13,18 +13,18 @@ entryPoints: web-secure: # https - address: ":443" + address: ':443' {%- if cookiecutter.use_celery == 'y' %} flower: - address: ":5555" + address: ':5555' {%- endif %} certificatesResolvers: letsencrypt: # https://docs.traefik.io/master/https/acme/#lets-encrypt acme: - email: "{{ cookiecutter.email }}" + email: '{{ cookiecutter.email }}' storage: /etc/traefik/acme/acme.json # https://docs.traefik.io/master/https/acme/#httpchallenge httpChallenge: @@ -34,9 +34,9 @@ http: routers: web-secure-router: {%- if cookiecutter.domain_name.count('.') == 1 %} - rule: "Host(`{{ cookiecutter.domain_name }}`) || Host(`www.{{ cookiecutter.domain_name }}`)" + rule: 'Host(`{{ cookiecutter.domain_name }}`) || Host(`www.{{ cookiecutter.domain_name }}`)' {%- else %} - rule: "Host(`{{ cookiecutter.domain_name }}`)" + rule: 'Host(`{{ cookiecutter.domain_name }}`)' {%- endif %} entryPoints: - web-secure @@ -49,7 +49,7 @@ http: {%- if cookiecutter.use_celery == 'y' %} flower-secure-router: - rule: "Host(`{{ cookiecutter.domain_name }}`)" + rule: 'Host(`{{ cookiecutter.domain_name }}`)' entryPoints: - flower service: flower @@ -61,9 +61,9 @@ http: web-media-router: {%- if cookiecutter.domain_name.count('.') == 1 %} - rule: "(Host(`{{ cookiecutter.domain_name }}`) || Host(`www.{{ cookiecutter.domain_name }}`)) && PathPrefix(`/media/`)" + rule: '(Host(`{{ cookiecutter.domain_name }}`) || Host(`www.{{ cookiecutter.domain_name }}`)) && PathPrefix(`/media/`)' {%- else %} - rule: "Host(`{{ cookiecutter.domain_name }}`) && PathPrefix(`/media/`)" + rule: 'Host(`{{ cookiecutter.domain_name }}`) && PathPrefix(`/media/`)' {%- endif %} entryPoints: - web-secure @@ -79,7 +79,7 @@ http: # https://docs.traefik.io/master/middlewares/headers/#hostsproxyheaders # https://docs.djangoproject.com/en/dev/ref/csrf/#ajax headers: - hostsProxyHeaders: ["X-CSRFToken"] + hostsProxyHeaders: ['X-CSRFToken'] services: django: diff --git a/{{cookiecutter.project_slug}}/gulpfile.js b/{{cookiecutter.project_slug}}/gulpfile.js index fa3636ea..df434c13 100644 --- a/{{cookiecutter.project_slug}}/gulpfile.js +++ b/{{cookiecutter.project_slug}}/gulpfile.js @@ -3,29 +3,29 @@ //////////////////////////////// // Gulp and package -const { src, dest, parallel, series, watch } = require('gulp') -const pjson = require('./package.json') +const { src, dest, parallel, series, watch } = require('gulp'); +const pjson = require('./package.json'); // Plugins -const autoprefixer = require('autoprefixer') -const browserSync = require('browser-sync').create() -const concat = require('gulp-concat') +const autoprefixer = require('autoprefixer'); +const browserSync = require('browser-sync').create(); +const concat = require('gulp-concat'); const tildeImporter = require('node-sass-tilde-importer'); -const cssnano = require ('cssnano') -const imagemin = require('gulp-imagemin') -const pixrem = require('pixrem') -const plumber = require('gulp-plumber') -const postcss = require('gulp-postcss') -const reload = browserSync.reload -const rename = require('gulp-rename') -const sass = require('gulp-sass')(require('sass')) -const spawn = require('child_process').spawn -const uglify = require('gulp-uglify-es').default +const cssnano = require('cssnano'); +const imagemin = require('gulp-imagemin'); +const pixrem = require('pixrem'); +const plumber = require('gulp-plumber'); +const postcss = require('gulp-postcss'); +const reload = browserSync.reload; +const rename = require('gulp-rename'); +const sass = require('gulp-sass')(require('sass')); +const spawn = require('child_process').spawn; +const uglify = require('gulp-uglify-es').default; // Relative paths function function pathsConfig(appName) { - this.app = `./${pjson.name}` - const vendorsRoot = 'node_modules' + this.app = `./${pjson.name}`; + const vendorsRoot = 'node_modules'; return { vendorsJs: [ @@ -39,10 +39,10 @@ function pathsConfig(appName) { fonts: `${this.app}/static/fonts`, images: `${this.app}/static/images`, js: `${this.app}/static/js`, - } + }; } -const paths = pathsConfig() +const paths = pathsConfig(); //////////////////////////////// // Tasks @@ -51,27 +51,27 @@ const paths = pathsConfig() // Styles autoprefixing and minification function styles() { const processCss = [ - autoprefixer(), // adds vendor prefixes - pixrem(), // add fallbacks for rem units - ] + autoprefixer(), // adds vendor prefixes + pixrem(), // add fallbacks for rem units + ]; const minifyCss = [ - cssnano({ preset: 'default' }) // minify result - ] + cssnano({ preset: 'default' }), // minify result + ]; return src(`${paths.sass}/project.scss`) - .pipe(sass({ - importer: tildeImporter, - includePaths: [ - paths.sass - ] - }).on('error', sass.logError)) + .pipe( + sass({ + importer: tildeImporter, + includePaths: [paths.sass], + }).on('error', sass.logError), + ) .pipe(plumber()) // Checks for errors .pipe(postcss(processCss)) .pipe(dest(paths.css)) .pipe(rename({ suffix: '.min' })) .pipe(postcss(minifyCss)) // Minifies the result - .pipe(dest(paths.css)) + .pipe(dest(paths.css)); } // Javascript minification @@ -80,7 +80,7 @@ function scripts() { .pipe(plumber()) // Checks for errors .pipe(uglify()) // Minifies the js .pipe(rename({ suffix: '.min' })) - .pipe(dest(paths.js)) + .pipe(dest(paths.js)); } // Vendor Javascript minification @@ -91,97 +91,91 @@ function vendorScripts() { .pipe(plumber()) // Checks for errors .pipe(uglify()) // Minifies the js .pipe(rename({ suffix: '.min' })) - .pipe(dest(paths.js, { sourcemaps: '.' })) + .pipe(dest(paths.js, { sourcemaps: '.' })); } // Image compression function imgCompression() { return src(`${paths.images}/*`) .pipe(imagemin()) // Compresses PNG, JPEG, GIF and SVG images - .pipe(dest(paths.images)) + .pipe(dest(paths.images)); } {%- if cookiecutter.use_async == 'y' -%} // Run django server function asyncRunServer() { - const cmd = spawn('gunicorn', [ - 'config.asgi', '-k', 'uvicorn.workers.UvicornWorker', '--reload' - ], {stdio: 'inherit'} - ) - cmd.on('close', function(code) { - console.log('gunicorn exited with code ' + code) + const cmd = spawn( + 'gunicorn', + ['config.asgi', '-k', 'uvicorn.workers.UvicornWorker', '--reload'], + {stdio: 'inherit'}, + ); + cmd.on('close', function (code) { + console.log('gunicorn exited with code ' + code); }) } {%- else %} // Run django server function runServer(cb) { - const cmd = spawn('python', ['manage.py', 'runserver'], {stdio: 'inherit'}) - cmd.on('close', function(code) { - console.log('runServer exited with code ' + code) - cb(code) - }) + const cmd = spawn('python', ['manage.py', 'runserver'], { stdio: 'inherit' }); + cmd.on('close', function (code) { + console.log('runServer exited with code ' + code); + cb(code); + }); } {%- endif %} // Browser sync server for live reload function initBrowserSync() { browserSync.init( - [ - `${paths.css}/*.css`, - `${paths.js}/*.js`, - `${paths.templates}/*.html` - ], { + [`${paths.css}/*.css`, `${paths.js}/*.js`, `${paths.templates}/*.html`], + { {%- if cookiecutter.use_docker == 'y' %} // https://www.browsersync.io/docs/options/#option-open // Disable as it doesn't work from inside a container open: false, {%- endif %} // https://www.browsersync.io/docs/options/#option-proxy - proxy: { + proxy: { {%- if cookiecutter.use_docker == 'n' %} target: '127.0.0.1:8000', {%- else %} target: 'django:8000', {%- endif %} proxyReq: [ - function(proxyReq, req) { - // Assign proxy "host" header same as current request at Browsersync server - proxyReq.setHeader('Host', req.headers.host) - } - ] - } - } - ) + function (proxyReq, req) { + // Assign proxy 'host' header same as current request at Browsersync server + proxyReq.setHeader('Host', req.headers.host); + }, + ], + }, + }, + ); } // Watch function watchPaths() { - watch(`${paths.sass}/*.scss`{% if cookiecutter.windows == 'y' %}, { usePolling: true }{% endif %}, styles) - watch(`${paths.templates}/**/*.html`{% if cookiecutter.windows == 'y' %}, { usePolling: true }{% endif %}).on("change", reload) - watch([`${paths.js}/*.js`, `!${paths.js}/*.min.js`]{% if cookiecutter.windows == 'y' %}, { usePolling: true }{% endif %}, scripts).on("change", reload) + watch(`${paths.sass}/*.scss`{% if cookiecutter.windows == 'y' %}, { usePolling: true }{% endif %}, styles); + watch(`${paths.templates}/**/*.html`{% if cookiecutter.windows == 'y' %}, { usePolling: true }{% endif %}).on('change', reload); + watch([`${paths.js}/*.js`, `!${paths.js}/*.min.js`]{% if cookiecutter.windows == 'y' %}, { usePolling: true }{% endif %}, scripts).on( + 'change', + reload, + ); } // Generate all assets -const generateAssets = parallel( - styles, - scripts, - vendorScripts, - imgCompression -) +const generateAssets = parallel(styles, scripts, vendorScripts, imgCompression); // Set up dev environment -const dev = parallel( - {%- if cookiecutter.use_docker == 'n' %} - {%- if cookiecutter.use_async == 'y' %} - asyncRunServer, - {%- else %} - runServer, - {%- endif %} - {%- endif %} - initBrowserSync, - watchPaths -) +{%- if cookiecutter.use_docker == 'n' %} +{%- if cookiecutter.use_async == 'y' %} +const dev = parallel(asyncRunServer, initBrowserSync, watchPaths); +{%- else %} +const dev = parallel(runServer, initBrowserSync, watchPaths); +{%- endif %} +{%- else %} +const dev = parallel(initBrowserSync, watchPaths); +{%- endif %} -exports.default = series(generateAssets, dev) -exports["generate-assets"] = generateAssets -exports["dev"] = dev +exports.default = series(generateAssets, dev); +exports['generate-assets'] = generateAssets; +exports['dev'] = dev; diff --git a/{{cookiecutter.project_slug}}/local.yml b/{{cookiecutter.project_slug}}/local.yml index 66ca3b0e..e55e18d3 100644 --- a/{{cookiecutter.project_slug}}/local.yml +++ b/{{cookiecutter.project_slug}}/local.yml @@ -25,7 +25,7 @@ services: - ./.envs/.local/.django - ./.envs/.local/.postgres ports: - - "8000:8000" + - '8000:8000' command: /start postgres: @@ -53,7 +53,7 @@ services: - ./config:/app/config:z - ./{{ cookiecutter.project_slug }}:/app/{{ cookiecutter.project_slug }}:z ports: - - "9000:9000" + - '9000:9000' command: /start-docs {%- if cookiecutter.use_mailhog == 'y' %} @@ -101,7 +101,7 @@ services: image: {{ cookiecutter.project_slug }}_local_flower container_name: {{ cookiecutter.project_slug }}_local_flower ports: - - "5555:5555" + - '5555:5555' command: /start-flower {%- endif %} @@ -121,10 +121,10 @@ services: - /app/node_modules command: npm run dev ports: - - "3000:3000" + - '3000:3000' {%- if cookiecutter.frontend_pipeline == 'Gulp' %} # Expose browsersync UI: https://www.browsersync.io/docs/options/#option-ui - - "3001:3001" + - '3001:3001' {%- endif %} {%- endif %} diff --git a/{{cookiecutter.project_slug}}/production.yml b/{{cookiecutter.project_slug}}/production.yml index 4e9b9e04..4d56fbfa 100644 --- a/{{cookiecutter.project_slug}}/production.yml +++ b/{{cookiecutter.project_slug}}/production.yml @@ -60,10 +60,10 @@ services: volumes: - production_traefik:/etc/traefik/acme ports: - - "0.0.0.0:80:80" - - "0.0.0.0:443:443" + - '0.0.0.0:80:80' + - '0.0.0.0:443:443' {%- if cookiecutter.use_celery == 'y' %} - - "0.0.0.0:5555:5555" + - '0.0.0.0:5555:5555' {%- endif %} redis: diff --git a/{{cookiecutter.project_slug}}/webpack/common.config.js b/{{cookiecutter.project_slug}}/webpack/common.config.js index 41efb1c7..6aba2bc7 100644 --- a/{{cookiecutter.project_slug}}/webpack/common.config.js +++ b/{{cookiecutter.project_slug}}/webpack/common.config.js @@ -3,20 +3,25 @@ const BundleTracker = require('webpack-bundle-tracker'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = { - target: "web", + target: 'web', context: path.join(__dirname, '../'), entry: { - 'project': path.resolve(__dirname, '../{{cookiecutter.project_slug}}/static/js/project'), - 'vendors': path.resolve(__dirname, '../{{cookiecutter.project_slug}}/static/js/vendors'), + project: path.resolve(__dirname, '../{{cookiecutter.project_slug}}/static/js/project'), + vendors: path.resolve(__dirname, '../{{cookiecutter.project_slug}}/static/js/vendors'), }, output: { - path: path.resolve(__dirname, '../{{cookiecutter.project_slug}}/static/webpack_bundles/'), + path: path.resolve( + __dirname, + '../{{cookiecutter.project_slug}}/static/webpack_bundles/', + ), publicPath: '/static/webpack_bundles/', filename: 'js/[name]-[fullhash].js', chunkFilename: 'js/[name]-[hash].js', }, plugins: [ - new BundleTracker({filename: path.resolve(__dirname, '../webpack-stats.json')}), + new BundleTracker({ + filename: path.resolve(__dirname, '../webpack-stats.json'), + }), new MiniCssExtractPlugin({ filename: 'css/[name].[contenthash].css' }), ], module: { @@ -35,11 +40,7 @@ module.exports = { loader: 'postcss-loader', options: { postcssOptions: { - plugins: [ - 'postcss-preset-env', - 'autoprefixer', - 'pixrem', - ], + plugins: ['postcss-preset-env', 'autoprefixer', 'pixrem'], }, }, }, diff --git a/{{cookiecutter.project_slug}}/webpack/prod.config.js b/{{cookiecutter.project_slug}}/webpack/prod.config.js index b9c2186e..868d26dd 100644 --- a/{{cookiecutter.project_slug}}/webpack/prod.config.js +++ b/{{cookiecutter.project_slug}}/webpack/prod.config.js @@ -5,9 +5,9 @@ const commonConfig = require('./common.config'); {%- if cookiecutter.use_whitenoise == 'n' %} {%- if cookiecutter.cloud_provider == 'AWS' %} const s3BucketName = process.env.DJANGO_AWS_STORAGE_BUCKET_NAME; -const awsS3Domain = process.env.DJANGO_AWS_S3_CUSTOM_DOMAIN ? - process.env.DJANGO_AWS_S3_CUSTOM_DOMAIN - : `${s3BucketName}.s3.amazonaws.com`; +const awsS3Domain = process.env.DJANGO_AWS_S3_CUSTOM_DOMAIN + ? process.env.DJANGO_AWS_S3_CUSTOM_DOMAIN + : `${s3BucketName}.s3.amazonaws.com`; const staticUrl = `https://${awsS3Domain}/static/`; {%- elif cookiecutter.cloud_provider == 'GCP' %} const staticUrl = `https://storage.googleapis.com/${process.env.DJANGO_GCP_STORAGE_BUCKET_NAME}/static/`; diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/js/project.js b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/js/project.js index 62770f1c..930fa54a 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/js/project.js +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/js/project.js @@ -1,5 +1,5 @@ -{%- if cookiecutter.frontend_pipeline == 'Webpack' %} +{%- if cookiecutter.frontend_pipeline == 'Webpack' -%} import '../sass/project.scss'; -{%- endif %} +{% endif -%} /* Project specific Javascript goes here. */ diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/sass/project.scss b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/sass/project.scss index c9511e72..43435aca 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/sass/project.scss +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/sass/project.scss @@ -1,12 +1,11 @@ -@import "custom_bootstrap_vars"; -@import "~bootstrap/scss/bootstrap"; - +@import 'custom_bootstrap_vars'; +@import '~bootstrap/scss/bootstrap'; // project specific CSS goes here -//////////////////////////////// - //Variables// -//////////////////////////////// +/////////////// +// Variables // +/////////////// // Alert colors @@ -17,9 +16,9 @@ $pink: #f2dede; $dark-pink: #eed3d7; $red: #b94a48; -//////////////////////////////// - //Alerts// -//////////////////////////////// +//////////// +// Alerts // +//////////// // bootstrap alert CSS, translated to the django-standard levels of // debug, info, success, warning, error