diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..9f4c97f31 --- /dev/null +++ b/.github/FUNDING.yml @@ -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'] diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index 3a9a641b1..1b65a2c80 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -74,6 +74,7 @@ Listed in alphabetical order. Bouke Haarsma Brent Payne `@brentpayne`_ @brentpayne Burhan Khalid            `@burhan`_                   @burhan + Caio Ariede `@caioariede`_ @caioariede Carl Johnson `@carlmjohnson`_ @carlmjohnson Catherine Devlin `@catherinedevlin`_ Cédric Gaspoz `@cgaspoz`_ @@ -230,6 +231,7 @@ Listed in alphabetical order. .. _@c-rhodes: https://github.com/c-rhodes .. _@caffodian: https://github.com/caffodian .. _@canonnervio: https://github.com/canonnervio +.. _@caioariede: https://github.com/caioariede .. _@carlmjohnson: https://github.com/carlmjohnson .. _@catherinedevlin: https://github.com/catherinedevlin .. _@ccurvey: https://github.com/ccurvey diff --git a/hooks/pre_gen_project.py b/hooks/pre_gen_project.py index 91332f144..7f9bd3eac 100644 --- a/hooks/pre_gen_project.py +++ b/hooks/pre_gen_project.py @@ -59,3 +59,12 @@ if "{{ cookiecutter.use_docker }}".lower() == "n": ) + 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) diff --git a/requirements.txt b/requirements.txt index f4d12375d..e9d2afb2f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,8 +10,8 @@ flake8==3.7.8 # Testing # ------------------------------------------------------------------------------ tox==3.14.0 -pytest==5.1.2 -pytest_cases==1.11.2 +pytest==5.2.0 +pytest_cases==1.11.3 pytest-cookies==0.4.0 -pytest-xdist==1.29.0 +pytest-xdist==1.30.0 pyyaml==5.1.2 diff --git a/tests/test_cookiecutter_generation.py b/tests/test_cookiecutter_generation.py index 77f71df5b..20e4f9ed2 100755 --- a/tests/test_cookiecutter_generation.py +++ b/tests/test_cookiecutter_generation.py @@ -49,6 +49,11 @@ def context_combination( cloud_provider, ): """Fixture that parametrize the function where it's used.""" + if cloud_provider == "None": + # Either of the two should be set for serving static files, so if cloud provider + # is not set, we force Whitenoise to be set + use_whitenoise = "y" + return { "windows": windows, "use_docker": use_docker, @@ -157,3 +162,12 @@ def test_invalid_slug(cookies, context, slug): assert result.exit_code != 0 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) diff --git a/{{cookiecutter.project_slug}}/config/settings/base.py b/{{cookiecutter.project_slug}}/config/settings/base.py index 776e03315..292c1729d 100644 --- a/{{cookiecutter.project_slug}}/config/settings/base.py +++ b/{{cookiecutter.project_slug}}/config/settings/base.py @@ -205,6 +205,7 @@ TEMPLATES = [ "django.template.context_processors.static", "django.template.context_processors.tz", "django.contrib.messages.context_processors.messages", + "{{ cookiecutter.project_slug }}.utils.context_processors.settings_context", ], }, } diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index e37411653..7a5d5454d 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -92,7 +92,6 @@ AWS_DEFAULT_ACL = None # https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings AWS_S3_REGION_NAME = env("DJANGO_AWS_S3_REGION_NAME", default=None) {% elif cookiecutter.cloud_provider == 'GCP' %} -DEFAULT_FILE_STORAGE = "storages.backends.gcloud.GoogleCloudStorage" GS_BUCKET_NAME = env("DJANGO_GCP_STORAGE_BUCKET_NAME") GS_DEFAULT_ACL = "publicRead" {% endif -%} @@ -107,6 +106,7 @@ STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" STATICFILES_STORAGE = "config.settings.production.StaticRootS3Boto3Storage" STATIC_URL = f"https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/static/" {% elif cookiecutter.cloud_provider == 'GCP' -%} +STATICFILES_STORAGE = "config.settings.production.StaticRootGoogleCloudStorage" STATIC_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/static/" {% endif -%} @@ -132,8 +132,21 @@ class MediaRootS3Boto3Storage(S3Boto3Storage): DEFAULT_FILE_STORAGE = "config.settings.production.MediaRootS3Boto3Storage" MEDIA_URL = f"https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/media/" {%- 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_ROOT = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/media/" {%- endif %} # TEMPLATES diff --git a/{{cookiecutter.project_slug}}/requirements/base.txt b/{{cookiecutter.project_slug}}/requirements/base.txt index 9e1658f20..980380838 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -1,12 +1,12 @@ pytz==2019.2 # https://github.com/stub42/pytz -python-slugify==3.0.3 # https://github.com/un33k/python-slugify -Pillow==6.1.0 # https://github.com/python-pillow/Pillow +python-slugify==3.0.4 # https://github.com/un33k/python-slugify +Pillow==6.2.0 # https://github.com/python-pillow/Pillow {%- 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 {%- endif %} argon2-cffi==19.1.0 # https://github.com/hynek/argon2_cffi {%- if cookiecutter.use_whitenoise == 'y' %} -whitenoise==4.1.3 # https://github.com/evansd/whitenoise +whitenoise==4.1.4 # https://github.com/evansd/whitenoise {%- endif %} redis==3.3.8 # https://github.com/antirez/redis {%- if cookiecutter.use_celery == "y" %} @@ -19,7 +19,7 @@ flower==0.9.3 # https://github.com/mher/flower # Django # ------------------------------------------------------------------------------ -django==2.2.5 # pyup: < 3.0 # https://www.djangoproject.com/ +django==2.2.6 # pyup: < 3.0 # https://www.djangoproject.com/ 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-allauth==0.40.0 # https://github.com/pennersr/django-allauth diff --git a/{{cookiecutter.project_slug}}/requirements/local.txt b/{{cookiecutter.project_slug}}/requirements/local.txt index c1df0b84b..41813c475 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -11,8 +11,8 @@ psycopg2-binary==2.8.3 # https://github.com/psycopg/psycopg2 # Testing # ------------------------------------------------------------------------------ -mypy==0.720 # https://github.com/python/mypy -pytest==5.1.2 # https://github.com/pytest-dev/pytest +mypy==0.730 # https://github.com/python/mypy +pytest==5.2.0 # https://github.com/pytest-dev/pytest pytest-sugar==0.9.2 # https://github.com/Frozenball/pytest-sugar # Code quality @@ -30,6 +30,6 @@ pylint-celery==0.3 # https://github.com/PyCQA/pylint-celery factory-boy==2.12.0 # https://github.com/FactoryBoy/factory_boy django-debug-toolbar==2.0 # https://github.com/jazzband/django-debug-toolbar -django-extensions==2.2.1 # https://github.com/django-extensions/django-extensions +django-extensions==2.2.3 # https://github.com/django-extensions/django-extensions django-coverage-plugin==1.6.0 # https://github.com/nedbat/django_coverage_plugin pytest-django==3.5.1 # https://github.com/pytest-dev/pytest-django diff --git a/{{cookiecutter.project_slug}}/requirements/production.txt b/{{cookiecutter.project_slug}}/requirements/production.txt index 1714398f4..fae99a3f8 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -5,17 +5,17 @@ gunicorn==19.9.0 # https://github.com/benoitc/gunicorn psycopg2==2.8.3 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 {%- if cookiecutter.use_whitenoise == 'n' %} -Collectfast==1.0.0 # https://github.com/antonagestam/collectfast +Collectfast==1.1.0 # https://github.com/antonagestam/collectfast {%- endif %} {%- if cookiecutter.use_sentry == "y" %} -sentry-sdk==0.11.2 # https://github.com/getsentry/sentry-python +sentry-sdk==0.12.3 # https://github.com/getsentry/sentry-python {%- endif %} # Django # ------------------------------------------------------------------------------ {%- if cookiecutter.cloud_provider == 'AWS' %} -django-storages[boto3]==1.7.1 # https://github.com/jschneier/django-storages +django-storages[boto3]==1.7.2 # https://github.com/jschneier/django-storages {%- elif cookiecutter.cloud_provider == 'GCP' %} -django-storages[google]==1.7.1 # https://github.com/jschneier/django-storages +django-storages[google]==1.7.2 # https://github.com/jschneier/django-storages {%- 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 diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/utils/__init__.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/utils/context_processors.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/utils/context_processors.py new file mode 100644 index 000000000..de405076f --- /dev/null +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/utils/context_processors.py @@ -0,0 +1,5 @@ +from django.conf import settings + + +def settings_context(_request): + return {"settings": settings}