Merge commit '6e72169ffe3022b54db3d44297226226cf86c1e8'

This commit is contained in:
Trung Dong Huynh 2019-03-09 14:22:47 +00:00
commit a7079a8b13
10 changed files with 171 additions and 103 deletions

View File

@ -57,6 +57,7 @@ Listed in alphabetical order.
Andrew Mikhnevich `@zcho`_ Andrew Mikhnevich `@zcho`_
Andy Rose Andy Rose
Anna Callahan `@jazztpt`_ Anna Callahan `@jazztpt`_
Anna Sidwell `@takkaria`_
Antonia Blair `@antoniablair`_ @antoniablairart Antonia Blair `@antoniablair`_ @antoniablairart
Anuj Bansal `@ahhda`_ Anuj Bansal `@ahhda`_
Arcuri Davide `@dadokkio`_ Arcuri Davide `@dadokkio`_
@ -70,6 +71,7 @@ Listed in alphabetical order.
Bo Lopker `@blopker`_ Bo Lopker `@blopker`_
Bouke Haarsma Bouke Haarsma
Brent Payne `@brentpayne`_ @brentpayne Brent Payne `@brentpayne`_ @brentpayne
Bartek `@btknu`
Burhan Khalid            `@burhan`_                   @burhan Burhan Khalid            `@burhan`_                   @burhan
Carl Johnson `@carlmjohnson`_ @carlmjohnson Carl Johnson `@carlmjohnson`_ @carlmjohnson
Catherine Devlin `@catherinedevlin`_ Catherine Devlin `@catherinedevlin`_
@ -179,6 +181,7 @@ Listed in alphabetical order.
Denis Bobrov `@delneg`_ Denis Bobrov `@delneg`_
Philipp Matthies `@canonnervio`_ Philipp Matthies `@canonnervio`_
Vadim Iskuchekov `@Egregors`_ @egregors Vadim Iskuchekov `@Egregors`_ @egregors
Keith Bailey `@keithjeb`_
========================== ============================ ============== ========================== ============================ ==============
.. _@a7p: https://github.com/a7p .. _@a7p: https://github.com/a7p
@ -271,6 +274,7 @@ Listed in alphabetical order.
.. _@ssteinerX: https://github.com/ssteinerx .. _@ssteinerX: https://github.com/ssteinerx
.. _@stepmr: https://github.com/stepmr .. _@stepmr: https://github.com/stepmr
.. _@suledev: https://github.com/suledev .. _@suledev: https://github.com/suledev
.. _@takkaria: https://github.com/takkaria
.. _@timfreund: https://github.com/timfreund .. _@timfreund: https://github.com/timfreund
.. _@Travistock: https://github.com/Tavistock .. _@Travistock: https://github.com/Tavistock
.. _@trungdong: https://github.com/trungdong .. _@trungdong: https://github.com/trungdong
@ -295,6 +299,8 @@ Listed in alphabetical order.
.. _@purplediane: https://github.com/purplediane .. _@purplediane: https://github.com/purplediane
.. _@umrashrf: https://github.com/umrashrf .. _@umrashrf: https://github.com/umrashrf
.. _@ahhda: https://github.com/ahhda .. _@ahhda: https://github.com/ahhda
.. _@keithjeb: https://github.com/keithjeb
.. _@btknu: https://github.com/btknu
Special Thanks Special Thanks
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~

View File

@ -171,6 +171,16 @@ When developing locally you can go with MailHog_ for email testing provided ``us
.. _Mailhog: https://github.com/mailhog/MailHog/ .. _Mailhog: https://github.com/mailhog/MailHog/
.. _`CeleryTasks`:
Celery tasks in local development
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When not using docker Celery tasks are set to run in Eager mode, so that a full stack is not needed. When using docker the task
scheduler will be used by default.
If you need tasks to be executed on the main thread during development set CELERY_TASK_ALWAYS_EAGER = True in config/settings/local.py.
Possible uses could be for testing, or ease of profiling with DJDT.
.. _`CeleryFlower`: .. _`CeleryFlower`:

View File

@ -118,6 +118,16 @@ In production, we have Mailgun_ configured to have your back!
.. _Mailgun: https://www.mailgun.com/ .. _Mailgun: https://www.mailgun.com/
Celery
------
If the project is configured to use Celery as a task scheduler then by default tasks are set to run on the main thread
when developing locally. If you have the appropriate setup on your local machine then set
CELERY_TASK_ALWAYS_EAGER = False
in /config/settings/local.py
Sass Compilation & Live Reloading Sass Compilation & Live Reloading
--------------------------------- ---------------------------------

