Merge branch 'master' into user_app_urls

This commit is contained in:
Bruno Alla 2019-04-01 13:30:40 +01:00
commit 133aab2638
16 changed files with 163 additions and 47 deletions

View File

@ -13,9 +13,9 @@ before_install:
matrix:
include:
- name: Test
- name: Tox Test
script: tox -e py36
- name: Black
- name: Black template
script: tox -e black
- name: Basic Docker
script: sh tests/test_docker.sh

View File

@ -106,6 +106,7 @@ Listed in alphabetical order.
Garry Cairns `@garry-cairns`_
Garry Polley `@garrypolley`_
Hamish Durkin `@durkode`_
Hana Quadara `@hanaquadara`_
Harry Percival `@hjwp`_
Hendrik Schneider `@hendrikschneider`_
Henrique G. G. Pereira `@ikkebr`_
@ -311,6 +312,7 @@ Listed in alphabetical order.
.. _@saschalalala: https://github.com/saschalalala
.. _@mrcoles: https://github.com/mrcoles
.. _@ericgroom: https://github.com/ericgroom
.. _@hanaquadara: https://github.com/hanaquadara
Special Thanks
~~~~~~~~~~~~~~

View File

@ -17,11 +17,8 @@ Run these commands to deploy the project to Heroku:
heroku addons:create heroku-redis:hobby-dev
# If using mailgun:
heroku addons:create mailgun:starter
heroku addons:create sentry:f1
heroku config:set PYTHONHASHSEED=random
heroku config:set WEB_CONCURRENCY=4
@ -52,3 +49,70 @@ Run these commands to deploy the project to Heroku:
heroku run python manage.py check --deploy
heroku open
.. warning::
.. include:: mailgun.rst
Optional actions
----------------
Celery
++++++
Celery requires a few extra environment variables to be ready operational. Also, the worker is created,
it's in the ``Procfile``, but is turned off by default:
.. code-block:: bash
# Set the broker URL to Redis
heroku config:set CELERY_BROKER_URL=`heroku config:get REDIS_URL`
# Scale dyno to 1 instance
heroku ps:scale worker=1
Sentry
++++++
If you're opted for Sentry error tracking, you can either install it through the `Sentry add-on`_:
.. code-block:: bash
heroku addons:create sentry:f1
Or add the DSN for your account, if you already have one:
.. code-block:: bash
heroku config:set SENTRY_DSN=https://xxxx@sentry.io/12345
.. _Sentry add-on: https://elements.heroku.com/addons/sentry
Gulp & Bootstrap compilation
++++++++++++++++++++++++++++
If you've opted for a custom bootstrap build, you'll most likely need to setup
your app to use `multiple buildpacks`_: one for Python & one for Node.js:
.. code-block:: bash
heroku buildpacks:add --index 1 heroku/nodejs
At time of writing, this should do the trick: during deployment,
the Heroku should run ``npm install`` and then ``npm build``,
which runs Gulp in cookiecutter-django.
If things don't work, please refer to the Heroku docs.
.. _multiple buildpacks: https://devcenter.heroku.com/articles/using-multiple-buildpacks-for-an-app
About Heroku & Docker
---------------------
Although Heroku has some sort of `Docker support`_, it's not supported by cookiecutter-django.
We invite you to follow Heroku documentation about it.
.. _Docker support:: https://devcenter.heroku.com/articles/build-docker-images-heroku-yml

View File

@ -43,6 +43,11 @@ You will probably also need to setup the Mail backend, for example by adding a `
.. _Mailgun: https://mailgun.com
.. warning::
.. include:: mailgun.rst
Optional: Use AWS IAM Role for EC2 instance
-------------------------------------------

View File

@ -25,7 +25,7 @@ This is included in flake8's checks, but you can also run it separately to see a
The config for pylint is located in .pylintrc. It specifies:
* Use the pylint_common and pylint_django plugins. If using Celery, also use pylint_celery.
* Use the pylint_django plugin. If using Celery, also use pylint_celery.
* Set max line length to 120 chars
* Disable linting messages for missing docstring and invalid name
* max-parents=13

13
docs/mailgun.rst Normal file
View File

@ -0,0 +1,13 @@
If your email server used to send email isn't configured properly (Mailgun by default),
attempting to send an email will cause an Internal Server Error.
By default, django-allauth is setup to `have emails verifications mandatory`_,
which means it'll send a verification email when an unverified user tries to
log-in or when someone tries to sign-up.
This may happen just after you've setup your Mailgun account, which is running in a
sandbox subdomain by default. Either add your email to the list of authorized recipients
or verify your domain.
.. _have emails verifications mandatory: https://django-allauth.readthedocs.io/en/latest/configuration.html?highlight=ACCOUNT_EMAIL_VERIFICATION

View File

@ -11,5 +11,7 @@ This page contains some advice about errors and problems commonly encountered du
#. New apps not getting created in project root: This is the expected behavior, because cookiecutter-django does not change the way that django startapp works, you'll have to fix this manually (see `#1725`_)
#. .. include:: mailgun.rst
.. _#528: https://github.com/pydanny/cookiecutter-django/issues/528#issuecomment-212650373
.. _#1725: https://github.com/pydanny/cookiecutter-django/issues/1725#issuecomment-407493176

