diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 3a87b269b..000000000 --- a/.flake8 +++ /dev/null @@ -1,4 +0,0 @@ -[flake8] -exclude = docs -max-line-length = 119 -extend-ignore = E203 diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index da0480f1e..d955c79d4 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -13,7 +13,6 @@ labels: bug - Host system configuration: - - Version of cookiecutter CLI (get it with `cookiecutter --version`): - OS name and version: diff --git a/.github/contributors.json b/.github/contributors.json index df4b8f993..d70c5e371 100644 --- a/.github/contributors.json +++ b/.github/contributors.json @@ -1728,5 +1728,30 @@ "name": "Dominique Plante", "github_login": "dominiqueplante", "twitter_username": "" + }, + { + "name": "Lucas Klasa", + "github_login": "lucaskbr", + "twitter_username": "" + }, + { + "name": "DevForsure", + "github_login": "DevForsure", + "twitter_username": "" + }, + { + "name": "Vincent Leduc", + "github_login": "leducvin", + "twitter_username": "" + }, + { + "name": "Martín Blech", + "github_login": "martinblech", + "twitter_username": "" + }, + { + "name": "jlitrell", + "github_login": "jlitrell", + "twitter_username": "" } ] \ No newline at end of file diff --git a/.github/workflows/align-versions.yml b/.github/workflows/align-versions.yml index aea0707b8..ad058d7ef 100644 --- a/.github/workflows/align-versions.yml +++ b/.github/workflows/align-versions.yml @@ -14,7 +14,7 @@ permissions: jobs: run: - if: ${{ github.actor == 'pyup-bot' }} + if: ${{ github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request' && (github.event.pull_request.user.login == 'pyup-bot' || github.event.pull_request.user.login == 'dependabot[bot]') }} runs-on: ubuntu-latest env: GH_PAT: ${{ secrets.GH_PAT }} @@ -31,14 +31,14 @@ jobs: name: "${{ matrix.job.name }} versions" steps: - name: Checkout with token - uses: actions/checkout@v4 + uses: actions/checkout@v5 if: ${{ env.GH_PAT != '' }} with: token: ${{ env.GH_PAT }} ref: ${{ github.head_ref }} - name: Checkout without token - uses: actions/checkout@v4 + uses: actions/checkout@v5 if: ${{ env.GH_PAT == '' }} with: ref: ${{ github.head_ref }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3d4d7f7f5..7c6fe29fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: CI on: push: - branches: ["master", "main"] + branches: ["main"] pull_request: concurrency: @@ -22,7 +22,7 @@ jobs: name: "pytest ${{ matrix.os }}" runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install uv uses: astral-sh/setup-uv@v6 - name: Install dependencies @@ -51,7 +51,7 @@ jobs: COMPOSE_DOCKER_CLI_BUILD: 1 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install uv uses: astral-sh/setup-uv@v6 - name: Install dependencies @@ -93,7 +93,7 @@ jobs: DATABASE_URL: "postgres://postgres:postgres@localhost:5432/postgres" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: actions/setup-python@v5 with: python-version: "3.12" @@ -103,6 +103,6 @@ jobs: run: uv sync - uses: actions/setup-node@v4 with: - node-version: "22.14" + node-version: "24.7" - name: Bare Metal ${{ matrix.script.name }} run: sh tests/test_bare.sh ${{ matrix.script.args }} diff --git a/.github/workflows/dependabot-uv-lock.yml b/.github/workflows/dependabot-uv-lock.yml index 898a415a7..4992c0b3d 100644 --- a/.github/workflows/dependabot-uv-lock.yml +++ b/.github/workflows/dependabot-uv-lock.yml @@ -17,13 +17,13 @@ jobs: GH_PAT: ${{ secrets.GH_PAT }} steps: - name: Checkout with token - uses: actions/checkout@v4 + uses: actions/checkout@v5 if: ${{ env.GH_PAT != '' }} with: token: ${{ env.GH_PAT }} - name: Checkout without token - uses: actions/checkout@v4 + uses: actions/checkout@v5 if: ${{ env.GH_PAT == '' }} - uses: astral-sh/setup-uv@v6 diff --git a/.github/workflows/django-issue-checker.yml b/.github/workflows/django-issue-checker.yml index 79db564e0..aa904c089 100644 --- a/.github/workflows/django-issue-checker.yml +++ b/.github/workflows/django-issue-checker.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install uv uses: astral-sh/setup-uv@v6 - name: Create Django Major Issue diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index ebd092859..42b287da8 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: actions/setup-python@v5 with: python-version: "3.12" diff --git a/.github/workflows/update-changelog.yml b/.github/workflows/update-changelog.yml index 70b660471..e5eab0c85 100644 --- a/.github/workflows/update-changelog.yml +++ b/.github/workflows/update-changelog.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install uv uses: astral-sh/setup-uv@v6 - name: Set git details diff --git a/.github/workflows/update-contributors.yml b/.github/workflows/update-contributors.yml index eb95db9b7..136906407 100644 --- a/.github/workflows/update-contributors.yml +++ b/.github/workflows/update-contributors.yml @@ -3,7 +3,7 @@ name: Update Contributors on: push: branches: - - master + - main permissions: contents: read @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install uv uses: astral-sh/setup-uv@v6 - name: Update list diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b64915861..7ed4ead38 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ default_language_version: repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -26,27 +26,12 @@ repos: - id: prettier args: ["--tab-width", "2"] - - repo: https://github.com/asottile/pyupgrade - rev: v3.20.0 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.12.11 hooks: - - id: pyupgrade - args: [--py312-plus] - exclude: hooks/ - - - repo: https://github.com/psf/black - rev: 25.1.0 - hooks: - - id: black - - - repo: https://github.com/PyCQA/isort - rev: 6.0.1 - hooks: - - id: isort - - - repo: https://github.com/PyCQA/flake8 - rev: 7.3.0 - hooks: - - id: flake8 + - id: ruff + args: [--fix, --exit-non-zero-on-fix] + - id: ruff-format - repo: https://github.com/tox-dev/pyproject-fmt rev: "v2.6.0" diff --git a/CHANGELOG.md b/CHANGELOG.md index bfb40df01..af5fcc9a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,280 @@ All enhancements and patches to Cookiecutter Django will be documented in this f +## 2025.08.31 + + +### Updated + +- Update coverage to 7.10.6 ([#5999](https://github.com/cookiecutter/cookiecutter-django/pull/5999)) + +## 2025.08.29 + + +### Updated + +- Bump node from 24.6-bookworm-slim to 24.7-bookworm-slim in /{{cookiecutter.project_slug}}/compose/local/node ([#5997](https://github.com/cookiecutter/cookiecutter-django/pull/5997)) + +- Update ruff to 0.12.11 ([#5998](https://github.com/cookiecutter/cookiecutter-django/pull/5998)) + +## 2025.08.28 + + +### Updated + +- Update django-allauth to 65.11.1 ([#5992](https://github.com/cookiecutter/cookiecutter-django/pull/5992)) + +- Auto-update pre-commit hooks ([#5993](https://github.com/cookiecutter/cookiecutter-django/pull/5993)) + +## 2025.08.27 + + +### Updated + +- Update django-upgrade pre-commit hook ([#5991](https://github.com/cookiecutter/cookiecutter-django/pull/5991)) + +## 2025.08.26 + + +### Updated + +- Update sentry-sdk to 2.35.1 ([#5988](https://github.com/cookiecutter/cookiecutter-django/pull/5988)) + +- Update sphinx-autobuild to 2025.8.25 ([#5989](https://github.com/cookiecutter/cookiecutter-django/pull/5989)) + +## 2025.08.25 + + +### Updated + +- Update collectfasta to 3.3.1 ([#5987](https://github.com/cookiecutter/cookiecutter-django/pull/5987)) + +- Update coverage to 7.10.5 ([#5986](https://github.com/cookiecutter/cookiecutter-django/pull/5986)) + +- Update pytest-sugar to 1.1.1 ([#5984](https://github.com/cookiecutter/cookiecutter-django/pull/5984)) + +## 2025.08.21 + + +### Updated + +- Update ruff to 0.12.10 ([#5983](https://github.com/cookiecutter/cookiecutter-django/pull/5983)) + +## 2025.08.18 + + +### Updated + +- Bump node from 24.5 to 24.6 ([#5981](https://github.com/cookiecutter/cookiecutter-django/pull/5981)) + +- Update coverage to 7.10.4 ([#5980](https://github.com/cookiecutter/cookiecutter-django/pull/5980)) + +- Update pytest-sugar to 1.1.0 ([#5979](https://github.com/cookiecutter/cookiecutter-django/pull/5979)) + +## 2025.08.15 + + +### Updated + +- Update django-allauth to 65.11.0 ([#5977](https://github.com/cookiecutter/cookiecutter-django/pull/5977)) + +- Update sentry-sdk to 2.35.0 ([#5976](https://github.com/cookiecutter/cookiecutter-django/pull/5976)) + +## 2025.08.14 + + +### Updated + +- Update ruff to 0.12.9 ([#5975](https://github.com/cookiecutter/cookiecutter-django/pull/5975)) + +## 2025.08.13 + + +### Fixed + +- Fix imagemin corruption with Gulp ([#5974](https://github.com/cookiecutter/cookiecutter-django/pull/5974)) + +## 2025.08.12 + + +### Updated + +- Update coverage to 7.10.3 ([#5972](https://github.com/cookiecutter/cookiecutter-django/pull/5972)) + +## 2025.08.10 + + +### Updated + +- Update pre-commit to 4.3.0 ([#5971](https://github.com/cookiecutter/cookiecutter-django/pull/5971)) + +- Auto-update pre-commit hooks ([#5970](https://github.com/cookiecutter/cookiecutter-django/pull/5970)) + +## 2025.08.08 + + +### Changed + +- Remove `project.css` when a bundler is used ([#5874](https://github.com/cookiecutter/cookiecutter-django/pull/5874)) + +### Updated + +- Update redis to 6.4.0 ([#5968](https://github.com/cookiecutter/cookiecutter-django/pull/5968)) + +- Update ruff to 0.12.8 ([#5969](https://github.com/cookiecutter/cookiecutter-django/pull/5969)) + +## 2025.08.07 + + +### Updated + +- Update djangorestframework to 3.16.1 ([#5966](https://github.com/cookiecutter/cookiecutter-django/pull/5966)) + +## 2025.08.06 + + +### Updated + +- Update coverage to 7.10.2 ([#5964](https://github.com/cookiecutter/cookiecutter-django/pull/5964)) + +- Update redis to 6.3.0 ([#5963](https://github.com/cookiecutter/cookiecutter-django/pull/5963)) + +## 2025.08.05 + + +### Changed + +- Rename `master` branch to `main` ([#5961](https://github.com/cookiecutter/cookiecutter-django/pull/5961)) + +### Updated + +- Bump node from 22.14 to 24.5 in local Docker image ([#5960](https://github.com/cookiecutter/cookiecutter-django/pull/5960)) + +## 2025.08.01 + + +### Updated + +- Update django-debug-toolbar to 6.0.0 ([#5945](https://github.com/cookiecutter/cookiecutter-django/pull/5945)) + +- Bump amazon/aws-cli from 2.27.12 to 2.28.0 ([#5957](https://github.com/cookiecutter/cookiecutter-django/pull/5957)) + +- Update mypy to 1.17.1 ([#5956](https://github.com/cookiecutter/cookiecutter-django/pull/5956)) + +## 2025.07.30 + + +### Changed + +- docs: remove `$` from shell command examples for easier copy-pasting ([#5948](https://github.com/cookiecutter/cookiecutter-django/pull/5948)) + +### Updated + +- Update sentry-sdk to 2.34.1 ([#5955](https://github.com/cookiecutter/cookiecutter-django/pull/5955)) + +- Update ruff to 0.12.7 ([#5952](https://github.com/cookiecutter/cookiecutter-django/pull/5952)) + +## 2025.07.27 + + +### Updated + +- Update coverage to 7.10.1 ([#5947](https://github.com/cookiecutter/cookiecutter-django/pull/5947)) + +## 2025.07.25 + + +### Updated + +- Update django-anymail to 13.0.1 ([#5946](https://github.com/cookiecutter/cookiecutter-django/pull/5946)) + +## 2025.07.24 + + +### Updated + +- Update coverage to 7.10.0 ([#5944](https://github.com/cookiecutter/cookiecutter-django/pull/5944)) + +- Update ruff to 0.12.5 ([#5943](https://github.com/cookiecutter/cookiecutter-django/pull/5943)) + +- Bump traefik from 3.4.4 to 3.5.0 ([#5942](https://github.com/cookiecutter/cookiecutter-django/pull/5942)) + +## 2025.07.22 + + +### Updated + +- Update sentry-sdk to 2.33.2 ([#5941](https://github.com/cookiecutter/cookiecutter-django/pull/5941)) + +## 2025.07.21 + + +### Updated + +- Update sentry-sdk to 2.33.1 ([#5940](https://github.com/cookiecutter/cookiecutter-django/pull/5940)) + +## 2025.07.18 + + +### Updated + +- Update mypy to 1.17.0 ([#5937](https://github.com/cookiecutter/cookiecutter-django/pull/5937)) + +- Update django-stubs to 5.2.2 ([#5936](https://github.com/cookiecutter/cookiecutter-django/pull/5936)) + +## 2025.07.17 + + +### Updated + +- Update ruff to 0.12.4 ([#5935](https://github.com/cookiecutter/cookiecutter-django/pull/5935)) + +## 2025.07.16 + + +### Updated + +- Update sentry-sdk to 2.33.0 ([#5933](https://github.com/cookiecutter/cookiecutter-django/pull/5933)) + +## 2025.07.15 + + +### Updated + +- Update mypy to 1.16.1 ([#5901](https://github.com/cookiecutter/cookiecutter-django/pull/5901)) + +- Bump traefik from 3.4.3 to 3.4.4 ([#5930](https://github.com/cookiecutter/cookiecutter-django/pull/5930)) + +## 2025.07.14 + + +### Changed + +- Fix howto docker command ([#5929](https://github.com/cookiecutter/cookiecutter-django/pull/5929)) + +## 2025.07.11 + + +### Updated + +- Update ruff to 0.12.3 ([#5928](https://github.com/cookiecutter/cookiecutter-django/pull/5928)) + +- Update django-allauth to 65.10.0 ([#5927](https://github.com/cookiecutter/cookiecutter-django/pull/5927)) + +## 2025.07.05 + + +### Updated + +- Update coverage to 7.9.2 ([#5925](https://github.com/cookiecutter/cookiecutter-django/pull/5925)) + +## 2025.07.04 + + +### Updated + +- Update ruff to 0.12.2 ([#5923](https://github.com/cookiecutter/cookiecutter-django/pull/5923)) + ## 2025.07.02 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e6bf04061..b8a926794 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,7 @@ Always happy to get issues identified and pull requests! 2. Clone your fork 3. Create a branch for your changes -This last step is very important, don't start developing from master, it'll cause pain if you need to send another change later. +This last step is very important, don't start developing from main, it'll cause pain if you need to send another change later. ## Testing diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index faec8b02b..86acac432 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -768,6 +768,13 @@ Listed in alphabetical order. + + DevForsure + + DevForsure + + + Diane Chen @@ -1265,6 +1272,13 @@ Listed in alphabetical order. afrowave + + jlitrell + + jlitrell + + + John @@ -1510,6 +1524,13 @@ Listed in alphabetical order. + + Lucas Klasa + + lucaskbr + + + Luis Nell @@ -1594,6 +1615,13 @@ Listed in alphabetical order. + + Martín Blech + + martinblech + + + masavini @@ -2336,6 +2364,13 @@ Listed in alphabetical order. + + Vincent Leduc + + leducvin + + + Vitaly Babiy diff --git a/README.md b/README.md index 2d8f4af1b..e0f2d9e68 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Cookiecutter Django -[![Build Status](https://img.shields.io/github/actions/workflow/status/cookiecutter/cookiecutter-django/ci.yml?branch=master)](https://github.com/cookiecutter/cookiecutter-django/actions/workflows/ci.yml?query=branch%3Amaster) +[![Build Status](https://img.shields.io/github/actions/workflow/status/cookiecutter/cookiecutter-django/ci.yml?branch=main)](https://github.com/cookiecutter/cookiecutter-django/actions/workflows/ci.yml?query=branch%3Amain) [![Documentation Status](https://readthedocs.org/projects/cookiecutter-django/badge/?version=latest)](https://cookiecutter-django.readthedocs.io/en/latest/?badge=latest) -[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/cookiecutter/cookiecutter-django/master.svg)](https://results.pre-commit.ci/latest/github/cookiecutter/cookiecutter-django/master) +[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/cookiecutter/cookiecutter-django/main.svg)](https://results.pre-commit.ci/latest/github/cookiecutter/cookiecutter-django/main) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black) [![Updates](https://pyup.io/repos/github/cookiecutter/cookiecutter-django/shield.svg)](https://pyup.io/repos/github/cookiecutter/cookiecutter-django/) @@ -67,7 +67,7 @@ Projects that provide financial support to the maintainers: ### Two Scoops of Django -[![Cover of the book "Two Scoops of Django 3.x"](https://f004.backblazeb2.com/file/feldroycom/images/book-TSD3-800.jpg)](https://www.feldroy.com/two-scoops-press#two-scoops-of-django) +[![Cover of the book "Two Scoops of Django 3.x"](https://f004.backblazeb2.com/file/feldroycom/images/book-TSD3-800.jpg)](https://www.feldroy.com/two-scoops-of-django) Two Scoops of Django 3.x is the best ice cream-themed Django reference in the universe! @@ -84,11 +84,11 @@ and then editing the results to include your name, email, and various configurat First, get Cookiecutter. Trust me, it's awesome: - $ pip install "cookiecutter>=1.7.0" + pip install "cookiecutter>=1.7.0" Now run it against this repo: - $ cookiecutter https://github.com/cookiecutter/cookiecutter-django + cookiecutter https://github.com/cookiecutter/cookiecutter-django You'll be prompted for some values. Provide them, then a Django project will be created for you. @@ -175,16 +175,16 @@ Answer the prompts with your own desired [options](http://cookiecutter-django.re Enter the project and take a look around: - $ cd reddit/ - $ ls + cd reddit/ + ls Create a git repo and push it there: - $ git init - $ git add . - $ git commit -m "first awesome commit" - $ git remote add origin git@github.com:pydanny/redditclone.git - $ git push -u origin master + git init + git add . + git commit -m "first awesome commit" + git remote add origin git@github.com:pydanny/redditclone.git + git push -u origin main Now take a look at your repo. Don't forget to carefully look at the generated README. Awesome, right? diff --git a/docs/5-help/faq.rst b/docs/5-help/faq.rst index 294e6c8e1..5b4e824f5 100644 --- a/docs/5-help/faq.rst +++ b/docs/5-help/faq.rst @@ -10,7 +10,7 @@ It is there to add a migration so you don't have to manually change the ``sites. See `0003_set_site_domain_and_name.py`_. -.. _`0003_set_site_domain_and_name.py`: https://github.com/cookiecutter/cookiecutter-django/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/%7B%7Bcookiecutter.project_slug%7D%7D/contrib/sites/migrations/0003_set_site_domain_and_name.py +.. _`0003_set_site_domain_and_name.py`: https://github.com/cookiecutter/cookiecutter-django/blob/main/%7B%7Bcookiecutter.project_slug%7D%7D/%7B%7Bcookiecutter.project_slug%7D%7D/contrib/sites/migrations/0003_set_site_domain_and_name.py Why aren't you using just one configuration file (12-Factor App) diff --git a/docs/6-about/maintainer-guide.md b/docs/6-about/maintainer-guide.md index 9baac688a..fa9dfa95a 100644 --- a/docs/6-about/maintainer-guide.md +++ b/docs/6-about/maintainer-guide.md @@ -96,9 +96,9 @@ With that in mind, when merging changes, it's a good idea to set the labels and `update-contributors.yml` -Runs on each push to master branch. List the 5 most recently merged pull requests and extract their author. If any of the authors is a new one, updates the `.github/contributors.json`, regenerate the `CONTRIBUTORS.md` from it, and push back the changes to master. +Runs on each push to main branch. List the 5 most recently merged pull requests and extract their author. If any of the authors is a new one, updates the `.github/contributors.json`, regenerate the `CONTRIBUTORS.md` from it, and push back the changes to master. #### Limitations -- If you merge a pull request from a new contributor, and merge another one right after, the push to master will fail as the remote will be out of date. +- If you merge a pull request from a new contributor, and merge another one right after, the push to main will fail as the remote will be out of date. - If you merge more than 5 pull requests in a row like this, the new contributor might fail to be added. diff --git a/hooks/__init__.py b/hooks/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 318c5beb7..7ef449420 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -1,3 +1,4 @@ +# ruff: noqa: PLR0133 import json import random import shutil @@ -6,7 +7,7 @@ from pathlib import Path try: # Inspired by - # https://github.com/django/django/blob/master/django/utils/crypto.py + # https://github.com/django/django/blob/main/django/utils/crypto.py random = random.SystemRandom() using_sysrandom = True except NotImplementedError: @@ -79,7 +80,7 @@ def remove_heroku_files(): file_names = ["Procfile", "requirements.txt"] for file_name in file_names: if file_name == "requirements.txt" and "{{ cookiecutter.ci_tool }}".lower() == "travis": - # don't remove the file if we are using travisci but not using heroku + # Don't remove the file if we are using Travis CI but not using Heroku continue Path(file_name).unlink() shutil.rmtree("bin") @@ -106,6 +107,12 @@ def remove_vendors_js(): vendors_js_path.unlink() +def remove_project_css(): + project_css_path = Path("{{ cookiecutter.project_slug }}", "static", "css", "project.css") + if project_css_path.exists(): + project_css_path.unlink() + + def remove_packagejson_file(): file_names = ["package.json"] for file_name in file_names: @@ -179,7 +186,7 @@ def handle_js_runner(choice, use_docker, use_async): "dev": "concurrently npm:dev:*", "dev:webpack": "webpack serve --config webpack/dev.config.js", "dev:django": dev_django_cmd, - } + }, ) else: remove_dev_deps.append("concurrently") @@ -239,7 +246,7 @@ def remove_dotdrone_file(): Path(".drone.yml").unlink() -def generate_random_string(length, using_digits=False, using_ascii_letters=False, using_punctuation=False): +def generate_random_string(length, using_digits=False, using_ascii_letters=False, using_punctuation=False): # noqa: FBT002 """ Example: opting out for 50 symbol-long, [a-z][A-Z][0-9] string @@ -268,7 +275,7 @@ def set_flag(file_path: Path, flag, value=None, formatted=None, *args, **kwargs) if random_string is None: print( "We couldn't find a secure pseudo-random number generator on your " - "system. Please, make sure to manually {} later.".format(flag) + f"system. Please, make sure to manually {flag} later.", ) random_string = flag if formatted is not None: @@ -285,18 +292,17 @@ def set_flag(file_path: Path, flag, value=None, formatted=None, *args, **kwargs) def set_django_secret_key(file_path: Path): - django_secret_key = set_flag( + return set_flag( file_path, "!!!SET DJANGO_SECRET_KEY!!!", length=64, using_digits=True, using_ascii_letters=True, ) - return django_secret_key def set_django_admin_url(file_path: Path): - django_admin_url = set_flag( + return set_flag( file_path, "!!!SET DJANGO_ADMIN_URL!!!", formatted="{}/", @@ -304,24 +310,22 @@ def set_django_admin_url(file_path: Path): using_digits=True, using_ascii_letters=True, ) - return django_admin_url def generate_random_user(): return generate_random_string(length=32, using_ascii_letters=True) -def generate_postgres_user(debug=False): +def generate_postgres_user(debug=False): # noqa: FBT002 return DEBUG_VALUE if debug else generate_random_user() def set_postgres_user(file_path, value): - postgres_user = set_flag(file_path, "!!!SET POSTGRES_USER!!!", value=value) - return postgres_user + return set_flag(file_path, "!!!SET POSTGRES_USER!!!", value=value) def set_postgres_password(file_path, value=None): - postgres_password = set_flag( + return set_flag( file_path, "!!!SET POSTGRES_PASSWORD!!!", value=value, @@ -329,16 +333,14 @@ def set_postgres_password(file_path, value=None): using_digits=True, using_ascii_letters=True, ) - return postgres_password def set_celery_flower_user(file_path, value): - celery_flower_user = set_flag(file_path, "!!!SET CELERY_FLOWER_USER!!!", value=value) - return celery_flower_user + return set_flag(file_path, "!!!SET CELERY_FLOWER_USER!!!", value=value) def set_celery_flower_password(file_path, value=None): - celery_flower_password = set_flag( + return set_flag( file_path, "!!!SET CELERY_FLOWER_PASSWORD!!!", value=value, @@ -346,7 +348,6 @@ def set_celery_flower_password(file_path, value=None): using_digits=True, using_ascii_letters=True, ) - return celery_flower_password def append_to_gitignore_file(ignored_line): @@ -355,7 +356,7 @@ def append_to_gitignore_file(ignored_line): gitignore_file.write("\n") -def set_flags_in_envs(postgres_user, celery_flower_user, debug=False): +def set_flags_in_envs(postgres_user, celery_flower_user, debug=False): # noqa: FBT002 local_django_envs_path = Path(".envs", ".local", ".django") production_django_envs_path = Path(".envs", ".production", ".django") local_postgres_envs_path = Path(".envs", ".local", ".postgres") @@ -405,7 +406,7 @@ def remove_drf_starter_files(): shutil.rmtree(Path("{{cookiecutter.project_slug}}", "users", "tests", "api")) -def main(): +def main(): # noqa: C901, PLR0912, PLR0915 debug = "{{ cookiecutter.debug }}".lower() == "y" set_flags_in_envs( @@ -444,7 +445,7 @@ def main(): print( INFO + ".env(s) are only utilized when Docker Compose and/or " "Heroku support is enabled so keeping them does not make sense " - "given your current setup." + TERMINATOR + "given your current setup." + TERMINATOR, ) remove_envs_and_associated_files() else: @@ -462,6 +463,7 @@ def main(): if "{{ cookiecutter.use_docker }}".lower() == "y": remove_node_dockerfile() else: + remove_project_css() handle_js_runner( "{{ cookiecutter.frontend_pipeline }}", use_docker=("{{ cookiecutter.use_docker }}".lower() == "y"), @@ -471,7 +473,7 @@ def main(): if "{{ cookiecutter.cloud_provider }}" == "None" and "{{ cookiecutter.use_docker }}".lower() == "n": print( WARNING + "You chose to not use any cloud providers nor Docker, " - "media files won't be served in production." + TERMINATOR + "media files won't be served in production." + TERMINATOR, ) if "{{ cookiecutter.use_celery }}".lower() == "n": diff --git a/hooks/pre_gen_project.py b/hooks/pre_gen_project.py index 1e0c591ef..de2f87e3e 100644 --- a/hooks/pre_gen_project.py +++ b/hooks/pre_gen_project.py @@ -1,3 +1,4 @@ +# ruff: noqa: PLR0133 import sys TERMINATOR = "\x1b[0m" @@ -16,9 +17,9 @@ SUCCESS = "\x1b[1;32m [SUCCESS]: " project_slug = "{{ cookiecutter.project_slug }}" if hasattr(project_slug, "isidentifier"): - assert project_slug.isidentifier(), "'{}' project slug is not a valid Python identifier.".format(project_slug) + assert project_slug.isidentifier(), f"'{project_slug}' project slug is not a valid Python identifier." -assert project_slug == project_slug.lower(), "'{}' project slug should be all lowercase".format(project_slug) +assert project_slug == project_slug.lower(), f"'{project_slug}' project slug should be all lowercase" assert "\\" not in "{{ cookiecutter.author_name }}", "Don't include backslashes in author name." diff --git a/pyproject.toml b/pyproject.toml index 5fc62289b..dcd676543 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "cookiecutter-django" -version = "2025.07.02" +version = "2025.08.31" description = "A Cookiecutter template for creating production-ready Django projects quickly." readme = "README.md" keywords = [ @@ -43,7 +43,7 @@ dependencies = [ "pytest-xdist==3.6.1", "pyyaml==6.0.2", "requests==2.32.3", - "ruff==0.12.1", + "ruff==0.12.11", "sh==2.1; sys_platform!='win23'", "tox==4.23.2", "tox-uv>=1.17", @@ -58,22 +58,83 @@ docs = [ "sphinx-rtd-theme>=3", ] -[tool.black] +[tool.ruff] +target-version = "py39" line-length = 119 -target-version = [ - 'py312', +# Exclude the template content as most files aren't parseable +extend-exclude = [ + "[{]{2}cookiecutter.project_slug[}]{2}/*", + "docs/*", ] -# ==== isort ==== - -[tool.isort] -profile = "black" -line_length = 119 -known_first_party = [ - "tests", - "scripts", - "hooks", +lint.select = [ + "A", + # "ANN", # flake8-annotations: we should support this in the future but many errors atm + "ASYNC", + "B", + "BLE", + "C4", + "C90", + "COM", + "DTZ", + "E", + "EM", + "ERA", + "EXE", + "F", + "FA", + "FBT", + "FLY", + "G", + "I", + "ICN", + "INP", + "INT", + "ISC", + "N", + "PD", + "PERF", + "PGH", + "PIE", + "PL", + "PT", + # "ARG", # Unused function argument + "PTH", + "PYI", + "Q", + "RET", + "RSE", + # "FURB", + # "LOG", + "RUF", + "S", + "SIM", + "SLF", + "SLOT", + "T10", + "TC", + "TID", + "TRY", + "UP", + "W", + "YTT", ] +lint.ignore = [ + "EM101", + "RUF012", # Mutable class attributes should be annotated with `typing.ClassVar` + "S101", # Use of assert detected https://docs.astral.sh/ruff/rules/assert/ + "SIM102", # sometimes it's better to nest + "TRY003", # Avoid specifying long messages outside the exception class + # Checks for uses of isinstance/issubclass that take a tuple of types for comparison. + # Deactivated because it can make the code slow: https://github.com/astral-sh/ruff/issues/7871 + "UP038", +] +# The fixes in extend-unsafe-fixes will require +# provide the `--unsafe-fixes` flag when fixing. +lint.extend-unsafe-fixes = [ + "UP038", +] +lint.isort.force-single-line = true [tool.pyproject-fmt] keep_full_version = true diff --git a/scripts/create_django_issue.py b/scripts/create_django_issue.py index e728da798..bbc897f5c 100644 --- a/scripts/create_django_issue.py +++ b/scripts/create_django_issue.py @@ -13,7 +13,9 @@ import os import re import sys from pathlib import Path -from typing import TYPE_CHECKING, Any, NamedTuple +from typing import TYPE_CHECKING +from typing import Any +from typing import NamedTuple import requests from github import Github @@ -59,7 +61,7 @@ class DjVersion(NamedTuple): def get_package_info(package: str) -> dict: """Get package metadata using PyPI API.""" # "django" converts to "Django" on redirect - r = requests.get(f"https://pypi.org/pypi/{package}/json", allow_redirects=True) + r = requests.get(f"https://pypi.org/pypi/{package}/json", allow_redirects=True) # noqa: S113 if not r.ok: print(f"Couldn't find package: {package}") sys.exit(1) @@ -214,9 +216,9 @@ class GitHubManager: for classifier in package_info["info"]["classifiers"]: # Usually in the form of "Framework :: Django :: 3.2" tokens = classifier.split(" ") - if len(tokens) >= 5 and tokens[2].lower() == "django" and "." in tokens[4]: + if len(tokens) >= 5 and tokens[2].lower() == "django" and "." in tokens[4]: # noqa: PLR2004 version = DjVersion.parse(tokens[4]) - if len(version) == 2: + if len(version) == 2: # noqa: PLR2004 supported_dj_versions.append(version) if supported_dj_versions: diff --git a/scripts/ruff_version.py b/scripts/ruff_version.py index 4b0ab965c..114a58adc 100644 --- a/scripts/ruff_version.py +++ b/scripts/ruff_version.py @@ -1,12 +1,14 @@ from __future__ import annotations import subprocess -import tomllib from pathlib import Path +import tomllib + ROOT = Path(__file__).parent.parent TEMPLATED_ROOT = ROOT / "{{cookiecutter.project_slug}}" REQUIREMENTS_LOCAL_TXT = TEMPLATED_ROOT / "requirements" / "local.txt" +TEMPLATE_PRE_COMMIT_CONFIG = ROOT / ".pre-commit-config.yaml" PRE_COMMIT_CONFIG = TEMPLATED_ROOT / ".pre-commit-config.yaml" PYPROJECT_TOML = ROOT / "pyproject.toml" @@ -18,7 +20,7 @@ def main() -> None: return update_ruff_version(old_version, new_version) - subprocess.run(["uv", "lock", "--no-upgrade"], cwd=ROOT) + subprocess.run(["uv", "lock", "--no-upgrade"], cwd=ROOT, check=False) # noqa: S607 def get_requirements_txt_version() -> str: @@ -44,12 +46,13 @@ def update_ruff_version(old_version: str, new_version: str) -> None: f"ruff=={new_version}", ) PYPROJECT_TOML.write_text(new_content) - # Update pre-commit config - new_content = PRE_COMMIT_CONFIG.read_text().replace( - f"repo: https://github.com/astral-sh/ruff-pre-commit\n rev: v{old_version}", - f"repo: https://github.com/astral-sh/ruff-pre-commit\n rev: v{new_version}", - ) - PRE_COMMIT_CONFIG.write_text(new_content) + # Update pre-commit configs + for config_file in [PRE_COMMIT_CONFIG, TEMPLATE_PRE_COMMIT_CONFIG]: + new_content = config_file.read_text().replace( + f"repo: https://github.com/astral-sh/ruff-pre-commit\n rev: v{old_version}", + f"repo: https://github.com/astral-sh/ruff-pre-commit\n rev: v{new_version}", + ) + config_file.write_text(new_content) if __name__ == "__main__": diff --git a/scripts/update_changelog.py b/scripts/update_changelog.py index 1bedebf5a..773e687d1 100644 --- a/scripts/update_changelog.py +++ b/scripts/update_changelog.py @@ -23,7 +23,7 @@ def main() -> None: Script entry point. """ # Generate changelog for PRs merged yesterday - merged_date = dt.date.today() - dt.timedelta(days=1) + merged_date = dt.date.today() - dt.timedelta(days=1) # noqa: DTZ011 repo = Github(login_or_token=GITHUB_TOKEN).get_repo(GITHUB_REPO) merged_pulls = list(iter_pulls(repo, merged_date)) print(f"Merged pull requests: {merged_pulls}") @@ -54,7 +54,7 @@ def main() -> None: # Run uv lock uv_lock_path = ROOT / "uv.lock" - subprocess.run(["uv", "lock", "--no-upgrade"], cwd=ROOT) + subprocess.run(["uv", "lock", "--no-upgrade"], cwd=ROOT, check=False) # noqa: S607 # Commit changes, create tag and push update_git_repo([changelog_path, setup_py_path, uv_lock_path], release) diff --git a/tests/test_cookiecutter_generation.py b/tests/test_cookiecutter_generation.py index 76d2f4b98..bf56df3d6 100755 --- a/tests/test_cookiecutter_generation.py +++ b/tests/test_cookiecutter_generation.py @@ -1,4 +1,4 @@ -import glob +import glob # noqa: EXE002 import os import re import sys @@ -207,18 +207,6 @@ def test_ruff_format_passes(cookies, context_override): pytest.fail(e.stdout.decode()) -@auto_fixable -@pytest.mark.parametrize("context_override", SUPPORTED_COMBINATIONS, ids=_fixture_id) -def test_isort_passes(cookies, context_override): - """Check whether generated project passes isort style.""" - result = cookies.bake(extra_context=context_override) - - try: - sh.isort(_cwd=str(result.project_path)) - except sh.ErrorReturnCode as e: - pytest.fail(e.stdout.decode()) - - @auto_fixable @pytest.mark.parametrize("context_override", SUPPORTED_COMBINATIONS, ids=_fixture_id) def test_django_upgrade_passes(cookies, context_override): @@ -227,7 +215,7 @@ def test_django_upgrade_passes(cookies, context_override): python_files = [ file_path.removeprefix(f"{result.project_path}/") - for file_path in glob.glob(str(result.project_path / "**" / "*.py"), recursive=True) + for file_path in glob.glob(str(result.project_path / "**" / "*.py"), recursive=True) # noqa: PTH207 ] try: sh.django_upgrade( diff --git a/tox.ini b/tox.ini index 70cde339f..43cb6baa9 100644 --- a/tox.ini +++ b/tox.ini @@ -1,11 +1,7 @@ [tox] skipsdist = true -envlist = py312,black-template +envlist = py312 [testenv] passenv = AUTOFIXABLE_STYLES commands = pytest -n auto {posargs:./tests} - -[testenv:black-template] -deps = black -commands = black --check hooks tests docs scripts diff --git a/uv.lock b/uv.lock index 4f056d7ff..b2c685394 100644 --- a/uv.lock +++ b/uv.lock @@ -182,7 +182,7 @@ wheels = [ [[package]] name = "cookiecutter-django" -version = "2025.7.2" +version = "2025.8.31" source = { virtual = "." } dependencies = [ { name = "binaryornot" }, @@ -229,7 +229,7 @@ requires-dist = [ { name = "pytest-xdist", specifier = "==3.6.1" }, { name = "pyyaml", specifier = "==6.0.2" }, { name = "requests", specifier = "==2.32.3" }, - { name = "ruff", specifier = "==0.12.1" }, + { name = "ruff", specifier = "==0.12.11" }, { name = "sh", marker = "sys_platform != 'win23'", specifier = "==2.1" }, { name = "tox", specifier = "==4.23.2" }, { name = "tox-uv", specifier = ">=1.17" }, @@ -830,27 +830,28 @@ wheels = [ [[package]] name = "ruff" -version = "0.12.1" +version = "0.12.11" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/97/38/796a101608a90494440856ccfb52b1edae90de0b817e76bfade66b12d320/ruff-0.12.1.tar.gz", hash = "sha256:806bbc17f1104fd57451a98a58df35388ee3ab422e029e8f5cf30aa4af2c138c", size = 4413426 } +sdist = { url = "https://files.pythonhosted.org/packages/de/55/16ab6a7d88d93001e1ae4c34cbdcfb376652d761799459ff27c1dc20f6fa/ruff-0.12.11.tar.gz", hash = "sha256:c6b09ae8426a65bbee5425b9d0b82796dbb07cb1af045743c79bfb163001165d", size = 5347103 } wheels = [ - { url = "https://files.pythonhosted.org/packages/06/bf/3dba52c1d12ab5e78d75bd78ad52fb85a6a1f29cc447c2423037b82bed0d/ruff-0.12.1-py3-none-linux_armv6l.whl", hash = "sha256:6013a46d865111e2edb71ad692fbb8262e6c172587a57c0669332a449384a36b", size = 10305649 }, - { url = "https://files.pythonhosted.org/packages/8c/65/dab1ba90269bc8c81ce1d499a6517e28fe6f87b2119ec449257d0983cceb/ruff-0.12.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b3f75a19e03a4b0757d1412edb7f27cffb0c700365e9d6b60bc1b68d35bc89e0", size = 11120201 }, - { url = "https://files.pythonhosted.org/packages/3f/3e/2d819ffda01defe857fa2dd4cba4d19109713df4034cc36f06bbf582d62a/ruff-0.12.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:9a256522893cb7e92bb1e1153283927f842dea2e48619c803243dccc8437b8be", size = 10466769 }, - { url = "https://files.pythonhosted.org/packages/63/37/bde4cf84dbd7821c8de56ec4ccc2816bce8125684f7b9e22fe4ad92364de/ruff-0.12.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:069052605fe74c765a5b4272eb89880e0ff7a31e6c0dbf8767203c1fbd31c7ff", size = 10660902 }, - { url = "https://files.pythonhosted.org/packages/0e/3a/390782a9ed1358c95e78ccc745eed1a9d657a537e5c4c4812fce06c8d1a0/ruff-0.12.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a684f125a4fec2d5a6501a466be3841113ba6847827be4573fddf8308b83477d", size = 10167002 }, - { url = "https://files.pythonhosted.org/packages/6d/05/f2d4c965009634830e97ffe733201ec59e4addc5b1c0efa035645baa9e5f/ruff-0.12.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdecdef753bf1e95797593007569d8e1697a54fca843d78f6862f7dc279e23bd", size = 11751522 }, - { url = "https://files.pythonhosted.org/packages/35/4e/4bfc519b5fcd462233f82fc20ef8b1e5ecce476c283b355af92c0935d5d9/ruff-0.12.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:70d52a058c0e7b88b602f575d23596e89bd7d8196437a4148381a3f73fcd5010", size = 12520264 }, - { url = "https://files.pythonhosted.org/packages/85/b2/7756a6925da236b3a31f234b4167397c3e5f91edb861028a631546bad719/ruff-0.12.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84d0a69d1e8d716dfeab22d8d5e7c786b73f2106429a933cee51d7b09f861d4e", size = 12133882 }, - { url = "https://files.pythonhosted.org/packages/dd/00/40da9c66d4a4d51291e619be6757fa65c91b92456ff4f01101593f3a1170/ruff-0.12.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6cc32e863adcf9e71690248607ccdf25252eeeab5193768e6873b901fd441fed", size = 11608941 }, - { url = "https://files.pythonhosted.org/packages/91/e7/f898391cc026a77fbe68dfea5940f8213622474cb848eb30215538a2dadf/ruff-0.12.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fd49a4619f90d5afc65cf42e07b6ae98bb454fd5029d03b306bd9e2273d44cc", size = 11602887 }, - { url = "https://files.pythonhosted.org/packages/f6/02/0891872fc6aab8678084f4cf8826f85c5d2d24aa9114092139a38123f94b/ruff-0.12.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ed5af6aaaea20710e77698e2055b9ff9b3494891e1b24d26c07055459bb717e9", size = 10521742 }, - { url = "https://files.pythonhosted.org/packages/2a/98/d6534322c74a7d47b0f33b036b2498ccac99d8d8c40edadb552c038cecf1/ruff-0.12.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:801d626de15e6bf988fbe7ce59b303a914ff9c616d5866f8c79eb5012720ae13", size = 10149909 }, - { url = "https://files.pythonhosted.org/packages/34/5c/9b7ba8c19a31e2b6bd5e31aa1e65b533208a30512f118805371dbbbdf6a9/ruff-0.12.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2be9d32a147f98a1972c1e4df9a6956d612ca5f5578536814372113d09a27a6c", size = 11136005 }, - { url = "https://files.pythonhosted.org/packages/dc/34/9bbefa4d0ff2c000e4e533f591499f6b834346025e11da97f4ded21cb23e/ruff-0.12.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:49b7ce354eed2a322fbaea80168c902de9504e6e174fd501e9447cad0232f9e6", size = 11648579 }, - { url = "https://files.pythonhosted.org/packages/6f/1c/20cdb593783f8f411839ce749ec9ae9e4298c2b2079b40295c3e6e2089e1/ruff-0.12.1-py3-none-win32.whl", hash = "sha256:d973fa626d4c8267848755bd0414211a456e99e125dcab147f24daa9e991a245", size = 10519495 }, - { url = "https://files.pythonhosted.org/packages/cf/56/7158bd8d3cf16394928f47c637d39a7d532268cd45220bdb6cd622985760/ruff-0.12.1-py3-none-win_amd64.whl", hash = "sha256:9e1123b1c033f77bd2590e4c1fe7e8ea72ef990a85d2484351d408224d603013", size = 11547485 }, - { url = "https://files.pythonhosted.org/packages/91/d0/6902c0d017259439d6fd2fd9393cea1cfe30169940118b007d5e0ea7e954/ruff-0.12.1-py3-none-win_arm64.whl", hash = "sha256:78ad09a022c64c13cc6077707f036bab0fac8cd7088772dcd1e5be21c5002efc", size = 10691209 }, + { url = "https://files.pythonhosted.org/packages/d6/a2/3b3573e474de39a7a475f3fbaf36a25600bfeb238e1a90392799163b64a0/ruff-0.12.11-py3-none-linux_armv6l.whl", hash = "sha256:93fce71e1cac3a8bf9200e63a38ac5c078f3b6baebffb74ba5274fb2ab276065", size = 11979885 }, + { url = "https://files.pythonhosted.org/packages/76/e4/235ad6d1785a2012d3ded2350fd9bc5c5af8c6f56820e696b0118dfe7d24/ruff-0.12.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b8e33ac7b28c772440afa80cebb972ffd823621ded90404f29e5ab6d1e2d4b93", size = 12742364 }, + { url = "https://files.pythonhosted.org/packages/2c/0d/15b72c5fe6b1e402a543aa9d8960e0a7e19dfb079f5b0b424db48b7febab/ruff-0.12.11-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d69fb9d4937aa19adb2e9f058bc4fbfe986c2040acb1a4a9747734834eaa0bfd", size = 11920111 }, + { url = "https://files.pythonhosted.org/packages/3e/c0/f66339d7893798ad3e17fa5a1e587d6fd9806f7c1c062b63f8b09dda6702/ruff-0.12.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:411954eca8464595077a93e580e2918d0a01a19317af0a72132283e28ae21bee", size = 12160060 }, + { url = "https://files.pythonhosted.org/packages/03/69/9870368326db26f20c946205fb2d0008988aea552dbaec35fbacbb46efaa/ruff-0.12.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6a2c0a2e1a450f387bf2c6237c727dd22191ae8c00e448e0672d624b2bbd7fb0", size = 11799848 }, + { url = "https://files.pythonhosted.org/packages/25/8c/dd2c7f990e9b3a8a55eee09d4e675027d31727ce33cdb29eab32d025bdc9/ruff-0.12.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ca4c3a7f937725fd2413c0e884b5248a19369ab9bdd850b5781348ba283f644", size = 13536288 }, + { url = "https://files.pythonhosted.org/packages/7a/30/d5496fa09aba59b5e01ea76775a4c8897b13055884f56f1c35a4194c2297/ruff-0.12.11-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4d1df0098124006f6a66ecf3581a7f7e754c4df7644b2e6704cd7ca80ff95211", size = 14490633 }, + { url = "https://files.pythonhosted.org/packages/9b/2f/81f998180ad53445d403c386549d6946d0748e536d58fce5b5e173511183/ruff-0.12.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a8dd5f230efc99a24ace3b77e3555d3fbc0343aeed3fc84c8d89e75ab2ff793", size = 13888430 }, + { url = "https://files.pythonhosted.org/packages/87/71/23a0d1d5892a377478c61dbbcffe82a3476b050f38b5162171942a029ef3/ruff-0.12.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4dc75533039d0ed04cd33fb8ca9ac9620b99672fe7ff1533b6402206901c34ee", size = 12913133 }, + { url = "https://files.pythonhosted.org/packages/80/22/3c6cef96627f89b344c933781ed38329bfb87737aa438f15da95907cbfd5/ruff-0.12.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fc58f9266d62c6eccc75261a665f26b4ef64840887fc6cbc552ce5b29f96cc8", size = 13169082 }, + { url = "https://files.pythonhosted.org/packages/05/b5/68b3ff96160d8b49e8dd10785ff3186be18fd650d356036a3770386e6c7f/ruff-0.12.11-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:5a0113bd6eafd545146440225fe60b4e9489f59eb5f5f107acd715ba5f0b3d2f", size = 13139490 }, + { url = "https://files.pythonhosted.org/packages/59/b9/050a3278ecd558f74f7ee016fbdf10591d50119df8d5f5da45a22c6afafc/ruff-0.12.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0d737b4059d66295c3ea5720e6efc152623bb83fde5444209b69cd33a53e2000", size = 11958928 }, + { url = "https://files.pythonhosted.org/packages/f9/bc/93be37347db854806904a43b0493af8d6873472dfb4b4b8cbb27786eb651/ruff-0.12.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:916fc5defee32dbc1fc1650b576a8fed68f5e8256e2180d4d9855aea43d6aab2", size = 11764513 }, + { url = "https://files.pythonhosted.org/packages/7a/a1/1471751e2015a81fd8e166cd311456c11df74c7e8769d4aabfbc7584c7ac/ruff-0.12.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c984f07d7adb42d3ded5be894fb4007f30f82c87559438b4879fe7aa08c62b39", size = 12745154 }, + { url = "https://files.pythonhosted.org/packages/68/ab/2542b14890d0f4872dd81b7b2a6aed3ac1786fae1ce9b17e11e6df9e31e3/ruff-0.12.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e07fbb89f2e9249f219d88331c833860489b49cdf4b032b8e4432e9b13e8a4b9", size = 13227653 }, + { url = "https://files.pythonhosted.org/packages/22/16/2fbfc61047dbfd009c58a28369a693a1484ad15441723be1cd7fe69bb679/ruff-0.12.11-py3-none-win32.whl", hash = "sha256:c792e8f597c9c756e9bcd4d87cf407a00b60af77078c96f7b6366ea2ce9ba9d3", size = 11944270 }, + { url = "https://files.pythonhosted.org/packages/08/a5/34276984705bfe069cd383101c45077ee029c3fe3b28225bf67aa35f0647/ruff-0.12.11-py3-none-win_amd64.whl", hash = "sha256:a3283325960307915b6deb3576b96919ee89432ebd9c48771ca12ee8afe4a0fd", size = 13046600 }, + { url = "https://files.pythonhosted.org/packages/84/a8/001d4a7c2b37623a3fd7463208267fb906df40ff31db496157549cfd6e72/ruff-0.12.11-py3-none-win_arm64.whl", hash = "sha256:bae4d6e6a2676f8fb0f98b74594a048bae1b944aab17e9f5d504062303c6dbea", size = 12135290 }, ] [[package]] diff --git a/{{cookiecutter.project_slug}}/.github/workflows/ci.yml b/{{cookiecutter.project_slug}}/.github/workflows/ci.yml index cc762a830..1e2d96488 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/ci.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/ci.yml @@ -7,11 +7,11 @@ env: on: pull_request: - branches: ['master', 'main'] + branches: ['main'] paths-ignore: ['docs/**'] push: - branches: ['master', 'main'] + branches: ['main'] paths-ignore: ['docs/**'] concurrency: @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Code Repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Set up Python uses: actions/setup-python@v5 @@ -65,7 +65,7 @@ jobs: steps: - name: Checkout Code Repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 {%- if cookiecutter.use_docker == 'y' %} - name: Set up Docker Buildx diff --git a/{{cookiecutter.project_slug}}/.pre-commit-config.yaml b/{{cookiecutter.project_slug}}/.pre-commit-config.yaml index b3d31de6d..9f23edfa7 100644 --- a/{{cookiecutter.project_slug}}/.pre-commit-config.yaml +++ b/{{cookiecutter.project_slug}}/.pre-commit-config.yaml @@ -7,7 +7,7 @@ default_language_version: repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -33,14 +33,14 @@ repos: exclude: '{{cookiecutter.project_slug}}/templates/' - repo: https://github.com/adamchainz/django-upgrade - rev: '1.25.0' + rev: '1.27.0' hooks: - id: django-upgrade args: ['--target-version', '5.0'] # Run the Ruff linter. - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.1 + rev: v0.12.11 hooks: # Linter - id: ruff-check diff --git a/{{cookiecutter.project_slug}}/compose/local/node/Dockerfile b/{{cookiecutter.project_slug}}/compose/local/node/Dockerfile index 990652a3c..8a8ee7f8a 100644 --- a/{{cookiecutter.project_slug}}/compose/local/node/Dockerfile +++ b/{{cookiecutter.project_slug}}/compose/local/node/Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/node:22.14-bookworm-slim +FROM docker.io/node:24.7-bookworm-slim WORKDIR /app diff --git a/{{cookiecutter.project_slug}}/compose/production/aws/Dockerfile b/{{cookiecutter.project_slug}}/compose/production/aws/Dockerfile index db5fbda66..6cba899a2 100644 --- a/{{cookiecutter.project_slug}}/compose/production/aws/Dockerfile +++ b/{{cookiecutter.project_slug}}/compose/production/aws/Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/amazon/aws-cli:2.27.12 +FROM docker.io/amazon/aws-cli:2.28.0 # Clear entrypoint from the base image, otherwise it's always calling the aws CLI ENTRYPOINT [] diff --git a/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile b/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile index 58f77b1de..a74698c62 100644 --- a/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile +++ b/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile @@ -1,5 +1,5 @@ {% if cookiecutter.frontend_pipeline in ['Gulp', 'Webpack'] -%} -FROM docker.io/node:22.14-bookworm-slim AS client-builder +FROM docker.io/node:24.7-bookworm-slim AS client-builder ARG APP_HOME=/app WORKDIR ${APP_HOME} diff --git a/{{cookiecutter.project_slug}}/compose/production/traefik/Dockerfile b/{{cookiecutter.project_slug}}/compose/production/traefik/Dockerfile index eddb4941d..2a83e94bf 100644 --- a/{{cookiecutter.project_slug}}/compose/production/traefik/Dockerfile +++ b/{{cookiecutter.project_slug}}/compose/production/traefik/Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/traefik:3.4.3 +FROM docker.io/traefik:3.5.0 RUN mkdir -p /etc/traefik/acme \ && touch /etc/traefik/acme/acme.json \ && chmod 600 /etc/traefik/acme/acme.json diff --git a/{{cookiecutter.project_slug}}/docs/howto.rst b/{{cookiecutter.project_slug}}/docs/howto.rst index 944c2b731..721a1b446 100644 --- a/{{cookiecutter.project_slug}}/docs/howto.rst +++ b/{{cookiecutter.project_slug}}/docs/howto.rst @@ -15,7 +15,7 @@ from inside the `{{cookiecutter.project_slug}}/docs` directory. {% else %} To build and serve docs, use the commands:: - docker compose -f docker-compose.local.yml up docs + docker compose -f docker-compose.docs.yml up {% endif %} diff --git a/{{cookiecutter.project_slug}}/gulpfile.mjs b/{{cookiecutter.project_slug}}/gulpfile.mjs index 70d4e5e2f..41f02b78e 100644 --- a/{{cookiecutter.project_slug}}/gulpfile.mjs +++ b/{{cookiecutter.project_slug}}/gulpfile.mjs @@ -101,7 +101,7 @@ function vendorScripts() { // Image compression async function imgCompression() { const imagemin = (await import("gulp-imagemin")).default; - return src(`${paths.images}/*`) + return src(`${paths.images}/*`, { encoding: false }) .pipe(imagemin()) // Compresses PNG, JPEG, GIF and SVG images .pipe(dest(paths.images)); } diff --git a/{{cookiecutter.project_slug}}/package.json b/{{cookiecutter.project_slug}}/package.json index d0458179b..0cc93797d 100644 --- a/{{cookiecutter.project_slug}}/package.json +++ b/{{cookiecutter.project_slug}}/package.json @@ -35,7 +35,7 @@ "webpack-merge": "^6.0.1" }, "engines": { - "node": "22.14" + "node": "24.7" }, "browserslist": [ "last 2 versions" diff --git a/{{cookiecutter.project_slug}}/requirements/base.txt b/{{cookiecutter.project_slug}}/requirements/base.txt index 3d3b97276..900d5c0e5 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -11,7 +11,7 @@ argon2-cffi==25.1.0 # https://github.com/hynek/argon2_cffi {%- if cookiecutter.use_whitenoise == 'y' %} whitenoise==6.9.0 # https://github.com/evansd/whitenoise {%- endif %} -redis==6.2.0 # https://github.com/redis/redis-py +redis==6.4.0 # https://github.com/redis/redis-py {%- if cookiecutter.use_docker == "y" or cookiecutter.windows == "n" %} hiredis==3.2.1 # https://github.com/redis/hiredis-py {%- endif %} @@ -32,7 +32,7 @@ uvicorn-worker==0.3.0 # https://github.com/Kludex/uvicorn-worker django==5.1.11 # pyup: < 5.2 # https://www.djangoproject.com/ django-environ==0.12.0 # https://github.com/joke2k/django-environ django-model-utils==5.0.0 # https://github.com/jazzband/django-model-utils -django-allauth[mfa]==65.9.0 # https://github.com/pennersr/django-allauth +django-allauth[mfa]==65.11.1 # https://github.com/pennersr/django-allauth django-crispy-forms==2.4 # https://github.com/django-crispy-forms/django-crispy-forms crispy-bootstrap5==2025.6 # https://github.com/django-crispy-forms/crispy-bootstrap5 {%- if cookiecutter.frontend_pipeline == 'Django Compressor' %} @@ -41,7 +41,7 @@ django-compressor==4.5.1 # https://github.com/django-compressor/django-compress django-redis==6.0.0 # https://github.com/jazzband/django-redis {%- if cookiecutter.use_drf == 'y' %} # Django REST Framework -djangorestframework==3.16.0 # https://github.com/encode/django-rest-framework +djangorestframework==3.16.1 # https://github.com/encode/django-rest-framework django-cors-headers==4.7.0 # https://github.com/adamchainz/django-cors-headers # DRF-spectacular for api documentation drf-spectacular==0.28.0 # https://github.com/tfranzel/drf-spectacular diff --git a/{{cookiecutter.project_slug}}/requirements/local.txt b/{{cookiecutter.project_slug}}/requirements/local.txt index a2caf9ee6..57f683961 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -13,10 +13,10 @@ watchfiles==1.1.0 # https://github.com/samuelcolvin/watchfiles # Testing # ------------------------------------------------------------------------------ -mypy==1.15.0 # https://github.com/python/mypy -django-stubs[compatible-mypy]==5.2.1 # https://github.com/typeddjango/django-stubs +mypy==1.17.1 # https://github.com/python/mypy +django-stubs[compatible-mypy]==5.2.2 # https://github.com/typeddjango/django-stubs pytest==8.4.1 # https://github.com/pytest-dev/pytest -pytest-sugar==1.0.0 # https://github.com/Teemu/pytest-sugar +pytest-sugar==1.1.1 # https://github.com/Teemu/pytest-sugar {%- if cookiecutter.use_drf == "y" %} djangorestframework-stubs==3.16.0 # https://github.com/typeddjango/djangorestframework-stubs {%- endif %} @@ -24,21 +24,21 @@ djangorestframework-stubs==3.16.0 # https://github.com/typeddjango/djangorestfr # Documentation # ------------------------------------------------------------------------------ sphinx==8.2.3 # pyup: != 8.3.0 # https://github.com/sphinx-doc/sphinx -sphinx-autobuild==2024.10.3 # https://github.com/GaretJax/sphinx-autobuild -sphinx-rtd-theme==3.0.1 # https://pypi.org/project/sphinx-rtd-theme/ +sphinx-autobuild==2025.8.25 # https://github.com/GaretJax/sphinx-autobuild +sphinx-rtd-theme==3.0.2 # https://pypi.org/project/sphinx-rtd-theme/ # Code quality # ------------------------------------------------------------------------------ -ruff==0.12.1 # https://github.com/astral-sh/ruff -coverage==7.9.1 # https://github.com/nedbat/coveragepy +ruff==0.12.11 # https://github.com/astral-sh/ruff +coverage==7.10.6 # https://github.com/nedbat/coveragepy djlint==1.36.4 # https://github.com/Riverside-Healthcare/djLint -pre-commit==4.2.0 # https://github.com/pre-commit/pre-commit +pre-commit==4.3.0 # https://github.com/pre-commit/pre-commit # Django # ------------------------------------------------------------------------------ factory-boy==3.3.2 # https://github.com/FactoryBoy/factory_boy -django-debug-toolbar==5.2.0 # https://github.com/jazzband/django-debug-toolbar +django-debug-toolbar==6.0.0 # https://github.com/jazzband/django-debug-toolbar django-extensions==4.1 # https://github.com/django-extensions/django-extensions django-coverage-plugin==3.1.1 # https://github.com/nedbat/django_coverage_plugin pytest-django==4.11.1 # https://github.com/pytest-dev/pytest-django diff --git a/{{cookiecutter.project_slug}}/requirements/production.txt b/{{cookiecutter.project_slug}}/requirements/production.txt index 0f17445e7..78a5d17fd 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -5,10 +5,10 @@ gunicorn==23.0.0 # https://github.com/benoitc/gunicorn psycopg[c]==3.2.9 # https://github.com/psycopg/psycopg {%- if cookiecutter.use_whitenoise == 'n'and cookiecutter.cloud_provider in ('AWS', 'GCP') %} -Collectfasta==3.3.0 # https://github.com/jasongi/collectfasta +Collectfasta==3.3.1 # https://github.com/jasongi/collectfasta {%- endif %} {%- if cookiecutter.use_sentry == "y" %} -sentry-sdk==2.32.0 # https://github.com/getsentry/sentry-python +sentry-sdk==2.35.1 # https://github.com/getsentry/sentry-python {%- endif %} {%- if cookiecutter.use_docker == "n" and cookiecutter.windows == "y" %} hiredis==3.2.1 # https://github.com/redis/hiredis-py @@ -24,21 +24,21 @@ django-storages[google]==1.14.6 # https://github.com/jschneier/django-storages django-storages[azure]==1.14.6 # https://github.com/jschneier/django-storages {%- endif %} {%- if cookiecutter.mail_service == 'Mailgun' %} -django-anymail[mailgun]==13.0 # https://github.com/anymail/django-anymail +django-anymail[mailgun]==13.0.1 # https://github.com/anymail/django-anymail {%- elif cookiecutter.mail_service == 'Amazon SES' %} -django-anymail[amazon-ses]==13.0 # https://github.com/anymail/django-anymail +django-anymail[amazon-ses]==13.0.1 # https://github.com/anymail/django-anymail {%- elif cookiecutter.mail_service == 'Mailjet' %} -django-anymail[mailjet]==13.0 # https://github.com/anymail/django-anymail +django-anymail[mailjet]==13.0.1 # https://github.com/anymail/django-anymail {%- elif cookiecutter.mail_service == 'Mandrill' %} -django-anymail[mandrill]==13.0 # https://github.com/anymail/django-anymail +django-anymail[mandrill]==13.0.1 # https://github.com/anymail/django-anymail {%- elif cookiecutter.mail_service == 'Postmark' %} -django-anymail[postmark]==13.0 # https://github.com/anymail/django-anymail +django-anymail[postmark]==13.0.1 # https://github.com/anymail/django-anymail {%- elif cookiecutter.mail_service == 'Sendgrid' %} -django-anymail[sendgrid]==13.0 # https://github.com/anymail/django-anymail +django-anymail[sendgrid]==13.0.1 # https://github.com/anymail/django-anymail {%- elif cookiecutter.mail_service == 'Brevo' %} -django-anymail[brevo]==13.0 # https://github.com/anymail/django-anymail +django-anymail[brevo]==13.0.1 # https://github.com/anymail/django-anymail {%- elif cookiecutter.mail_service == 'SparkPost' %} -django-anymail[sparkpost]==13.0 # https://github.com/anymail/django-anymail +django-anymail[sparkpost]==13.0.1 # https://github.com/anymail/django-anymail {%- elif cookiecutter.mail_service == 'Other SMTP' %} -django-anymail==13.0 # https://github.com/anymail/django-anymail +django-anymail==13.0.1 # https://github.com/anymail/django-anymail {%- endif %}