View File

@ -4,10 +4,11 @@ binaryornot==0.4.4
# Code quality # Code quality
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
flake8==3.7.5 flake8==3.7.6
# Testing # Testing
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
tox==3.6.1 tox==3.6.1
pytest==4.2.0 pytest==4.3.0
pytest-cookies==0.3.0 pytest-cookies==0.3.0
pyyaml==3.13

View File

@ -1,6 +1,7 @@
import os import os
import re import re
import sh import sh
import yaml
import pytest import pytest
from binaryornot.check import is_binary from binaryornot.check import is_binary
@ -85,3 +86,19 @@ def test_flake8_compliance(cookies):
sh.flake8(str(result.project)) sh.flake8(str(result.project))
except sh.ErrorReturnCode as e: except sh.ErrorReturnCode as e:
pytest.fail(e) pytest.fail(e)
def test_travis_invokes_pytest(cookies, context):
context.update({"use_travisci": "y"})
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}/.travis.yml', 'r') as travis_yml:
try:
assert yaml.load(travis_yml)['script'] == ['pytest']
except yaml.YAMLError as e:
pytest.fail(e)

View File

@ -9,3 +9,7 @@ before_install:
language: python language: python
python: python:
- "3.6" - "3.6"
install:
- pip install -r requirements/local.txt
script:
- "pytest"

View File

@ -76,8 +76,10 @@ INSTALLED_APPS += ['django_extensions'] # noqa F405
# Celery # Celery
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
{% if cookiecutter.use_docker == 'n' -%}
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#task-always-eager # http://docs.celeryproject.org/en/latest/userguide/configuration.html#task-always-eager
CELERY_TASK_ALWAYS_EAGER = True CELERY_TASK_ALWAYS_EAGER = True
{%- endif %}
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#task-eager-propagates # http://docs.celeryproject.org/en/latest/userguide/configuration.html#task-eager-propagates
CELERY_TASK_EAGER_PROPAGATES = True CELERY_TASK_EAGER_PROPAGATES = True

View File

