Merge branch 'cookiecutter-master'

# Conflicts:
#	{{cookiecutter.project_slug}}/requirements/local.txt
This commit is contained in:
Alejandro Franco 2025-09-01 18:41:48 -06:00
commit 8b2c1634e7
39 changed files with 554 additions and 186 deletions

View File

@ -1,4 +0,0 @@
[flake8]
exclude = docs
max-line-length = 119
extend-ignore = E203

View File

@ -13,7 +13,6 @@ labels: bug
<!-- To assist you best, please include commands that you've run, options you've selected and any relevant logs -->
- Host system configuration:
- Version of cookiecutter CLI (get it with `cookiecutter --version`):
- OS name and version:

View File

@ -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": ""
}
]

View File

@ -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 }}

View File

@ -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 }}

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -3,6 +3,280 @@ All enhancements and patches to Cookiecutter Django will be documented in this f
<!-- GENERATOR_PLACEHOLDER -->
## 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

View File

@ -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

View File

@ -768,6 +768,13 @@ Listed in alphabetical order.
</td>
<td></td>
</tr>
<tr>
<td>DevForsure</td>
<td>
<a href="https://github.com/DevForsure">DevForsure</a>
</td>
<td></td>
</tr>
<tr>
<td>Diane Chen</td>
<td>
@ -1265,6 +1272,13 @@ Listed in alphabetical order.
</td>
<td>afrowave</td>
</tr>
<tr>
<td>jlitrell</td>
<td>
<a href="https://github.com/jlitrell">jlitrell</a>
</td>
<td></td>
</tr>
<tr>
<td>John</td>
<td>
@ -1510,6 +1524,13 @@ Listed in alphabetical order.
</td>
<td></td>
</tr>
<tr>
<td>Lucas Klasa</td>
<td>
<a href="https://github.com/lucaskbr">lucaskbr</a>
</td>
<td></td>
</tr>
<tr>
<td>Luis Nell</td>
<td>
@ -1594,6 +1615,13 @@ Listed in alphabetical order.
</td>
<td></td>
</tr>
<tr>
<td>Martín Blech</td>
<td>
<a href="https://github.com/martinblech">martinblech</a>
</td>
<td></td>
</tr>
<tr>
<td>masavini</td>
<td>
@ -2336,6 +2364,13 @@ Listed in alphabetical order.
</td>
<td></td>
</tr>
<tr>
<td>Vincent Leduc</td>
<td>
<a href="https://github.com/leducvin">leducvin</a>
</td>
<td></td>
</tr>
<tr>
<td>Vitaly Babiy</td>
<td>

View File

@ -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?

View File

@ -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)

View File

@ -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.

0
hooks/__init__.py Normal file
View File

View File

@ -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":

View File

@ -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."

View File

@ -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

View File

@ -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:

View File

@ -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(
# 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}",
)
PRE_COMMIT_CONFIG.write_text(new_content)
config_file.write_text(new_content)
if __name__ == "__main__":

View File

@ -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)

View File

@ -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(

View File

@ -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

43
uv.lock
View File

@ -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]]

View File

@ -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

View File

@ -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

View File

@ -1,4 +1,4 @@
FROM docker.io/node:22.14-bookworm-slim
FROM docker.io/node:24.7-bookworm-slim
WORKDIR /app

View File

@ -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 []

View File

@ -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}

View File

@ -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

View File

@ -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 %}

View File

@ -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));
}

View File

@ -35,7 +35,7 @@
"webpack-merge": "^6.0.1"
},
"engines": {
"node": "22.14"
"node": "24.7"
},
"browserslist": [
"last 2 versions"

View File

@ -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

View File

@ -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

View File

@ -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 %}