View File

@ -30,9 +30,8 @@ if "{{ cookiecutter.use_docker }}".lower() == "n":
python_major_version = sys.version_info[0]
if python_major_version == 2:
print(
WARNING + "Cookiecutter Django does not support Python 2. "
"Stability is guaranteed with Python 3.6+ only, "
"are you sure you want to proceed (y/n)? " + TERMINATOR
WARNING + "You're running cookiecutter under Python 2, but the generated "
"project requires Python 3.6+. Do you want to proceed (y/n)? " + TERMINATOR
)
yes_options, no_options = frozenset(["y"]), frozenset(["n"])
while True:

View File

@ -4,11 +4,13 @@ binaryornot==0.4.4
# Code quality
# ------------------------------------------------------------------------------
black==19.3b0
flake8==3.7.6
# Testing
# ------------------------------------------------------------------------------
tox==3.6.1
pytest==4.3.1
tox==3.8.3
pytest==4.4.0
pytest_cases==1.5.1
pytest-cookies==0.3.0
pyyaml==5.1

View File

@ -1,14 +1,17 @@
import os
import re
import sh
import yaml
import pytest
from pytest_cases import pytest_fixture_plus
import sh
import yaml
from binaryornot.check import is_binary
PATTERN = "{{(\s?cookiecutter)[.](.*?)}}"
RE_OBJ = re.compile(PATTERN)
YN_CHOICES = ["y", "n"]
@pytest.fixture
def context():
@ -24,6 +27,35 @@ def context():
}
@pytest_fixture_plus
@pytest.mark.parametrize("windows", YN_CHOICES, ids=lambda yn: f"win:{yn}")
@pytest.mark.parametrize("use_docker", YN_CHOICES, ids=lambda yn: f"docker:{yn}")
@pytest.mark.parametrize("use_celery", YN_CHOICES, ids=lambda yn: f"celery:{yn}")
@pytest.mark.parametrize("use_mailhog", YN_CHOICES, ids=lambda yn: f"mailhog:{yn}")
@pytest.mark.parametrize("use_sentry", YN_CHOICES, ids=lambda yn: f"sentry:{yn}")
@pytest.mark.parametrize("use_compressor", YN_CHOICES, ids=lambda yn: f"cmpr:{yn}")
@pytest.mark.parametrize("use_whitenoise", YN_CHOICES, ids=lambda yn: f"wnoise:{yn}")
def context_combination(
windows,
use_docker,
use_celery,
use_mailhog,
use_sentry,
use_compressor,
use_whitenoise,
):
"""Fixture that parametrize the function where it's used."""
return {
"windows": windows,
"use_docker": use_docker,
"use_compressor": use_compressor,
"use_celery": use_celery,
"use_mailhog": use_mailhog,
"use_sentry": use_sentry,
"use_whitenoise": use_whitenoise,
}
def build_files_list(root_dir):
"""Build a list containing absolute paths to the generated files."""
return [
@ -48,8 +80,13 @@ def check_paths(paths):
assert match is None, msg.format(path)
def test_default_configuration(cookies, context):
result = cookies.bake(extra_context=context)
def test_project_generation(cookies, context, context_combination):
"""
Test that project is generated and fully rendered.
This is parametrized for each combination from ``context_combination`` fixture
"""
result = cookies.bake(extra_context={**context, **context_combination})
assert result.exit_code == 0
assert result.exception is None
assert result.project.basename == context["project_slug"]
@ -60,33 +97,24 @@ def test_default_configuration(cookies, context):
check_paths(paths)
@pytest.fixture(params=["use_mailhog", "use_celery", "windows"])
def feature_context(request, context):
context.update({request.param: "y"})
return context
def test_linting_passes(cookies, context_combination):
"""
Generated project should pass flake8 & black.
def test_enabled_features(cookies, feature_context):
result = cookies.bake(extra_context=feature_context)
assert result.exit_code == 0
assert result.exception is None
assert result.project.basename == feature_context["project_slug"]
assert result.project.isdir()
paths = build_files_list(str(result.project))
assert paths
check_paths(paths)
def test_flake8_compliance(cookies):
"""generated project should pass flake8"""
result = cookies.bake()
This is parametrized for each combination from ``context_combination`` fixture
"""
result = cookies.bake(extra_context=context_combination)
try:
sh.flake8(str(result.project))
except sh.ErrorReturnCode as e:
pytest.fail(e)
try:
sh.black("--check", "--diff", "--exclude", "migrations", f"{result.project}/")
except sh.ErrorReturnCode as e:
pytest.fail(e)
def test_travis_invokes_pytest(cookies, context):
context.update({"use_travisci": "y"})

View File

@ -1,5 +1,5 @@
[MASTER]
load-plugins=pylint_common, pylint_django{% if cookiecutter.use_celery == "y" %}, pylint_celery {% endif %}
load-plugins=pylint_django{% if cookiecutter.use_celery == "y" %}, pylint_celery {% endif %}
[FORMAT]
max-line-length=120

View File

@ -43,9 +43,7 @@ USE_TZ = True
DATABASES = {"default": env.db("DATABASE_URL")}
{%- else %}
DATABASES = {
"default": env.db(
"DATABASE_URL", default="postgres://{% if cookiecutter.windows == 'y' %}localhost{% endif %}/{{cookiecutter.project_slug}}"
),
"default": env.db("DATABASE_URL", default="postgres://{% if cookiecutter.windows == 'y' %}localhost{% endif %}/{{cookiecutter.project_slug}}")
}
{%- endif %}
DATABASES["default"]["ATOMIC_REQUESTS"] = True

View File

@ -182,7 +182,7 @@ COMPRESS_ENABLED = env.bool("COMPRESS_ENABLED", default=True)
# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_STORAGE
COMPRESS_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_URL
COMPRESS_URL = STATIC_URL
COMPRESS_URL = STATIC_URL{% if cookiecutter.use_whitenoise == 'y' %} # noqa F405{% endif %}
{% endif %}
{%- if cookiecutter.use_whitenoise == 'n' -%}
# Collectfast

View File

@ -1,8 +1,8 @@
pytz==2018.9 # https://github.com/stub42/pytz
python-slugify==3.0.0 # https://github.com/un33k/python-slugify
python-slugify==3.0.2 # https://github.com/un33k/python-slugify
Pillow==5.4.1 # https://github.com/python-pillow/Pillow
{%- if cookiecutter.use_compressor == "y" %}
rcssmin==1.0.6{% if cookiecutter.windows == 'y' and 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 %}
argon2-cffi==19.1.0 # https://github.com/hynek/argon2_cffi
{%- if cookiecutter.use_whitenoise == 'y' %}
@ -10,8 +10,7 @@ whitenoise==4.1.2 # https://github.com/evansd/whitenoise
{%- endif %}
redis==3.2.1 # https://github.com/antirez/redis
{%- if cookiecutter.use_celery == "y" %}
celery==4.2.1 # pyup: < 5.0 # https://github.com/celery/celery
kombu==4.4.0 # https://github.com/celery/kombu
celery==4.3.0 # pyup: < 5.0 # https://github.com/celery/celery
{%- if cookiecutter.use_docker == 'y' %}
flower==0.9.3 # https://github.com/mher/flower
{%- endif %}

View File

@ -2,7 +2,7 @@
Werkzeug==0.15.1 # https://github.com/pallets/werkzeug
ipdb==0.12 # https://github.com/gotcha/ipdb
Sphinx==1.8.5 # https://github.com/sphinx-doc/sphinx
Sphinx==2.0.0 # https://github.com/sphinx-doc/sphinx
{%- if cookiecutter.use_docker == 'y' %}
psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2
{%- else %}
@ -12,7 +12,7 @@ psycopg2-binary==2.7.7 # https://github.com/psycopg/psycopg2
# Testing
# ------------------------------------------------------------------------------
mypy==0.670 # https://github.com/python/mypy
pytest==4.3.1 # https://github.com/pytest-dev/pytest
pytest==4.4.0 # https://github.com/pytest-dev/pytest
pytest-sugar==0.9.2 # https://github.com/Frozenball/pytest-sugar
# Code quality
@ -20,6 +20,10 @@ pytest-sugar==0.9.2 # https://github.com/Frozenball/pytest-sugar
flake8==3.7.5 # https://github.com/PyCQA/flake8
coverage==4.5.3 # https://github.com/nedbat/coveragepy
black==19.3b0 # https://github.com/ambv/black
pylint-django==2.0.6 # https://github.com/PyCQA/pylint-django
{%- if cookiecutter.use_celery == 'y' %}
pylint-celery==0.3 # https://github.com/PyCQA/pylint-celery
{%- endif %}
# Django
# ------------------------------------------------------------------------------

View File

@ -8,7 +8,7 @@ psycopg2==2.7.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2
Collectfast==0.6.2 # https://github.com/antonagestam/collectfast
{%- endif %}
{%- if cookiecutter.use_sentry == "y" %}
sentry-sdk==0.7.7 # https://github.com/getsentry/sentry-python
sentry-sdk==0.7.9 # https://github.com/getsentry/sentry-python
{%- endif %}
# Django