@ -1,63 +1,70 @@
////////////////////////////////
// Setup
////////////////////////////////
//////////////////////////////// // Gulp and package
//Setup// const { src, dest, parallel, series, watch } = require('gulp')
//////////////////////////////// const pjson = require('./package.json')
// Plugins // Plugins
var gulp = require('gulp'), const autoprefixer = require('autoprefixer')
pjson = require('./package.json'), const browserSync = require('browser-sync').create()
gutil = require('gulp-util'), {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
sass = require('gulp-sass'), const concat = require('gulp-concat')
autoprefixer = require('gulp-autoprefixer'), {% endif %}
cssnano = require('gulp-cssnano'), const cssnano = require ('cssnano')
{% if cookiecutter.custom_bootstrap_compilation == 'y' %} const imagemin = require('gulp-imagemin')
concat = require('gulp-concat'), const pixrem = require('pixrem')
{% endif %} const plumber = require('gulp-plumber')
rename = require('gulp-rename'), const postcss = require('gulp-postcss')
del = require('del'), const reload = browserSync.reload
plumber = require('gulp-plumber'), const rename = require('gulp-rename')
pixrem = require('gulp-pixrem'), const sass = require('gulp-sass')
uglify = require('gulp-uglify'), const spawn = require('child_process').spawn
imagemin = require('gulp-imagemin'), const uglify = require('gulp-uglify-es').default
spawn = require('child_process').spawn,
runSequence = require('run-sequence'),
browserSync = require('browser-sync').create(),
reload = browserSync.reload;
// Relative paths function // Relative paths function
var pathsConfig = function (appName) { function pathsConfig(appName) {
this.app = "./" + (appName || pjson.name); this.app = `./${pjson.name}`
var vendorsRoot = 'node_modules/'; const vendorsRoot = 'node_modules'
return { return {
{% if cookiecutter.custom_bootstrap_compilation == 'y' %} {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
bootstrapSass: vendorsRoot + '/bootstrap/scss', bootstrapSass: `${vendorsRoot}/bootstrap/scss`,
vendorsJs: [ vendorsJs: [
vendorsRoot + 'jquery/dist/jquery.slim.js', `${vendorsRoot}/jquery/dist/jquery.slim.js`,
vendorsRoot + 'popper.js/dist/umd/popper.js', `${vendorsRoot}/popper.js/dist/umd/popper.js`,
vendorsRoot + 'bootstrap/dist/js/bootstrap.js' `${vendorsRoot}/bootstrap/dist/js/bootstrap.js`,
], ],
{% endif %} {% endif %}
app: this.app, app: this.app,
templates: this.app + '/templates', templates: `${this.app}/templates`,
css: this.app + '/static/css', css: `${this.app}/static/css`,
sass: this.app + '/static/sass', sass: `${this.app}/static/sass`,
fonts: this.app + '/static/fonts', fonts: `${this.app}/static/fonts`,
images: this.app + '/static/images', images: `${this.app}/static/images`,
js: this.app + '/static/js' js: `${this.app}/static/js`,
} }
}; }
var paths = pathsConfig(); var paths = pathsConfig()
//////////////////////////////// ////////////////////////////////
//Tasks// // Tasks
//////////////////////////////// ////////////////////////////////
// Styles autoprefixing and minification // Styles autoprefixing and minification
gulp.task('styles', function() { function styles() {
return gulp.src(paths.sass + '/project.scss') var processCss = [
autoprefixer(), // adds vendor prefixes
pixrem(), // add fallbacks for rem units
]
var minifyCss = [
cssnano({ preset: 'default' }) // minify result
]
return src(`${paths.sass}/project.scss`)
.pipe(sass({ .pipe(sass({
includePaths: [ includePaths: [
{% if cookiecutter.custom_bootstrap_compilation == 'y' %} {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
@ -67,72 +74,86 @@ gulp.task('styles', function() {
] ]
}).on('error', sass.logError)) }).on('error', sass.logError))
.pipe(plumber()) // Checks for errors .pipe(plumber()) // Checks for errors
.pipe(autoprefixer({browsers: ['last 2 versions']})) // Adds vendor prefixes .pipe(postcss(processCss))
.pipe(pixrem()) // add fallbacks for rem units .pipe(dest(paths.css))
.pipe(gulp.dest(paths.css))
.pipe(rename({ suffix: '.min' })) .pipe(rename({ suffix: '.min' }))
.pipe(cssnano()) // Minifies the result .pipe(postcss(minifyCss)) // Minifies the result
.pipe(gulp.dest(paths.css)); .pipe(dest(paths.css))
}); }
// Javascript minification // Javascript minification
gulp.task('scripts', function() { function scripts() {
return gulp.src(paths.js + '/project.js') return src(`${paths.js}/project.js`)
.pipe(plumber()) // Checks for errors .pipe(plumber()) // Checks for errors
.pipe(uglify()) // Minifies the js .pipe(uglify()) // Minifies the js
.pipe(rename({ suffix: '.min' })) .pipe(rename({ suffix: '.min' }))
.pipe(gulp.dest(paths.js)); .pipe(dest(paths.js))
}); }
{% if cookiecutter.custom_bootstrap_compilation == 'y' %} {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
// Vendor Javascript minification // Vendor Javascript minification
gulp.task('vendor-scripts', function() { function vendorScripts() {
return gulp.src(paths.vendorsJs) return src(paths.vendorsJs)
.pipe(concat('vendors.js')) .pipe(concat('vendors.js'))
.pipe(gulp.dest(paths.js)) .pipe(dest(paths.js))
.pipe(plumber()) // Checks for errors .pipe(plumber()) // Checks for errors
.pipe(uglify()) // Minifies the js .pipe(uglify()) // Minifies the js
.pipe(rename({ suffix: '.min' })) .pipe(rename({ suffix: '.min' }))
.pipe(gulp.dest(paths.js)); .pipe(dest(paths.js))
}); }
{% endif %} {% endif %}
// Image compression // Image compression
gulp.task('imgCompression', function(){ function imgCompression() {
return gulp.src(paths.images + '/*') return src(`${paths.images}/*`)
.pipe(imagemin()) // Compresses PNG, JPEG, GIF and SVG images .pipe(imagemin()) // Compresses PNG, JPEG, GIF and SVG images
.pipe(gulp.dest(paths.images)) .pipe(dest(paths.images))
}); }
// Run django server // Run django server
gulp.task('runServer', function(cb) { function runServer(cb) {
var cmd = spawn('python', ['manage.py', 'runserver'], {stdio: 'inherit'}); var cmd = spawn('python', ['manage.py', 'runserver'], {stdio: 'inherit'})
cmd.on('close', function(code) { cmd.on('close', function(code) {
console.log('runServer exited with code ' + code); console.log('runServer exited with code ' + code)
cb(code); cb(code)
}); })
}); }
// Browser sync server for live reload // Browser sync server for live reload
gulp.task('browserSync', function() { function initBrowserSync() {
browserSync.init( browserSync.init(
[paths.css + "/*.css", paths.js + "*.js", paths.templates + '*.html'], { [
proxy: "localhost:8000" `${paths.css}/*.css`,
}); `${paths.js}/*.js`,
}); `${paths.templates}/*.html`
], {
proxy: "localhost:8000"
}
)
}
// Watch // Watch
gulp.task('watch', function() { function watchPaths() {
watch(`${paths.sass}/*.scss`, styles)
watch(`${paths.templates}/**/*.html`).on("change", reload)
watch([`${paths.js}/*.js`, `!${paths.js}/*.min.js`], scripts).on("change", reload)
}
gulp.watch(paths.sass + '/*.scss', ['styles']); // Generate all assets
gulp.watch(paths.js + '/*.js', ['scripts']).on("change", reload); const generateAssets = parallel(
gulp.watch(paths.images + '/*', ['imgCompression']); styles,
gulp.watch(paths.templates + '/**/*.html').on("change", reload); scripts,
{% if cookiecutter.custom_bootstrap_compilation == 'y' %}vendorScripts,{% endif %}
imgCompression
)
}); // Set up dev environment
const dev = parallel(
runServer,
initBrowserSync,
watchPaths
)
// Default task exports.default = series(generateAssets, dev)
gulp.task('default', function() { exports["generate-assets"] = generateAssets
runSequence(['styles', 'scripts', {% if cookiecutter.custom_bootstrap_compilation == 'y' %}'vendor-scripts', {% endif %}'imgCompression'], ['runServer', 'browserSync', 'watch']); exports["dev"] = dev
});

View File

@ -6,32 +6,29 @@
{% if cookiecutter.js_task_runner == 'Gulp' -%} {% if cookiecutter.js_task_runner == 'Gulp' -%}
{% if cookiecutter.custom_bootstrap_compilation == 'y' -%} {% if cookiecutter.custom_bootstrap_compilation == 'y' -%}
"bootstrap": "4.1.1", "bootstrap": "4.1.1",
{% endif -%}
"browser-sync": "^2.14.0",
"del": "^2.2.2",
"gulp": "^3.9.1",
"gulp-autoprefixer": "^5.0.0",
{% if cookiecutter.custom_bootstrap_compilation == 'y' -%}
"gulp-concat": "^2.6.1", "gulp-concat": "^2.6.1",
{% endif -%}
"gulp-cssnano": "^2.1.2",
"gulp-imagemin": "^4.1.0",
"gulp-pixrem": "^1.0.0",
"gulp-plumber": "^1.1.0",
"gulp-rename": "^1.2.2",
"gulp-sass": "^3.1.0",
"gulp-uglify": "^3.0.0",
"gulp-util": "^3.0.7",
{% if cookiecutter.custom_bootstrap_compilation == 'y' -%}
"jquery": "3.3.1", "jquery": "3.3.1",
"popper.js": "1.14.3", "popper.js": "1.14.3",
{% endif -%} {% endif -%}
"run-sequence": "^2.1.1" "autoprefixer": "^9.4.7",
"browser-sync": "^2.14.0",
"cssnano": "^4.1.10",
"gulp": "^4.0.0",
"gulp-imagemin": "^5.0.3",
"gulp-plumber": "^1.2.1",
"gulp-postcss": "^8.0.0",
"gulp-rename": "^1.2.2",
"gulp-sass": "^4.0.2",
"gulp-uglify-es": "^1.0.4",
"pixrem": "^5.0.0"
{%- endif %} {%- endif %}
}, },
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=8"
}, },
"browserslist": [
"last 2 versions"
],
"scripts": { "scripts": {
{% if cookiecutter.js_task_runner == 'Gulp' -%} {% if cookiecutter.js_task_runner == 'Gulp' -%}
"dev": "gulp" "dev": "gulp"

View File

@ -18,7 +18,7 @@ flower==0.9.2 # https://github.com/mher/flower
# Django # Django
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
django==2.0.10 # pyup: < 2.1 # https://www.djangoproject.com/ django==2.0.13 # pyup: < 2.1 # 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.1.2 # https://github.com/jazzband/django-model-utils django-model-utils==3.1.2 # https://github.com/jazzband/django-model-utils
django-allauth==0.38.0 # https://github.com/pennersr/django-allauth django-allauth==0.38.0 # https://github.com/pennersr/django-allauth