mirror of
https://github.com/cookiecutter/cookiecutter-django.git
synced 2024-11-25 19:14:03 +03:00
Merge branch 'master' into drf-option-with-tests
# Conflicts: # hooks/post_gen_project.py
This commit is contained in:
commit
949d8b684c
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
patreon: danielroygreenfeld
|
||||||
|
open_collective: # Replace with a single Open Collective username
|
||||||
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
otechie: # Replace with a single Otechie username
|
||||||
|
custom: ['https://www.patreon.com/browniebroke']
|
|
@ -5,7 +5,7 @@ services:
|
||||||
|
|
||||||
language: python
|
language: python
|
||||||
|
|
||||||
python: 3.6
|
python: 3.7
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- docker-compose -v
|
- docker-compose -v
|
||||||
|
@ -14,7 +14,7 @@ before_install:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- name: Test results
|
- name: Test results
|
||||||
script: tox -e py36
|
script: tox -e py37
|
||||||
- name: Run flake8 on result
|
- name: Run flake8 on result
|
||||||
script: tox -e flake8
|
script: tox -e flake8
|
||||||
- name: Run black on result
|
- name: Run black on result
|
||||||
|
|
25
CHANGELOG.md
25
CHANGELOG.md
|
@ -2,6 +2,31 @@
|
||||||
All enhancements and patches to Cookiecutter Django will be documented in this file.
|
All enhancements and patches to Cookiecutter Django will be documented in this file.
|
||||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## [2020-01-12]
|
||||||
|
### Changed
|
||||||
|
- Fix mypy setup and added django-stubs
|
||||||
|
- Add Gitlab CI as option
|
||||||
|
|
||||||
|
## [2020-01-11]
|
||||||
|
### Changed
|
||||||
|
- Speed up & reduce size for production Django image
|
||||||
|
- Bumped runtime version for Heroku
|
||||||
|
- Added Debian 10 (Buster) OS dependencies
|
||||||
|
- Update Traefik to v2
|
||||||
|
- Switched Docker images from Alpine based to Debian based
|
||||||
|
|
||||||
|
## [2019-10-06]
|
||||||
|
### Changed
|
||||||
|
- Default Python version is now 3.7 (@nicolas471)
|
||||||
|
|
||||||
|
## [2019-10-04]
|
||||||
|
### Fixed
|
||||||
|
- Fix static files handling on GCP (@caioariede)
|
||||||
|
|
||||||
|
## [2019-10-03]
|
||||||
|
### Fixed
|
||||||
|
- Fix incompatible combination between Whitenoise and no cloud provider (@caioariede)
|
||||||
|
|
||||||
## [2019-07-09]
|
## [2019-07-09]
|
||||||
### Fixed
|
### Fixed
|
||||||
- Always use test settings in pytest (@danihodovic)
|
- Always use test settings in pytest (@danihodovic)
|
||||||
|
|
|
@ -39,9 +39,9 @@ To run all tests using various versions of python in virtualenvs defined in tox.
|
||||||
It is possible to test with a specific version of python. To do this, the command
|
It is possible to test with a specific version of python. To do this, the command
|
||||||
is::
|
is::
|
||||||
|
|
||||||
$ tox -e py36
|
$ tox -e py37
|
||||||
|
|
||||||
This will run py.test with the python3.6 interpreter, for example.
|
This will run py.test with the python3.7 interpreter, for example.
|
||||||
|
|
||||||
To run a particular test with tox for against your current Python version::
|
To run a particular test with tox for against your current Python version::
|
||||||
|
|
||||||
|
|
|
@ -71,9 +71,12 @@ Listed in alphabetical order.
|
||||||
Benjamin Abel
|
Benjamin Abel
|
||||||
Bert de Miranda `@bertdemiranda`_
|
Bert de Miranda `@bertdemiranda`_
|
||||||
Bo Lopker `@blopker`_
|
Bo Lopker `@blopker`_
|
||||||
|
Bo Peng `@BoPeng`_
|
||||||
Bouke Haarsma
|
Bouke Haarsma
|
||||||
Brent Payne `@brentpayne`_ @brentpayne
|
Brent Payne `@brentpayne`_ @brentpayne
|
||||||
|
Bruce Olivier `@bolivierjr`_
|
||||||
Burhan Khalid `@burhan`_ @burhan
|
Burhan Khalid `@burhan`_ @burhan
|
||||||
|
Caio Ariede `@caioariede`_ @caioariede
|
||||||
Carl Johnson `@carlmjohnson`_ @carlmjohnson
|
Carl Johnson `@carlmjohnson`_ @carlmjohnson
|
||||||
Catherine Devlin `@catherinedevlin`_
|
Catherine Devlin `@catherinedevlin`_
|
||||||
Cédric Gaspoz `@cgaspoz`_
|
Cédric Gaspoz `@cgaspoz`_
|
||||||
|
@ -92,6 +95,7 @@ Listed in alphabetical order.
|
||||||
Dan Shultz `@shultz`_
|
Dan Shultz `@shultz`_
|
||||||
Dani Hodovic `@danihodovic`_
|
Dani Hodovic `@danihodovic`_
|
||||||
Daniel Hepper `@dhepper`_ @danielhepper
|
Daniel Hepper `@dhepper`_ @danielhepper
|
||||||
|
Daniel Hillier `@danifus`_
|
||||||
Daniele Tricoli `@eriol`_
|
Daniele Tricoli `@eriol`_
|
||||||
David Díaz `@ddiazpinto`_ @DavidDiazPinto
|
David Díaz `@ddiazpinto`_ @DavidDiazPinto
|
||||||
Davit Tovmasyan `@davitovmasyan`_
|
Davit Tovmasyan `@davitovmasyan`_
|
||||||
|
@ -100,6 +104,7 @@ Listed in alphabetical order.
|
||||||
Demetris Stavrou `@demestav`_
|
Demetris Stavrou `@demestav`_
|
||||||
Denis Bobrov `@delneg`_
|
Denis Bobrov `@delneg`_
|
||||||
Denis Orehovsky `@apirobot`_
|
Denis Orehovsky `@apirobot`_
|
||||||
|
Denis Savran `@blaxpy`_
|
||||||
Diane Chen `@purplediane`_ @purplediane88
|
Diane Chen `@purplediane`_ @purplediane88
|
||||||
Dónal Adams `@epileptic-fish`_
|
Dónal Adams `@epileptic-fish`_
|
||||||
Dong Huynh `@trungdong`_
|
Dong Huynh `@trungdong`_
|
||||||
|
@ -111,13 +116,17 @@ Listed in alphabetical order.
|
||||||
Florian Idelberger `@step21`_ @windrush
|
Florian Idelberger `@step21`_ @windrush
|
||||||
Garry Cairns `@garry-cairns`_
|
Garry Cairns `@garry-cairns`_
|
||||||
Garry Polley `@garrypolley`_
|
Garry Polley `@garrypolley`_
|
||||||
|
Gilbishkosma `@Gilbishkosma`_
|
||||||
Hamish Durkin `@durkode`_
|
Hamish Durkin `@durkode`_
|
||||||
Hana Quadara `@hanaquadara`_
|
Hana Quadara `@hanaquadara`_
|
||||||
|
Harry Moreno `@morenoh149`_ @morenoh149
|
||||||
Harry Percival `@hjwp`_
|
Harry Percival `@hjwp`_
|
||||||
Hendrik Schneider `@hendrikschneider`_
|
Hendrik Schneider `@hendrikschneider`_
|
||||||
Henrique G. G. Pereira `@ikkebr`_
|
Henrique G. G. Pereira `@ikkebr`_
|
||||||
Ian Lee `@IanLee1521`_
|
Ian Lee `@IanLee1521`_
|
||||||
Irfan Ahmad `@erfaan`_ @erfaan
|
Irfan Ahmad `@erfaan`_ @erfaan
|
||||||
|
Isaac12x `@Isaac12x`_
|
||||||
|
Ivan Khomutov `@ikhomutov`_
|
||||||
Jan Van Bruggen `@jvanbrug`_
|
Jan Van Bruggen `@jvanbrug`_
|
||||||
Jelmer Draaijer `@foarsitter`_
|
Jelmer Draaijer `@foarsitter`_
|
||||||
Jerome Caisip `@jeromecaisip`_
|
Jerome Caisip `@jeromecaisip`_
|
||||||
|
@ -137,6 +146,7 @@ Listed in alphabetical order.
|
||||||
Keyvan Mosharraf `@keyvanm`_
|
Keyvan Mosharraf `@keyvanm`_
|
||||||
Krzysztof Szumny `@noisy`_
|
Krzysztof Szumny `@noisy`_
|
||||||
Krzysztof Żuraw `@krzysztofzuraw`_
|
Krzysztof Żuraw `@krzysztofzuraw`_
|
||||||
|
Leo won `@leollon`_
|
||||||
Leo Zhou `@glasslion`_
|
Leo Zhou `@glasslion`_
|
||||||
Leonardo Jimenez `@xpostudio4`_
|
Leonardo Jimenez `@xpostudio4`_
|
||||||
Lin Xianyi `@iynaix`_
|
Lin Xianyi `@iynaix`_
|
||||||
|
@ -159,6 +169,7 @@ Listed in alphabetical order.
|
||||||
Michael Gecht `@mimischi`_ @_mischi
|
Michael Gecht `@mimischi`_ @_mischi
|
||||||
Min ho Kim `@minho42`_
|
Min ho Kim `@minho42`_
|
||||||
mozillazg `@mozillazg`_
|
mozillazg `@mozillazg`_
|
||||||
|
Nico Stefani `@nicolas471`_ @moby_dick91
|
||||||
Oleg Russkin `@rolep`_
|
Oleg Russkin `@rolep`_
|
||||||
Pablo `@oubiga`_
|
Pablo `@oubiga`_
|
||||||
Parbhat Puri `@parbhat`_
|
Parbhat Puri `@parbhat`_
|
||||||
|
@ -199,6 +210,7 @@ Listed in alphabetical order.
|
||||||
William Archinal `@archinal`_
|
William Archinal `@archinal`_
|
||||||
Xaver Y.R. Chen `@yrchen`_ @yrchen
|
Xaver Y.R. Chen `@yrchen`_ @yrchen
|
||||||
Yaroslav Halchenko
|
Yaroslav Halchenko
|
||||||
|
Yuchen Xie `@mapx`_
|
||||||
========================== ============================ ==============
|
========================== ============================ ==============
|
||||||
|
|
||||||
.. _@a7p: https://github.com/a7p
|
.. _@a7p: https://github.com/a7p
|
||||||
|
@ -220,9 +232,12 @@ Listed in alphabetical order.
|
||||||
.. _@arruda: https://github.com/arruda
|
.. _@arruda: https://github.com/arruda
|
||||||
.. _@bertdemiranda: https://github.com/bertdemiranda
|
.. _@bertdemiranda: https://github.com/bertdemiranda
|
||||||
.. _@bittner: https://github.com/bittner
|
.. _@bittner: https://github.com/bittner
|
||||||
|
.. _@blaxpy: https://github.com/blaxpy
|
||||||
.. _@bloodpet: https://github.com/bloodpet
|
.. _@bloodpet: https://github.com/bloodpet
|
||||||
.. _@blopker: https://github.com/blopker
|
.. _@blopker: https://github.com/blopker
|
||||||
.. _@bogdal: https://github.com/bogdal
|
.. _@bogdal: https://github.com/bogdal
|
||||||
|
.. _@bolivierjr: https://github.com/bolivierjr
|
||||||
|
.. _@BoPeng: https://github.com/BoPeng
|
||||||
.. _@brentpayne: https://github.com/brentpayne
|
.. _@brentpayne: https://github.com/brentpayne
|
||||||
.. _@btknu: https://github.com/btknu
|
.. _@btknu: https://github.com/btknu
|
||||||
.. _@burhan: https://github.com/burhan
|
.. _@burhan: https://github.com/burhan
|
||||||
|
@ -230,6 +245,7 @@ Listed in alphabetical order.
|
||||||
.. _@c-rhodes: https://github.com/c-rhodes
|
.. _@c-rhodes: https://github.com/c-rhodes
|
||||||
.. _@caffodian: https://github.com/caffodian
|
.. _@caffodian: https://github.com/caffodian
|
||||||
.. _@canonnervio: https://github.com/canonnervio
|
.. _@canonnervio: https://github.com/canonnervio
|
||||||
|
.. _@caioariede: https://github.com/caioariede
|
||||||
.. _@carlmjohnson: https://github.com/carlmjohnson
|
.. _@carlmjohnson: https://github.com/carlmjohnson
|
||||||
.. _@catherinedevlin: https://github.com/catherinedevlin
|
.. _@catherinedevlin: https://github.com/catherinedevlin
|
||||||
.. _@ccurvey: https://github.com/ccurvey
|
.. _@ccurvey: https://github.com/ccurvey
|
||||||
|
@ -244,6 +260,7 @@ Listed in alphabetical order.
|
||||||
.. _@curtisstpierre: https://github.com/curtisstpierre
|
.. _@curtisstpierre: https://github.com/curtisstpierre
|
||||||
.. _@dadokkio: https://github.com/dadokkio
|
.. _@dadokkio: https://github.com/dadokkio
|
||||||
.. _@danihodovic: https://github.com/danihodovic
|
.. _@danihodovic: https://github.com/danihodovic
|
||||||
|
.. _@danifus: https://github.com/danifus
|
||||||
.. _@davitovmasyan: https://github.com/davitovmasyan
|
.. _@davitovmasyan: https://github.com/davitovmasyan
|
||||||
.. _@ddiazpinto: https://github.com/ddiazpinto
|
.. _@ddiazpinto: https://github.com/ddiazpinto
|
||||||
.. _@delneg: https://github.com/delneg
|
.. _@delneg: https://github.com/delneg
|
||||||
|
@ -264,6 +281,7 @@ Listed in alphabetical order.
|
||||||
.. _@foarsitter: https://github.com/foarsitter
|
.. _@foarsitter: https://github.com/foarsitter
|
||||||
.. _@garry-cairns: https://github.com/garry-cairns
|
.. _@garry-cairns: https://github.com/garry-cairns
|
||||||
.. _@garrypolley: https://github.com/garrypolley
|
.. _@garrypolley: https://github.com/garrypolley
|
||||||
|
.. _@Gilbishkosma: https://github.com/Gilbishkosma
|
||||||
.. _@glasslion: https://github.com/glasslion
|
.. _@glasslion: https://github.com/glasslion
|
||||||
.. _@goldhand: https://github.com/goldhand
|
.. _@goldhand: https://github.com/goldhand
|
||||||
.. _@hackebrot: https://github.com/hackebrot
|
.. _@hackebrot: https://github.com/hackebrot
|
||||||
|
@ -272,7 +290,9 @@ Listed in alphabetical order.
|
||||||
.. _@hendrikschneider: https://github.com/hendrikschneider
|
.. _@hendrikschneider: https://github.com/hendrikschneider
|
||||||
.. _@hjwp: https://github.com/hjwp
|
.. _@hjwp: https://github.com/hjwp
|
||||||
.. _@IanLee1521: https://github.com/IanLee1521
|
.. _@IanLee1521: https://github.com/IanLee1521
|
||||||
|
.. _@ikhomutov: https://github.com/ikhomutov
|
||||||
.. _@ikkebr: https://github.com/ikkebr
|
.. _@ikkebr: https://github.com/ikkebr
|
||||||
|
.. _@Isaac12x: https://github.com/Isaac12x
|
||||||
.. _@iynaix: https://github.com/iynaix
|
.. _@iynaix: https://github.com/iynaix
|
||||||
.. _@jangeador: https://github.com/jangeador
|
.. _@jangeador: https://github.com/jangeador
|
||||||
.. _@jazztpt: https://github.com/jazztpt
|
.. _@jazztpt: https://github.com/jazztpt
|
||||||
|
@ -289,7 +309,9 @@ Listed in alphabetical order.
|
||||||
.. _@keyvanm: https://github.com/keyvanm
|
.. _@keyvanm: https://github.com/keyvanm
|
||||||
.. _@knitatoms: https://github.com/knitatoms
|
.. _@knitatoms: https://github.com/knitatoms
|
||||||
.. _@krzysztofzuraw: https://github.com/krzysztofzuraw
|
.. _@krzysztofzuraw: https://github.com/krzysztofzuraw
|
||||||
|
.. _@leollon: https://github.com/leollon
|
||||||
.. _@MathijsHoogland: https://github.com/MathijsHoogland
|
.. _@MathijsHoogland: https://github.com/MathijsHoogland
|
||||||
|
.. _@mapx: https://github.com/mapx
|
||||||
.. _@mattayes: https://github.com/mattayes
|
.. _@mattayes: https://github.com/mattayes
|
||||||
.. _@menzenski: https://github.com/menzenski
|
.. _@menzenski: https://github.com/menzenski
|
||||||
.. _@mfwarren: https://github.com/mfwarren
|
.. _@mfwarren: https://github.com/mfwarren
|
||||||
|
@ -298,11 +320,13 @@ Listed in alphabetical order.
|
||||||
.. _@minho42: https://github.com/minho42
|
.. _@minho42: https://github.com/minho42
|
||||||
.. _@mjsisley: https://github.com/mjsisley
|
.. _@mjsisley: https://github.com/mjsisley
|
||||||
.. _@mknapper1: https://github.com/mknapper1
|
.. _@mknapper1: https://github.com/mknapper1
|
||||||
|
.. _@morenoh149: https://github.com/morenoh149
|
||||||
.. _@mostaszewski: https://github.com/mostaszewski
|
.. _@mostaszewski: https://github.com/mostaszewski
|
||||||
.. _@mozillazg: https://github.com/mozillazg
|
.. _@mozillazg: https://github.com/mozillazg
|
||||||
.. _@mrcoles: https://github.com/mrcoles
|
.. _@mrcoles: https://github.com/mrcoles
|
||||||
.. _@msaizar: https://github.com/msaizar
|
.. _@msaizar: https://github.com/msaizar
|
||||||
.. _@myilmaz: https://github.com/myilmaz
|
.. _@myilmaz: https://github.com/myilmaz
|
||||||
|
.. _@nicolas471: https://github.com/nicolas471
|
||||||
.. _@noisy: https://github.com/noisy
|
.. _@noisy: https://github.com/noisy
|
||||||
.. _@originell: https://github.com/originell
|
.. _@originell: https://github.com/originell
|
||||||
.. _@oubiga: https://github.com/oubiga
|
.. _@oubiga: https://github.com/oubiga
|
||||||
|
|
14
README.rst
14
README.rst
|
@ -9,8 +9,8 @@ Cookiecutter Django
|
||||||
:target: https://pyup.io/repos/github/pydanny/cookiecutter-django/
|
:target: https://pyup.io/repos/github/pydanny/cookiecutter-django/
|
||||||
:alt: Updates
|
:alt: Updates
|
||||||
|
|
||||||
.. image:: https://badges.gitter.im/Join Chat.svg
|
.. image:: https://img.shields.io/badge/cookiecutter-Join%20on%20Slack-green?style=flat&logo=slack
|
||||||
:target: https://gitter.im/pydanny/cookiecutter-django?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
:target: https://join.slack.com/t/cookie-cutter/shared_invite/enQtNzI0Mzg5NjE5Nzk5LTRlYWI2YTZhYmQ4YmU1Y2Q2NmE1ZjkwOGM0NDQyNTIwY2M4ZTgyNDVkNjMxMDdhZGI5ZGE5YmJjM2M3ODJlY2U
|
||||||
|
|
||||||
.. image:: https://www.codetriage.com/pydanny/cookiecutter-django/badges/users.svg
|
.. image:: https://www.codetriage.com/pydanny/cookiecutter-django/badges/users.svg
|
||||||
:target: https://www.codetriage.com/pydanny/cookiecutter-django
|
:target: https://www.codetriage.com/pydanny/cookiecutter-django
|
||||||
|
@ -37,7 +37,7 @@ Features
|
||||||
---------
|
---------
|
||||||
|
|
||||||
* For Django 2.2
|
* For Django 2.2
|
||||||
* Works with Python 3.6
|
* Works with Python 3.7
|
||||||
* Renders Django projects with 100% starting test coverage
|
* Renders Django projects with 100% starting test coverage
|
||||||
* Twitter Bootstrap_ v4 (`maintained Foundation fork`_ also available)
|
* Twitter Bootstrap_ v4 (`maintained Foundation fork`_ also available)
|
||||||
* 12-Factor_ based settings via django-environ_
|
* 12-Factor_ based settings via django-environ_
|
||||||
|
@ -53,6 +53,7 @@ Features
|
||||||
* Instructions for deploying to PythonAnywhere_
|
* Instructions for deploying to PythonAnywhere_
|
||||||
* Run tests with unittest or pytest
|
* Run tests with unittest or pytest
|
||||||
* Customizable PostgreSQL version
|
* Customizable PostgreSQL version
|
||||||
|
* Default integration with pre-commit_ for identifying simple issues before submission to code review
|
||||||
|
|
||||||
.. _`maintained Foundation fork`: https://github.com/Parbhat/cookiecutter-django-foundation
|
.. _`maintained Foundation fork`: https://github.com/Parbhat/cookiecutter-django-foundation
|
||||||
|
|
||||||
|
@ -84,6 +85,7 @@ Optional Integrations
|
||||||
.. _PythonAnywhere: https://www.pythonanywhere.com/
|
.. _PythonAnywhere: https://www.pythonanywhere.com/
|
||||||
.. _Traefik: https://traefik.io/
|
.. _Traefik: https://traefik.io/
|
||||||
.. _LetsEncrypt: https://letsencrypt.org/
|
.. _LetsEncrypt: https://letsencrypt.org/
|
||||||
|
.. _pre-commit: https://github.com/pre-commit/pre-commit
|
||||||
|
|
||||||
Constraints
|
Constraints
|
||||||
-----------
|
-----------
|
||||||
|
@ -106,7 +108,7 @@ Projects that provide financial support to the maintainers:
|
||||||
Two Scoops of Django 1.11
|
Two Scoops of Django 1.11
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. image:: https://cdn.shopify.com/s/files/1/0304/6901/products/tsd-111-alpha_medium.jpg?v=1499531513
|
.. image:: https://cdn.shopify.com/s/files/1/0304/6901/products/2017-06-29-tsd11-sticker-02.png
|
||||||
:name: Two Scoops of Django 1.11 Cover
|
:name: Two Scoops of Django 1.11 Cover
|
||||||
:align: center
|
:align: center
|
||||||
:alt: Two Scoops of Django
|
:alt: Two Scoops of Django
|
||||||
|
@ -224,11 +226,11 @@ Community
|
||||||
|
|
||||||
* Have questions? **Before you ask questions anywhere else**, please post your question on `Stack Overflow`_ under the *cookiecutter-django* tag. We check there periodically for questions.
|
* Have questions? **Before you ask questions anywhere else**, please post your question on `Stack Overflow`_ under the *cookiecutter-django* tag. We check there periodically for questions.
|
||||||
* If you think you found a bug or want to request a feature, please open an issue_.
|
* If you think you found a bug or want to request a feature, please open an issue_.
|
||||||
* For anything else, you can chat with us on `Gitter`_.
|
* For anything else, you can chat with us on `Slack`_.
|
||||||
|
|
||||||
.. _`Stack Overflow`: http://stackoverflow.com/questions/tagged/cookiecutter-django
|
.. _`Stack Overflow`: http://stackoverflow.com/questions/tagged/cookiecutter-django
|
||||||
.. _`issue`: https://github.com/pydanny/cookiecutter-django/issues
|
.. _`issue`: https://github.com/pydanny/cookiecutter-django/issues
|
||||||
.. _`Gitter`: https://gitter.im/pydanny/cookiecutter-django?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
.. _`Slack`: https://join.slack.com/t/cookie-cutter/shared_invite/enQtNzI0Mzg5NjE5Nzk5LTRlYWI2YTZhYmQ4YmU1Y2Q2NmE1ZjkwOGM0NDQyNTIwY2M4ZTgyNDVkNjMxMDdhZGI5ZGE5YmJjM2M3ODJlY2U
|
||||||
|
|
||||||
For Readers of Two Scoops of Django
|
For Readers of Two Scoops of Django
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
|
|
@ -41,7 +41,11 @@
|
||||||
"use_sentry": "n",
|
"use_sentry": "n",
|
||||||
"use_whitenoise": "n",
|
"use_whitenoise": "n",
|
||||||
"use_heroku": "n",
|
"use_heroku": "n",
|
||||||
"use_travisci": "n",
|
"ci_tool": [
|
||||||
|
"None",
|
||||||
|
"Travis",
|
||||||
|
"Gitlab"
|
||||||
|
],
|
||||||
"keep_local_envs_in_vcs": "y",
|
"keep_local_envs_in_vcs": "y",
|
||||||
|
|
||||||
"debug": "n"
|
"debug": "n"
|
||||||
|
|
|
@ -35,7 +35,7 @@ Make sure your project is fully committed and pushed up to Bitbucket or Github o
|
||||||
|
|
||||||
git clone <my-repo-url> # you can also use hg
|
git clone <my-repo-url> # you can also use hg
|
||||||
cd my-project-name
|
cd my-project-name
|
||||||
mkvirtualenv --python=/usr/bin/python3.6 my-project-name
|
mkvirtualenv --python=/usr/bin/python3.7 my-project-name
|
||||||
pip install -r requirements/production.txt # may take a few minutes
|
pip install -r requirements/production.txt # may take a few minutes
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -152,6 +152,7 @@ If you are using ``supervisor``, you can use this file as a starting point::
|
||||||
Move it to ``/etc/supervisor/conf.d/{{cookiecutter.project_slug}}.conf`` and run::
|
Move it to ``/etc/supervisor/conf.d/{{cookiecutter.project_slug}}.conf`` and run::
|
||||||
|
|
||||||
supervisorctl reread
|
supervisorctl reread
|
||||||
|
supervisorctl update
|
||||||
supervisorctl start {{cookiecutter.project_slug}}
|
supervisorctl start {{cookiecutter.project_slug}}
|
||||||
|
|
||||||
For status check, run::
|
For status check, run::
|
||||||
|
|
|
@ -9,7 +9,7 @@ Setting Up Development Environment
|
||||||
|
|
||||||
Make sure to have the following on your host:
|
Make sure to have the following on your host:
|
||||||
|
|
||||||
* Python 3.6
|
* Python 3.7
|
||||||
* PostgreSQL_.
|
* PostgreSQL_.
|
||||||
* Redis_, if using Celery
|
* Redis_, if using Celery
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ First things first.
|
||||||
|
|
||||||
#. Create a virtualenv: ::
|
#. Create a virtualenv: ::
|
||||||
|
|
||||||
$ python3.6 -m venv <virtual env path>
|
$ python3.7 -m venv <virtual env path>
|
||||||
|
|
||||||
#. Activate the virtualenv you have just created: ::
|
#. Activate the virtualenv you have just created: ::
|
||||||
|
|
||||||
|
@ -26,6 +26,12 @@ First things first.
|
||||||
#. Install development requirements: ::
|
#. Install development requirements: ::
|
||||||
|
|
||||||
$ pip install -r requirements/local.txt
|
$ pip install -r requirements/local.txt
|
||||||
|
$ pre-commit install
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
the `pre-commit` exists in the generated project as default.
|
||||||
|
for the details of `pre-commit`, follow the [site of pre-commit](https://pre-commit.com/).
|
||||||
|
|
||||||
#. Create a new PostgreSQL database using createdb_: ::
|
#. Create a new PostgreSQL database using createdb_: ::
|
||||||
|
|
||||||
|
|
|
@ -94,8 +94,12 @@ use_heroku:
|
||||||
Indicates whether the project should be configured so as to be deployable
|
Indicates whether the project should be configured so as to be deployable
|
||||||
to Heroku_.
|
to Heroku_.
|
||||||
|
|
||||||
use_travisci:
|
ci_tool:
|
||||||
Indicates whether the project should be configured to use `Travis CI`_.
|
Select a CI tool for running tests. The choices are:
|
||||||
|
|
||||||
|
1. None
|
||||||
|
2. Travis_
|
||||||
|
3. Gitlab_
|
||||||
|
|
||||||
keep_local_envs_in_vcs:
|
keep_local_envs_in_vcs:
|
||||||
Indicates whether the project's ``.envs/.local/`` should be kept in VCS
|
Indicates whether the project's ``.envs/.local/`` should be kept in VCS
|
||||||
|
@ -138,3 +142,6 @@ debug:
|
||||||
.. _Heroku: https://github.com/heroku/heroku-buildpack-python
|
.. _Heroku: https://github.com/heroku/heroku-buildpack-python
|
||||||
|
|
||||||
.. _Travis CI: https://travis-ci.org/
|
.. _Travis CI: https://travis-ci.org/
|
||||||
|
|
||||||
|
.. _GitLab CI: https://docs.gitlab.com/ee/ci/
|
||||||
|
|
||||||
|
|
|
@ -49,8 +49,8 @@ Once the tests are complete, in order to see the code coverage, run the followin
|
||||||
Since this is a fresh install, and there are no tests built using the Python `unittest`_ library yet, you should get feedback that says there were no tests carried out.
|
Since this is a fresh install, and there are no tests built using the Python `unittest`_ library yet, you should get feedback that says there were no tests carried out.
|
||||||
|
|
||||||
.. _Pytest: https://docs.pytest.org/en/latest/example/simple.html
|
.. _Pytest: https://docs.pytest.org/en/latest/example/simple.html
|
||||||
.. _develop locally: ../developing-locally.rst
|
.. _develop locally: ./developing-locally.html
|
||||||
.. _develop locally with docker: ..../developing-locally-docker.rst
|
.. _develop locally with docker: ./developing-locally-docker.html
|
||||||
.. _customize: https://docs.pytest.org/en/latest/customize.html
|
.. _customize: https://docs.pytest.org/en/latest/customize.html
|
||||||
.. _unittest: https://docs.python.org/3/library/unittest.html#module-unittest
|
.. _unittest: https://docs.python.org/3/library/unittest.html#module-unittest
|
||||||
.. _configuring: https://coverage.readthedocs.io/en/v4.5.x/config.html
|
.. _configuring: https://coverage.readthedocs.io/en/v4.5.x/config.html
|
||||||
|
|
|
@ -70,7 +70,7 @@ def remove_heroku_files():
|
||||||
for file_name in file_names:
|
for file_name in file_names:
|
||||||
if (
|
if (
|
||||||
file_name == "requirements.txt"
|
file_name == "requirements.txt"
|
||||||
and "{{ cookiecutter.use_travisci }}".lower() == "y"
|
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 travisci but not using heroku
|
||||||
continue
|
continue
|
||||||
|
@ -105,6 +105,10 @@ def remove_dottravisyml_file():
|
||||||
os.remove(".travis.yml")
|
os.remove(".travis.yml")
|
||||||
|
|
||||||
|
|
||||||
|
def remove_dotgitlabciyml_file():
|
||||||
|
os.remove(".gitlab-ci.yml")
|
||||||
|
|
||||||
|
|
||||||
def append_to_project_gitignore(path):
|
def append_to_project_gitignore(path):
|
||||||
gitignore_file_path = ".gitignore"
|
gitignore_file_path = ".gitignore"
|
||||||
with open(gitignore_file_path, "a") as gitignore_file:
|
with open(gitignore_file_path, "a") as gitignore_file:
|
||||||
|
@ -279,6 +283,10 @@ def remove_node_dockerfile():
|
||||||
shutil.rmtree(os.path.join("compose", "local", "node"))
|
shutil.rmtree(os.path.join("compose", "local", "node"))
|
||||||
|
|
||||||
|
|
||||||
|
def remove_aws_dockerfile():
|
||||||
|
shutil.rmtree(os.path.join("compose", "production", "aws"))
|
||||||
|
|
||||||
|
|
||||||
def remove_drf_starter_files():
|
def remove_drf_starter_files():
|
||||||
os.remove(os.path.join("config", "api_router.py"))
|
os.remove(os.path.join("config", "api_router.py"))
|
||||||
shutil.rmtree(os.path.join("{{cookiecutter.project_slug}}", "users", "api"))
|
shutil.rmtree(os.path.join("{{cookiecutter.project_slug}}", "users", "api"))
|
||||||
|
@ -307,6 +315,12 @@ def main():
|
||||||
else:
|
else:
|
||||||
remove_docker_files()
|
remove_docker_files()
|
||||||
|
|
||||||
|
if (
|
||||||
|
"{{ cookiecutter.use_docker }}".lower() == "y"
|
||||||
|
and "{{ cookiecutter.cloud_provider}}".lower() != "aws"
|
||||||
|
):
|
||||||
|
remove_aws_dockerfile()
|
||||||
|
|
||||||
if "{{ cookiecutter.use_heroku }}".lower() == "n":
|
if "{{ cookiecutter.use_heroku }}".lower() == "n":
|
||||||
remove_heroku_files()
|
remove_heroku_files()
|
||||||
|
|
||||||
|
@ -344,9 +358,12 @@ def main():
|
||||||
if "{{ cookiecutter.use_docker }}".lower() == "y":
|
if "{{ cookiecutter.use_docker }}".lower() == "y":
|
||||||
remove_celery_compose_dirs()
|
remove_celery_compose_dirs()
|
||||||
|
|
||||||
if "{{ cookiecutter.use_travisci }}".lower() == "n":
|
if "{{ cookiecutter.ci_tool }}".lower() != "travis":
|
||||||
remove_dottravisyml_file()
|
remove_dottravisyml_file()
|
||||||
|
|
||||||
|
if "{{ cookiecutter.ci_tool }}".lower() != "gitlab":
|
||||||
|
remove_dotgitlabciyml_file()
|
||||||
|
|
||||||
if "{{ cookiecutter.use_drf }}".lower() == "n":
|
if "{{ cookiecutter.use_drf }}".lower() == "n":
|
||||||
remove_drf_starter_files()
|
remove_drf_starter_files()
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ if "{{ cookiecutter.use_docker }}".lower() == "n":
|
||||||
if python_major_version == 2:
|
if python_major_version == 2:
|
||||||
print(
|
print(
|
||||||
WARNING + "You're running cookiecutter under Python 2, but the generated "
|
WARNING + "You're running cookiecutter under Python 2, but the generated "
|
||||||
"project requires Python 3.6+. Do you want to proceed (y/n)? " + TERMINATOR
|
"project requires Python 3.7+. Do you want to proceed (y/n)? " + TERMINATOR
|
||||||
)
|
)
|
||||||
yes_options, no_options = frozenset(["y"]), frozenset(["n"])
|
yes_options, no_options = frozenset(["y"]), frozenset(["n"])
|
||||||
while True:
|
while True:
|
||||||
|
@ -59,3 +59,12 @@ if "{{ cookiecutter.use_docker }}".lower() == "n":
|
||||||
)
|
)
|
||||||
+ TERMINATOR
|
+ TERMINATOR
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
"{{ cookiecutter.use_whitenoise }}".lower() == "n"
|
||||||
|
and "{{ cookiecutter.cloud_provider }}" == "None"
|
||||||
|
):
|
||||||
|
print(
|
||||||
|
"You should either use Whitenoise or select a Cloud Provider to serve static files"
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
cookiecutter==1.6.0
|
cookiecutter==1.7.0
|
||||||
sh==1.12.14
|
sh==1.12.14
|
||||||
binaryornot==0.4.4
|
binaryornot==0.4.4
|
||||||
|
|
||||||
# Code quality
|
# Code quality
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
black==19.3b0
|
black==19.10b0
|
||||||
flake8==3.7.8
|
flake8==3.7.9
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
tox==3.14.0
|
tox==3.14.3
|
||||||
pytest==5.1.2
|
pytest==5.3.4
|
||||||
pytest_cases==1.11.2
|
pytest_cases==1.12.0
|
||||||
pytest-cookies==0.4.0
|
pytest-cookies==0.4.0
|
||||||
pytest-xdist==1.29.0
|
pytest-xdist==1.31.0
|
||||||
pyyaml==5.1.2
|
pyyaml==5.3
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -40,7 +40,7 @@ setup(
|
||||||
"License :: OSI Approved :: BSD License",
|
"License :: OSI Approved :: BSD License",
|
||||||
"Programming Language :: Python",
|
"Programming Language :: Python",
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3.6",
|
"Programming Language :: Python :: 3.7",
|
||||||
"Programming Language :: Python :: Implementation :: CPython",
|
"Programming Language :: Python :: Implementation :: CPython",
|
||||||
"Topic :: Software Development",
|
"Topic :: Software Development",
|
||||||
],
|
],
|
||||||
|
|
|
@ -11,9 +11,6 @@ from binaryornot.check import is_binary
|
||||||
PATTERN = r"{{(\s?cookiecutter)[.](.*?)}}"
|
PATTERN = r"{{(\s?cookiecutter)[.](.*?)}}"
|
||||||
RE_OBJ = re.compile(PATTERN)
|
RE_OBJ = re.compile(PATTERN)
|
||||||
|
|
||||||
YN_CHOICES = ["y", "n"]
|
|
||||||
CLOUD_CHOICES = ["AWS", "GCE", "None"]
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def context():
|
def context():
|
||||||
|
@ -30,14 +27,24 @@ def context():
|
||||||
|
|
||||||
|
|
||||||
@pytest_fixture_plus
|
@pytest_fixture_plus
|
||||||
@pytest.mark.parametrize("windows", YN_CHOICES, ids=lambda yn: f"win:{yn}")
|
@pytest.mark.parametrize("windows", ["y", "n"], ids=lambda yn: f"win:{yn}")
|
||||||
@pytest.mark.parametrize("use_docker", YN_CHOICES, ids=lambda yn: f"docker:{yn}")
|
@pytest.mark.parametrize("use_docker", ["y", "n"], ids=lambda yn: f"docker:{yn}")
|
||||||
@pytest.mark.parametrize("use_celery", YN_CHOICES, ids=lambda yn: f"celery:{yn}")
|
@pytest.mark.parametrize("use_celery", ["y", "n"], ids=lambda yn: f"celery:{yn}")
|
||||||
@pytest.mark.parametrize("use_mailhog", YN_CHOICES, ids=lambda yn: f"mailhog:{yn}")
|
@pytest.mark.parametrize("use_mailhog", ["y", "n"], ids=lambda yn: f"mailhog:{yn}")
|
||||||
@pytest.mark.parametrize("use_sentry", YN_CHOICES, ids=lambda yn: f"sentry:{yn}")
|
@pytest.mark.parametrize("use_sentry", ["y", "n"], ids=lambda yn: f"sentry:{yn}")
|
||||||
@pytest.mark.parametrize("use_compressor", YN_CHOICES, ids=lambda yn: f"cmpr:{yn}")
|
@pytest.mark.parametrize("use_compressor", ["y", "n"], ids=lambda yn: f"cmpr:{yn}")
|
||||||
@pytest.mark.parametrize("use_whitenoise", YN_CHOICES, ids=lambda yn: f"wnoise:{yn}")
|
@pytest.mark.parametrize(
|
||||||
@pytest.mark.parametrize("cloud_provider", CLOUD_CHOICES, ids=lambda yn: f"cloud:{yn}")
|
"use_whitenoise,cloud_provider",
|
||||||
|
[
|
||||||
|
("y", "AWS"),
|
||||||
|
("y", "GCP"),
|
||||||
|
("y", "None"),
|
||||||
|
("n", "AWS"),
|
||||||
|
("n", "GCP"),
|
||||||
|
# no whitenoise + co cloud provider is not supported
|
||||||
|
],
|
||||||
|
ids=lambda id: f"wnoise:{id[0]}-cloud:{id[1]}",
|
||||||
|
)
|
||||||
def context_combination(
|
def context_combination(
|
||||||
windows,
|
windows,
|
||||||
use_docker,
|
use_docker,
|
||||||
|
@ -133,7 +140,7 @@ def test_black_passes(cookies, context_combination):
|
||||||
|
|
||||||
|
|
||||||
def test_travis_invokes_pytest(cookies, context):
|
def test_travis_invokes_pytest(cookies, context):
|
||||||
context.update({"use_travisci": "y"})
|
context.update({"ci_tool": "Travis"})
|
||||||
result = cookies.bake(extra_context=context)
|
result = cookies.bake(extra_context=context)
|
||||||
|
|
||||||
assert result.exit_code == 0
|
assert result.exit_code == 0
|
||||||
|
@ -148,6 +155,24 @@ def test_travis_invokes_pytest(cookies, context):
|
||||||
pytest.fail(e)
|
pytest.fail(e)
|
||||||
|
|
||||||
|
|
||||||
|
def test_gitlab_invokes_flake8_and_pytest(cookies, context):
|
||||||
|
context.update({"ci_tool": "Gitlab"})
|
||||||
|
result = cookies.bake(extra_context=context)
|
||||||
|
|
||||||
|
assert result.exit_code == 0
|
||||||
|
assert result.exception is None
|
||||||
|
assert result.project.basename == context["project_slug"]
|
||||||
|
assert result.project.isdir()
|
||||||
|
|
||||||
|
with open(f"{result.project}/.gitlab-ci.yml", "r") as gitlab_yml:
|
||||||
|
try:
|
||||||
|
gitlab_config = yaml.load(gitlab_yml)
|
||||||
|
assert gitlab_config["flake8"]["script"] == ["flake8"]
|
||||||
|
assert gitlab_config["pytest"]["script"] == ["pytest"]
|
||||||
|
except yaml.YAMLError as e:
|
||||||
|
pytest.fail(e)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("slug", ["project slug", "Project_Slug"])
|
@pytest.mark.parametrize("slug", ["project slug", "Project_Slug"])
|
||||||
def test_invalid_slug(cookies, context, slug):
|
def test_invalid_slug(cookies, context, slug):
|
||||||
"""Invalid slug should failed pre-generation hook."""
|
"""Invalid slug should failed pre-generation hook."""
|
||||||
|
@ -157,3 +182,12 @@ def test_invalid_slug(cookies, context, slug):
|
||||||
|
|
||||||
assert result.exit_code != 0
|
assert result.exit_code != 0
|
||||||
assert isinstance(result.exception, FailedHookException)
|
assert isinstance(result.exception, FailedHookException)
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_whitenoise_and_no_cloud_provider(cookies, context):
|
||||||
|
"""It should not generate project if neither whitenoise or cloud provider are set"""
|
||||||
|
context.update({"use_whitenoise": "n", "cloud_provider": "None"})
|
||||||
|
result = cookies.bake(extra_context=context)
|
||||||
|
|
||||||
|
assert result.exit_code != 0
|
||||||
|
assert isinstance(result.exception, FailedHookException)
|
||||||
|
|
2
tox.ini
2
tox.ini
|
@ -1,6 +1,6 @@
|
||||||
[tox]
|
[tox]
|
||||||
skipsdist = true
|
skipsdist = true
|
||||||
envlist = py36,flake8,black,black-template
|
envlist = py37,flake8,black,black-template
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
deps = -rrequirements.txt
|
deps = -rrequirements.txt
|
||||||
|
|
|
@ -13,10 +13,16 @@ indent_style = space
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
|
|
||||||
[*.py]
|
[*.py]
|
||||||
line_length=120
|
line_length = 120
|
||||||
known_first_party={{ cookiecutter.project_slug }}
|
known_first_party = {{ cookiecutter.project_slug }}
|
||||||
multi_line_output=3
|
multi_line_output = 3
|
||||||
default_section=THIRDPARTY
|
default_section = THIRDPARTY
|
||||||
|
recursive = true
|
||||||
|
skip = venv/
|
||||||
|
skip_glob = **/migrations/*.py
|
||||||
|
include_trailing_comma = true
|
||||||
|
force_grid_wrap = 0
|
||||||
|
use_parentheses = true
|
||||||
|
|
||||||
[*.{html,css,scss,json,yml}]
|
[*.{html,css,scss,json,yml}]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
|
|
33
{{cookiecutter.project_slug}}/.gitlab-ci.yml
Normal file
33
{{cookiecutter.project_slug}}/.gitlab-ci.yml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
stages:
|
||||||
|
- lint
|
||||||
|
- test
|
||||||
|
|
||||||
|
variables:
|
||||||
|
POSTGRES_USER: '{{ cookiecutter.project_slug }}'
|
||||||
|
POSTGRES_PASSWORD: ''
|
||||||
|
POSTGRES_DB: 'test_{{ cookiecutter.project_slug }}'
|
||||||
|
|
||||||
|
flake8:
|
||||||
|
stage: lint
|
||||||
|
image: python:3.7-alpine
|
||||||
|
before_script:
|
||||||
|
- pip install -q flake8
|
||||||
|
script:
|
||||||
|
- flake8
|
||||||
|
|
||||||
|
pytest:
|
||||||
|
stage: test
|
||||||
|
image: python:3.7
|
||||||
|
tags:
|
||||||
|
- docker
|
||||||
|
services:
|
||||||
|
- postgres:11
|
||||||
|
variables:
|
||||||
|
DATABASE_URL: pgsql://$POSTGRES_USER:$POSTGRES_PASSWORD@postgres/$POSTGRES_DB
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- pip install -r requirements/local.txt
|
||||||
|
|
||||||
|
script:
|
||||||
|
- pytest
|
||||||
|
|
19
{{cookiecutter.project_slug}}/.pre-commit-config.yaml
Normal file
19
{{cookiecutter.project_slug}}/.pre-commit-config.yaml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
exclude: 'docs|node_modules|migrations|.git|.tox'
|
||||||
|
default_stages: [commit]
|
||||||
|
fail_fast: true
|
||||||
|
|
||||||
|
repos:
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: master
|
||||||
|
hooks:
|
||||||
|
- id: trailing-whitespace
|
||||||
|
files: (^|/)a/.+\.(py|html|sh|css|js)$
|
||||||
|
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: flake8
|
||||||
|
name: flake8
|
||||||
|
entry: flake8
|
||||||
|
language: python
|
||||||
|
types: [python]
|
||||||
|
|
|
@ -10,7 +10,7 @@ before_install:
|
||||||
- sudo apt-get install -qq libsqlite3-dev libxml2 libxml2-dev libssl-dev libbz2-dev wget curl llvm
|
- sudo apt-get install -qq libsqlite3-dev libxml2 libxml2-dev libssl-dev libbz2-dev wget curl llvm
|
||||||
language: python
|
language: python
|
||||||
python:
|
python:
|
||||||
- "3.6"
|
- "3.7"
|
||||||
install:
|
install:
|
||||||
- pip install -r requirements/local.txt
|
- pip install -r requirements/local.txt
|
||||||
script:
|
script:
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
FROM python:3.6-alpine
|
FROM python:3.7-slim-buster
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED 1
|
ENV PYTHONUNBUFFERED 1
|
||||||
|
|
||||||
RUN apk update \
|
RUN apt-get update \
|
||||||
|
# dependencies for building Python packages
|
||||||
|
&& apt-get install -y build-essential \
|
||||||
# psycopg2 dependencies
|
# psycopg2 dependencies
|
||||||
&& apk add --virtual build-deps gcc python3-dev musl-dev \
|
&& apt-get install -y libpq-dev \
|
||||||
&& apk add postgresql-dev \
|
|
||||||
# Pillow dependencies
|
|
||||||
&& apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \
|
|
||||||
# CFFI dependencies
|
|
||||||
&& apk add libffi-dev py-cffi \
|
|
||||||
# Translations dependencies
|
# Translations dependencies
|
||||||
&& apk add gettext \
|
&& apt-get install -y gettext \
|
||||||
# https://docs.djangoproject.com/en/dev/ref/django-admin/#dbshell
|
# cleaning up unused files
|
||||||
&& apk add postgresql-client
|
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Requirements are installed here to ensure they will be cached.
|
# Requirements are installed here to ensure they will be cached.
|
||||||
COPY ./requirements /requirements
|
COPY ./requirements /requirements
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o nounset
|
set -o nounset
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o nounset
|
set -o nounset
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o nounset
|
set -o nounset
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
|
@ -9,21 +9,23 @@ RUN npm run build
|
||||||
|
|
||||||
# Python build stage
|
# Python build stage
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
FROM python:3.6-alpine
|
FROM python:3.7-slim-buster
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED 1
|
ENV PYTHONUNBUFFERED 1
|
||||||
|
|
||||||
RUN apk update \
|
RUN apt-get update \
|
||||||
|
# dependencies for building Python packages
|
||||||
|
&& apt-get install -y build-essential \
|
||||||
# psycopg2 dependencies
|
# psycopg2 dependencies
|
||||||
&& apk add --virtual build-deps gcc python3-dev musl-dev \
|
&& apt-get install -y libpq-dev \
|
||||||
&& apk add postgresql-dev \
|
# Translations dependencies
|
||||||
# Pillow dependencies
|
&& apt-get install -y gettext \
|
||||||
&& apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \
|
# cleaning up unused files
|
||||||
# CFFI dependencies
|
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
|
||||||
&& apk add libffi-dev py-cffi
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
RUN addgroup -S django \
|
RUN addgroup --system django \
|
||||||
&& adduser -S -G django django
|
&& adduser --system --ingroup django django
|
||||||
|
|
||||||
# Requirements are installed here to ensure they will be cached.
|
# Requirements are installed here to ensure they will be cached.
|
||||||
COPY ./requirements /requirements
|
COPY ./requirements /requirements
|
||||||
|
@ -57,13 +59,11 @@ RUN chmod +x /start-flower
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
{%- if cookiecutter.js_task_runner == 'Gulp' %}
|
{%- if cookiecutter.js_task_runner == 'Gulp' %}
|
||||||
COPY --from=client-builder /app /app
|
COPY --from=client-builder --chown=django:django /app /app
|
||||||
{% else %}
|
{% else %}
|
||||||
COPY . /app
|
COPY --chown=django:django . /app
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
RUN chown -R django /app
|
|
||||||
|
|
||||||
USER django
|
USER django
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o nounset
|
set -o nounset
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
FROM traefik:alpine
|
FROM traefik:v2.0
|
||||||
RUN mkdir -p /etc/traefik/acme
|
RUN mkdir -p /etc/traefik/acme
|
||||||
RUN touch /etc/traefik/acme/acme.json
|
RUN touch /etc/traefik/acme/acme.json
|
||||||
RUN chmod 600 /etc/traefik/acme/acme.json
|
RUN chmod 600 /etc/traefik/acme/acme.json
|
||||||
COPY ./compose/production/traefik/traefik.toml /etc/traefik
|
COPY ./compose/production/traefik/traefik.yml /etc/traefik
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
logLevel = "INFO"
|
|
||||||
defaultEntryPoints = ["http", "https"]
|
|
||||||
|
|
||||||
# Entrypoints, http and https
|
|
||||||
[entryPoints]
|
|
||||||
# http should be redirected to https
|
|
||||||
[entryPoints.http]
|
|
||||||
address = ":80"
|
|
||||||
[entryPoints.http.redirect]
|
|
||||||
entryPoint = "https"
|
|
||||||
# https is the default
|
|
||||||
[entryPoints.https]
|
|
||||||
address = ":443"
|
|
||||||
[entryPoints.https.tls]
|
|
||||||
|
|
||||||
# Enable ACME (Let's Encrypt): automatic SSL
|
|
||||||
[acme]
|
|
||||||
# Email address used for registration
|
|
||||||
email = "{{ cookiecutter.email }}"
|
|
||||||
storage = "/etc/traefik/acme/acme.json"
|
|
||||||
entryPoint = "https"
|
|
||||||
onDemand = false
|
|
||||||
OnHostRule = true
|
|
||||||
# Use a HTTP-01 acme challenge rather than TLS-SNI-01 challenge
|
|
||||||
[acme.httpChallenge]
|
|
||||||
entryPoint = "http"
|
|
||||||
|
|
||||||
[file]
|
|
||||||
[backends]
|
|
||||||
[backends.django]
|
|
||||||
[backends.django.servers.server1]
|
|
||||||
url = "http://django:5000"
|
|
||||||
|
|
||||||
[frontends]
|
|
||||||
[frontends.django]
|
|
||||||
backend = "django"
|
|
||||||
passHostHeader = true
|
|
||||||
[frontends.django.headers]
|
|
||||||
HostsProxyHeaders = ['X-CSRFToken']
|
|
||||||
[frontends.django.routes.dr1]
|
|
||||||
rule = "Host:{{ cookiecutter.domain_name }}"
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
log:
|
||||||
|
level: INFO
|
||||||
|
|
||||||
|
entryPoints:
|
||||||
|
web:
|
||||||
|
# http
|
||||||
|
address: ":80"
|
||||||
|
|
||||||
|
web-secure:
|
||||||
|
# https
|
||||||
|
address: ":443"
|
||||||
|
|
||||||
|
certificatesResolvers:
|
||||||
|
letsencrypt:
|
||||||
|
# https://docs.traefik.io/master/https/acme/#lets-encrypt
|
||||||
|
acme:
|
||||||
|
email: "{{ cookiecutter.email }}"
|
||||||
|
storage: /etc/traefik/acme/acme.json
|
||||||
|
# https://docs.traefik.io/master/https/acme/#httpchallenge
|
||||||
|
httpChallenge:
|
||||||
|
entryPoint: web
|
||||||
|
|
||||||
|
http:
|
||||||
|
routers:
|
||||||
|
web-router:
|
||||||
|
rule: "Host(`{{ cookiecutter.domain_name }}`)"
|
||||||
|
entryPoints:
|
||||||
|
- web
|
||||||
|
middlewares:
|
||||||
|
- redirect
|
||||||
|
- csrf
|
||||||
|
service: django
|
||||||
|
|
||||||
|
web-secure-router:
|
||||||
|
rule: "Host(`{{ cookiecutter.domain_name }}`)"
|
||||||
|
entryPoints:
|
||||||
|
- web-secure
|
||||||
|
middlewares:
|
||||||
|
- csrf
|
||||||
|
service: django
|
||||||
|
tls:
|
||||||
|
# https://docs.traefik.io/master/routing/routers/#certresolver
|
||||||
|
certResolver: letsencrypt
|
||||||
|
|
||||||
|
middlewares:
|
||||||
|
redirect:
|
||||||
|
# https://docs.traefik.io/master/middlewares/redirectscheme/
|
||||||
|
redirectScheme:
|
||||||
|
scheme: https
|
||||||
|
permanent: true
|
||||||
|
csrf:
|
||||||
|
# https://docs.traefik.io/master/middlewares/headers/#hostsproxyheaders
|
||||||
|
# https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
|
||||||
|
headers:
|
||||||
|
hostsProxyHeaders: ['X-CSRFToken']
|
||||||
|
|
||||||
|
services:
|
||||||
|
django:
|
||||||
|
loadBalancer:
|
||||||
|
servers:
|
||||||
|
- url: http://django:5000
|
||||||
|
|
||||||
|
providers:
|
||||||
|
# https://docs.traefik.io/master/providers/file/
|
||||||
|
file:
|
||||||
|
filename: /etc/traefik/traefik.yml
|
||||||
|
watch: true
|
|
@ -131,12 +131,16 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#middleware
|
# https://docs.djangoproject.com/en/dev/ref/settings/#middleware
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
"django.middleware.security.SecurityMiddleware",
|
"django.middleware.security.SecurityMiddleware",
|
||||||
|
{%- if cookiecutter.use_whitenoise == 'y' %}
|
||||||
|
"whitenoise.middleware.WhiteNoiseMiddleware",
|
||||||
|
{%- endif %}
|
||||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||||
"django.middleware.locale.LocaleMiddleware",
|
"django.middleware.locale.LocaleMiddleware",
|
||||||
"django.middleware.common.CommonMiddleware",
|
"django.middleware.common.CommonMiddleware",
|
||||||
"django.middleware.csrf.CsrfViewMiddleware",
|
"django.middleware.csrf.CsrfViewMiddleware",
|
||||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||||
"django.contrib.messages.middleware.MessageMiddleware",
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
|
"django.middleware.common.BrokenLinkEmailsMiddleware",
|
||||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,14 @@ EMAIL_BACKEND = env(
|
||||||
)
|
)
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
|
{%- if cookiecutter.use_whitenoise == 'y' %}
|
||||||
|
|
||||||
|
# WhiteNoise
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# http://whitenoise.evans.io/en/latest/django.html#using-whitenoise-in-development
|
||||||
|
INSTALLED_APPS = ["whitenoise.runserver_nostatic"] + INSTALLED_APPS # noqa F405
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
# django-debug-toolbar
|
# django-debug-toolbar
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#prerequisites
|
# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#prerequisites
|
||||||
|
|
|
@ -92,7 +92,6 @@ AWS_DEFAULT_ACL = None
|
||||||
# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings
|
# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings
|
||||||
AWS_S3_REGION_NAME = env("DJANGO_AWS_S3_REGION_NAME", default=None)
|
AWS_S3_REGION_NAME = env("DJANGO_AWS_S3_REGION_NAME", default=None)
|
||||||
{% elif cookiecutter.cloud_provider == 'GCP' %}
|
{% elif cookiecutter.cloud_provider == 'GCP' %}
|
||||||
DEFAULT_FILE_STORAGE = "storages.backends.gcloud.GoogleCloudStorage"
|
|
||||||
GS_BUCKET_NAME = env("DJANGO_GCP_STORAGE_BUCKET_NAME")
|
GS_BUCKET_NAME = env("DJANGO_GCP_STORAGE_BUCKET_NAME")
|
||||||
GS_DEFAULT_ACL = "publicRead"
|
GS_DEFAULT_ACL = "publicRead"
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
|
@ -105,8 +104,11 @@ GS_DEFAULT_ACL = "publicRead"
|
||||||
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
|
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
|
||||||
{% elif cookiecutter.cloud_provider == 'AWS' -%}
|
{% elif cookiecutter.cloud_provider == 'AWS' -%}
|
||||||
STATICFILES_STORAGE = "config.settings.production.StaticRootS3Boto3Storage"
|
STATICFILES_STORAGE = "config.settings.production.StaticRootS3Boto3Storage"
|
||||||
|
COLLECTFAST_STRATEGY = "collectfast.strategies.boto3.Boto3Strategy"
|
||||||
STATIC_URL = f"https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/static/"
|
STATIC_URL = f"https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/static/"
|
||||||
{% elif cookiecutter.cloud_provider == 'GCP' -%}
|
{% elif cookiecutter.cloud_provider == 'GCP' -%}
|
||||||
|
STATICFILES_STORAGE = "config.settings.production.StaticRootGoogleCloudStorage"
|
||||||
|
COLLECTFAST_STRATEGY = "collectfast.strategies.gcloud.GoogleCloudStrategy"
|
||||||
STATIC_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/static/"
|
STATIC_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/static/"
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
|
|
||||||
|
@ -132,14 +134,27 @@ class MediaRootS3Boto3Storage(S3Boto3Storage):
|
||||||
DEFAULT_FILE_STORAGE = "config.settings.production.MediaRootS3Boto3Storage"
|
DEFAULT_FILE_STORAGE = "config.settings.production.MediaRootS3Boto3Storage"
|
||||||
MEDIA_URL = f"https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/media/"
|
MEDIA_URL = f"https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/media/"
|
||||||
{%- elif cookiecutter.cloud_provider == 'GCP' %}
|
{%- elif cookiecutter.cloud_provider == 'GCP' %}
|
||||||
|
from storages.backends.gcloud import GoogleCloudStorage # noqa E402
|
||||||
|
|
||||||
|
|
||||||
|
class StaticRootGoogleCloudStorage(GoogleCloudStorage):
|
||||||
|
location = "static"
|
||||||
|
default_acl = "publicRead"
|
||||||
|
|
||||||
|
|
||||||
|
class MediaRootGoogleCloudStorage(GoogleCloudStorage):
|
||||||
|
location = "media"
|
||||||
|
file_overwrite = False
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_FILE_STORAGE = "config.settings.production.MediaRootGoogleCloudStorage"
|
||||||
MEDIA_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/media/"
|
MEDIA_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/media/"
|
||||||
MEDIA_ROOT = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/media/"
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
# TEMPLATES
|
# TEMPLATES
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#templates
|
# https://docs.djangoproject.com/en/dev/ref/settings/#templates
|
||||||
TEMPLATES[0]["OPTIONS"]["loaders"] = [ # noqa F405
|
TEMPLATES[-1]["OPTIONS"]["loaders"] = [ # type: ignore[index] # noqa F405
|
||||||
(
|
(
|
||||||
"django.template.loaders.cached.Loader",
|
"django.template.loaders.cached.Loader",
|
||||||
[
|
[
|
||||||
|
@ -179,14 +194,7 @@ ANYMAIL = {
|
||||||
"MAILGUN_API_URL": env("MAILGUN_API_URL", default="https://api.mailgun.net/v3"),
|
"MAILGUN_API_URL": env("MAILGUN_API_URL", default="https://api.mailgun.net/v3"),
|
||||||
}
|
}
|
||||||
|
|
||||||
{% if cookiecutter.use_whitenoise == 'y' -%}
|
{% if cookiecutter.use_compressor == 'y' -%}
|
||||||
# WhiteNoise
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
# http://whitenoise.evans.io/en/latest/django.html#enable-whitenoise
|
|
||||||
MIDDLEWARE.insert(1, "whitenoise.middleware.WhiteNoiseMiddleware") # noqa F405
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
{%- if cookiecutter.use_compressor == 'y' -%}
|
|
||||||
# django-compressor
|
# django-compressor
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_ENABLED
|
# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_ENABLED
|
||||||
|
|
|
@ -32,7 +32,7 @@ PASSWORD_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"]
|
||||||
|
|
||||||
# TEMPLATES
|
# TEMPLATES
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
TEMPLATES[0]["OPTIONS"]["loaders"] = [ # noqa F405
|
TEMPLATES[-1]["OPTIONS"]["loaders"] = [ # type: ignore[index] # noqa F405
|
||||||
(
|
(
|
||||||
"django.template.loaders.cached.Loader",
|
"django.template.loaders.cached.Loader",
|
||||||
[
|
[
|
||||||
|
|
|
@ -65,6 +65,8 @@ services:
|
||||||
command: /start-flower
|
command: /start-flower
|
||||||
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
|
{% if cookiecutter.cloud_provider == 'AWS' %}
|
||||||
awscli:
|
awscli:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
|
@ -73,3 +75,4 @@ services:
|
||||||
- ./.envs/.production/.django
|
- ./.envs/.production/.django
|
||||||
volumes:
|
volumes:
|
||||||
- production_postgres_data_backups:/backups
|
- production_postgres_data_backups:/backups
|
||||||
|
{%- endif %}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[pytest]
|
[pytest]
|
||||||
addopts = --ds=config.settings.test
|
addopts = --ds=config.settings.test --reuse-db
|
||||||
python_files = tests.py test_*.py
|
python_files = tests.py test_*.py
|
||||||
{%- if cookiecutter.js_task_runner != 'None' %}
|
{%- if cookiecutter.js_task_runner != 'None' %}
|
||||||
norecursedirs = node_modules
|
norecursedirs = node_modules
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
pytz==2019.2 # https://github.com/stub42/pytz
|
pytz==2019.3 # https://github.com/stub42/pytz
|
||||||
python-slugify==3.0.3 # https://github.com/un33k/python-slugify
|
python-slugify==4.0.0 # https://github.com/un33k/python-slugify
|
||||||
Pillow==6.1.0 # https://github.com/python-pillow/Pillow
|
Pillow==7.0.0 # https://github.com/python-pillow/Pillow
|
||||||
{%- if cookiecutter.use_compressor == "y" %}
|
{%- if cookiecutter.use_compressor == "y" %}
|
||||||
rcssmin==1.0.6{% if cookiecutter.windows == 'y' and cookiecutter.use_docker == 'n' %} --install-option="--without-c-extensions"{% endif %} # https://github.com/ndparker/rcssmin
|
rcssmin==1.0.6{% if cookiecutter.windows == 'y' and cookiecutter.use_docker == 'n' %} --install-option="--without-c-extensions"{% endif %} # https://github.com/ndparker/rcssmin
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
argon2-cffi==19.1.0 # https://github.com/hynek/argon2_cffi
|
argon2-cffi==19.2.0 # https://github.com/hynek/argon2_cffi
|
||||||
{%- if cookiecutter.use_whitenoise == 'y' %}
|
{%- if cookiecutter.use_whitenoise == 'y' %}
|
||||||
whitenoise==4.1.3 # https://github.com/evansd/whitenoise
|
whitenoise==5.0.1 # https://github.com/evansd/whitenoise
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
redis==3.3.8 # https://github.com/antirez/redis
|
redis==3.3.11 # https://github.com/antirez/redis
|
||||||
{%- if cookiecutter.use_celery == "y" %}
|
{%- if cookiecutter.use_celery == "y" %}
|
||||||
celery==4.3.0 # pyup: < 5.0 # https://github.com/celery/celery
|
celery==4.4.0 # pyup: < 5.0 # https://github.com/celery/celery
|
||||||
django-celery-beat==1.5.0 # https://github.com/celery/django-celery-beat
|
django-celery-beat==1.5.0 # https://github.com/celery/django-celery-beat
|
||||||
{%- if cookiecutter.use_docker == 'y' %}
|
{%- if cookiecutter.use_docker == 'y' %}
|
||||||
flower==0.9.3 # https://github.com/mher/flower
|
flower==0.9.3 # https://github.com/mher/flower
|
||||||
|
@ -19,16 +19,16 @@ flower==0.9.3 # https://github.com/mher/flower
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
django==2.2.5 # pyup: < 3.0 # https://www.djangoproject.com/
|
django==2.2.9 # pyup: < 3.0 # https://www.djangoproject.com/
|
||||||
django-environ==0.4.5 # https://github.com/joke2k/django-environ
|
django-environ==0.4.5 # https://github.com/joke2k/django-environ
|
||||||
django-model-utils==3.2.0 # https://github.com/jazzband/django-model-utils
|
django-model-utils==4.0.0 # https://github.com/jazzband/django-model-utils
|
||||||
django-allauth==0.40.0 # https://github.com/pennersr/django-allauth
|
django-allauth==0.41.0 # https://github.com/pennersr/django-allauth
|
||||||
django-crispy-forms==1.7.2 # https://github.com/django-crispy-forms/django-crispy-forms
|
django-crispy-forms==1.8.1 # https://github.com/django-crispy-forms/django-crispy-forms
|
||||||
{%- if cookiecutter.use_compressor == "y" %}
|
{%- if cookiecutter.use_compressor == "y" %}
|
||||||
django-compressor==2.3 # https://github.com/django-compressor/django-compressor
|
django-compressor==2.4 # https://github.com/django-compressor/django-compressor
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
django-redis==4.10.0 # https://github.com/niwinz/django-redis
|
django-redis==4.11.0 # https://github.com/niwinz/django-redis
|
||||||
|
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
djangorestframework==3.10.3 # https://github.com/encode/django-rest-framework
|
djangorestframework==3.11.0 # https://github.com/encode/django-rest-framework
|
||||||
coreapi==2.3.3 # https://github.com/core-api/python-client
|
coreapi==2.3.3 # https://github.com/core-api/python-client
|
||||||
|
|
|
@ -1,35 +1,37 @@
|
||||||
-r ./base.txt
|
-r ./base.txt
|
||||||
|
|
||||||
Werkzeug==0.14.1 # pyup: < 0.15 # https://github.com/pallets/werkzeug
|
Werkzeug==0.16.0 # https://github.com/pallets/werkzeug
|
||||||
ipdb==0.12.2 # https://github.com/gotcha/ipdb
|
ipdb==0.12.3 # https://github.com/gotcha/ipdb
|
||||||
Sphinx==2.2.0 # https://github.com/sphinx-doc/sphinx
|
Sphinx==2.3.1 # https://github.com/sphinx-doc/sphinx
|
||||||
{%- if cookiecutter.use_docker == 'y' %}
|
{%- if cookiecutter.use_docker == 'y' %}
|
||||||
psycopg2==2.8.3 --no-binary psycopg2 # https://github.com/psycopg/psycopg2
|
psycopg2==2.8.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2
|
||||||
{%- else %}
|
{%- else %}
|
||||||
psycopg2-binary==2.8.3 # https://github.com/psycopg/psycopg2
|
psycopg2-binary==2.8.4 # https://github.com/psycopg/psycopg2
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
mypy==0.720 # https://github.com/python/mypy
|
mypy==0.761 # https://github.com/python/mypy
|
||||||
pytest==5.1.2 # https://github.com/pytest-dev/pytest
|
django-stubs==1.4.0 # https://github.com/typeddjango/django-stubs
|
||||||
|
pytest==5.3.4 # https://github.com/pytest-dev/pytest
|
||||||
pytest-sugar==0.9.2 # https://github.com/Frozenball/pytest-sugar
|
pytest-sugar==0.9.2 # https://github.com/Frozenball/pytest-sugar
|
||||||
|
|
||||||
# Code quality
|
# Code quality
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
flake8==3.7.8 # https://github.com/PyCQA/flake8
|
flake8==3.7.9 # https://github.com/PyCQA/flake8
|
||||||
coverage==4.5.4 # https://github.com/nedbat/coveragepy
|
coverage==5.0.3 # https://github.com/nedbat/coveragepy
|
||||||
black==19.3b0 # https://github.com/ambv/black
|
black==19.10b0 # https://github.com/ambv/black
|
||||||
pylint-django==2.0.11 # https://github.com/PyCQA/pylint-django
|
pylint-django==2.0.13 # https://github.com/PyCQA/pylint-django
|
||||||
{%- if cookiecutter.use_celery == 'y' %}
|
{%- if cookiecutter.use_celery == 'y' %}
|
||||||
pylint-celery==0.3 # https://github.com/PyCQA/pylint-celery
|
pylint-celery==0.3 # https://github.com/PyCQA/pylint-celery
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
pre-commit==1.21.0 # https://github.com/pre-commit/pre-commit
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
factory-boy==2.12.0 # https://github.com/FactoryBoy/factory_boy
|
factory-boy==2.12.0 # https://github.com/FactoryBoy/factory_boy
|
||||||
|
|
||||||
django-debug-toolbar==2.0 # https://github.com/jazzband/django-debug-toolbar
|
django-debug-toolbar==2.1 # https://github.com/jazzband/django-debug-toolbar
|
||||||
django-extensions==2.2.1 # https://github.com/django-extensions/django-extensions
|
django-extensions==2.2.6 # https://github.com/django-extensions/django-extensions
|
||||||
django-coverage-plugin==1.6.0 # https://github.com/nedbat/django_coverage_plugin
|
django-coverage-plugin==1.7.0 # https://github.com/nedbat/django_coverage_plugin
|
||||||
pytest-django==3.5.1 # https://github.com/pytest-dev/pytest-django
|
pytest-django==3.8.0 # https://github.com/pytest-dev/pytest-django
|
||||||
|
|
|
@ -2,20 +2,20 @@
|
||||||
|
|
||||||
-r ./base.txt
|
-r ./base.txt
|
||||||
|
|
||||||
gunicorn==19.9.0 # https://github.com/benoitc/gunicorn
|
gunicorn==20.0.4 # https://github.com/benoitc/gunicorn
|
||||||
psycopg2==2.8.3 --no-binary psycopg2 # https://github.com/psycopg/psycopg2
|
psycopg2==2.8.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2
|
||||||
{%- if cookiecutter.use_whitenoise == 'n' %}
|
{%- if cookiecutter.use_whitenoise == 'n' %}
|
||||||
Collectfast==1.0.0 # https://github.com/antonagestam/collectfast
|
Collectfast==1.3.1 # https://github.com/antonagestam/collectfast
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if cookiecutter.use_sentry == "y" %}
|
{%- if cookiecutter.use_sentry == "y" %}
|
||||||
sentry-sdk==0.11.2 # https://github.com/getsentry/sentry-python
|
sentry-sdk==0.14.1 # https://github.com/getsentry/sentry-python
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
{%- if cookiecutter.cloud_provider == 'AWS' %}
|
{%- if cookiecutter.cloud_provider == 'AWS' %}
|
||||||
django-storages[boto3]==1.7.2 # https://github.com/jschneier/django-storages
|
django-storages[boto3]==1.8 # https://github.com/jschneier/django-storages
|
||||||
{%- elif cookiecutter.cloud_provider == 'GCP' %}
|
{%- elif cookiecutter.cloud_provider == 'GCP' %}
|
||||||
django-storages[google]==1.7.2 # https://github.com/jschneier/django-storages
|
django-storages[google]==1.8 # https://github.com/jschneier/django-storages
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
django-anymail[mailgun]==6.1.0 # https://github.com/anymail/django-anymail
|
django-anymail[mailgun]==7.0.0 # https://github.com/anymail/django-anymail
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
python-3.6.8
|
python-3.7.6
|
||||||
|
|
|
@ -7,14 +7,16 @@ max-line-length = 120
|
||||||
exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules
|
exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules
|
||||||
|
|
||||||
[mypy]
|
[mypy]
|
||||||
python_version = 3.6
|
python_version = 3.7
|
||||||
check_untyped_defs = True
|
check_untyped_defs = True
|
||||||
ignore_errors = False
|
|
||||||
ignore_missing_imports = True
|
ignore_missing_imports = True
|
||||||
strict_optional = True
|
|
||||||
warn_unused_ignores = True
|
warn_unused_ignores = True
|
||||||
warn_redundant_casts = True
|
warn_redundant_casts = True
|
||||||
warn_unused_configs = True
|
warn_unused_configs = True
|
||||||
|
plugins = mypy_django_plugin.main
|
||||||
|
|
||||||
|
[mypy.plugins.django-stubs]
|
||||||
|
django_settings_module = config.settings.test
|
||||||
|
|
||||||
[mypy-*.migrations.*]
|
[mypy-*.migrations.*]
|
||||||
# Django migrations should not produce any errors:
|
# Django migrations should not produce any errors:
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
##basic build dependencies of various Django apps for Debian Jessie 10.x
|
||||||
|
#build-essential metapackage install: make, gcc, g++,
|
||||||
|
build-essential
|
||||||
|
#required to translate
|
||||||
|
gettext
|
||||||
|
python3-dev
|
||||||
|
|
||||||
|
##shared dependencies of:
|
||||||
|
##Pillow, pylibmc
|
||||||
|
zlib1g-dev
|
||||||
|
|
||||||
|
##Postgresql and psycopg2 dependencies
|
||||||
|
libpq-dev
|
||||||
|
|
||||||
|
##Pillow dependencies
|
||||||
|
libtiff5-dev
|
||||||
|
libjpeg62-turbo-dev
|
||||||
|
libfreetype6-dev
|
||||||
|
liblcms2-dev
|
||||||
|
libwebp-dev
|
||||||
|
|
||||||
|
##django-extensions
|
||||||
|
libgraphviz-dev
|
|
@ -1,7 +1,7 @@
|
||||||
import pytest
|
import pytest
|
||||||
from django.conf import settings
|
|
||||||
from django.test import RequestFactory
|
from django.test import RequestFactory
|
||||||
|
|
||||||
|
from {{ cookiecutter.project_slug }}.users.models import User
|
||||||
from {{ cookiecutter.project_slug }}.users.tests.factories import UserFactory
|
from {{ cookiecutter.project_slug }}.users.tests.factories import UserFactory
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ def media_storage(settings, tmpdir):
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def user() -> settings.AUTH_USER_MODEL:
|
def user() -> User:
|
||||||
return UserFactory()
|
return UserFactory()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
{{ form|crispy }}
|
{{ form|crispy }}
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<button type="submit" class="btn">Update</button>
|
<button type="submit" class="btn btn-primary">Update</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import pytest
|
import pytest
|
||||||
from django.conf import settings
|
|
||||||
|
from {{ cookiecutter.project_slug }}.users.models import User
|
||||||
|
|
||||||
pytestmark = pytest.mark.django_db
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
|
||||||
def test_user_get_absolute_url(user: settings.AUTH_USER_MODEL):
|
def test_user_get_absolute_url(user: User):
|
||||||
assert user.get_absolute_url() == f"/users/{user.username}/"
|
assert user.get_absolute_url() == f"/users/{user.username}/"
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import pytest
|
import pytest
|
||||||
from django.conf import settings
|
|
||||||
from django.urls import reverse, resolve
|
from django.urls import reverse, resolve
|
||||||
|
|
||||||
|
from {{ cookiecutter.project_slug }}.users.models import User
|
||||||
|
|
||||||
pytestmark = pytest.mark.django_db
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
|
||||||
def test_detail(user: settings.AUTH_USER_MODEL):
|
def test_detail(user: User):
|
||||||
assert (
|
assert (
|
||||||
reverse("users:detail", kwargs={"username": user.username})
|
reverse("users:detail", kwargs={"username": user.username})
|
||||||
== f"/users/{user.username}/"
|
== f"/users/{user.username}/"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import pytest
|
import pytest
|
||||||
from django.conf import settings
|
|
||||||
from django.test import RequestFactory
|
from django.test import RequestFactory
|
||||||
|
|
||||||
|
from {{ cookiecutter.project_slug }}.users.models import User
|
||||||
from {{ cookiecutter.project_slug }}.users.views import UserRedirectView, UserUpdateView
|
from {{ cookiecutter.project_slug }}.users.views import UserRedirectView, UserUpdateView
|
||||||
|
|
||||||
pytestmark = pytest.mark.django_db
|
pytestmark = pytest.mark.django_db
|
||||||
|
@ -16,9 +16,7 @@ class TestUserUpdateView:
|
||||||
https://github.com/pytest-dev/pytest-django/pull/258
|
https://github.com/pytest-dev/pytest-django/pull/258
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_get_success_url(
|
def test_get_success_url(self, user: User, request_factory: RequestFactory):
|
||||||
self, user: settings.AUTH_USER_MODEL, request_factory: RequestFactory
|
|
||||||
):
|
|
||||||
view = UserUpdateView()
|
view = UserUpdateView()
|
||||||
request = request_factory.get("/fake-url/")
|
request = request_factory.get("/fake-url/")
|
||||||
request.user = user
|
request.user = user
|
||||||
|
@ -27,9 +25,7 @@ class TestUserUpdateView:
|
||||||
|
|
||||||
assert view.get_success_url() == f"/users/{user.username}/"
|
assert view.get_success_url() == f"/users/{user.username}/"
|
||||||
|
|
||||||
def test_get_object(
|
def test_get_object(self, user: User, request_factory: RequestFactory):
|
||||||
self, user: settings.AUTH_USER_MODEL, request_factory: RequestFactory
|
|
||||||
):
|
|
||||||
view = UserUpdateView()
|
view = UserUpdateView()
|
||||||
request = request_factory.get("/fake-url/")
|
request = request_factory.get("/fake-url/")
|
||||||
request.user = user
|
request.user = user
|
||||||
|
@ -40,9 +36,7 @@ class TestUserUpdateView:
|
||||||
|
|
||||||
|
|
||||||
class TestUserRedirectView:
|
class TestUserRedirectView:
|
||||||
def test_get_redirect_url(
|
def test_get_redirect_url(self, user: User, request_factory: RequestFactory):
|
||||||
self, user: settings.AUTH_USER_MODEL, request_factory: RequestFactory
|
|
||||||
):
|
|
||||||
view = UserRedirectView()
|
view = UserRedirectView()
|
||||||
request = request_factory.get("/fake-url")
|
request = request_factory.get("/fake-url")
|
||||||
request.user = user
|
request.user = user
|
||||||
|
|
Loading…
Reference in New Issue
Block a user