diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index e3569e78..dc41463f 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -57,6 +57,7 @@ Listed in alphabetical order. Andrew Mikhnevich `@zcho`_ Andy Rose Anna Callahan `@jazztpt`_ + Anna Sidwell `@takkaria`_ Antonia Blair `@antoniablair`_ @antoniablairart Anuj Bansal `@ahhda`_ Arcuri Davide `@dadokkio`_ @@ -70,6 +71,7 @@ Listed in alphabetical order. Bo Lopker `@blopker`_ Bouke Haarsma Brent Payne `@brentpayne`_ @brentpayne + Bartek `@btknu` Burhan Khalid            `@burhan`_                   @burhan Carl Johnson `@carlmjohnson`_ @carlmjohnson Catherine Devlin `@catherinedevlin`_ @@ -179,6 +181,7 @@ Listed in alphabetical order. Denis Bobrov `@delneg`_ Philipp Matthies `@canonnervio`_ Vadim Iskuchekov `@Egregors`_ @egregors + Keith Bailey `@keithjeb`_ ========================== ============================ ============== .. _@a7p: https://github.com/a7p @@ -271,6 +274,7 @@ Listed in alphabetical order. .. _@ssteinerX: https://github.com/ssteinerx .. _@stepmr: https://github.com/stepmr .. _@suledev: https://github.com/suledev +.. _@takkaria: https://github.com/takkaria .. _@timfreund: https://github.com/timfreund .. _@Travistock: https://github.com/Tavistock .. _@trungdong: https://github.com/trungdong @@ -295,6 +299,8 @@ Listed in alphabetical order. .. _@purplediane: https://github.com/purplediane .. _@umrashrf: https://github.com/umrashrf .. _@ahhda: https://github.com/ahhda +.. _@keithjeb: https://github.com/keithjeb +.. _@btknu: https://github.com/btknu Special Thanks ~~~~~~~~~~~~~~ diff --git a/docs/developing-locally-docker.rst b/docs/developing-locally-docker.rst index 08b25f3b..895140f9 100644 --- a/docs/developing-locally-docker.rst +++ b/docs/developing-locally-docker.rst @@ -171,6 +171,16 @@ When developing locally you can go with MailHog_ for email testing provided ``us .. _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`: diff --git a/docs/developing-locally.rst b/docs/developing-locally.rst index 09c5db39..3434f68b 100644 --- a/docs/developing-locally.rst +++ b/docs/developing-locally.rst @@ -118,6 +118,16 @@ In production, we have Mailgun_ configured to have your back! .. _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 --------------------------------- diff --git a/requirements.txt b/requirements.txt index 1fd7fe7c..37a96913 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,10 +4,11 @@ binaryornot==0.4.4 # Code quality # ------------------------------------------------------------------------------ -flake8==3.7.5 +flake8==3.7.6 # Testing # ------------------------------------------------------------------------------ tox==3.6.1 -pytest==4.2.0 +pytest==4.3.0 pytest-cookies==0.3.0 +pyyaml==3.13 diff --git a/tests/test_cookiecutter_generation.py b/tests/test_cookiecutter_generation.py index cf173576..b2c235a8 100755 --- a/tests/test_cookiecutter_generation.py +++ b/tests/test_cookiecutter_generation.py @@ -1,6 +1,7 @@ import os import re import sh +import yaml import pytest from binaryornot.check import is_binary @@ -85,3 +86,19 @@ def test_flake8_compliance(cookies): sh.flake8(str(result.project)) except sh.ErrorReturnCode as 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) diff --git a/{{cookiecutter.project_slug}}/.travis.yml b/{{cookiecutter.project_slug}}/.travis.yml index 5ca54d00..3072f75f 100644 --- a/{{cookiecutter.project_slug}}/.travis.yml +++ b/{{cookiecutter.project_slug}}/.travis.yml @@ -9,3 +9,7 @@ before_install: language: python python: - "3.6" +install: + - pip install -r requirements/local.txt +script: + - "pytest" diff --git a/{{cookiecutter.project_slug}}/config/settings/local.py b/{{cookiecutter.project_slug}}/config/settings/local.py index 741f324a..6667a265 100644 --- a/{{cookiecutter.project_slug}}/config/settings/local.py +++ b/{{cookiecutter.project_slug}}/config/settings/local.py @@ -76,8 +76,10 @@ INSTALLED_APPS += ['django_extensions'] # noqa F405 # Celery # ------------------------------------------------------------------------------ +{% if cookiecutter.use_docker == 'n' -%} # http://docs.celeryproject.org/en/latest/userguide/configuration.html#task-always-eager CELERY_TASK_ALWAYS_EAGER = True +{%- endif %} # http://docs.celeryproject.org/en/latest/userguide/configuration.html#task-eager-propagates CELERY_TASK_EAGER_PROPAGATES = True diff --git a/{{cookiecutter.project_slug}}/gulpfile.js b/{{cookiecutter.project_slug}}/gulpfile.js index bb18a535..d92678ed 100644 --- a/{{cookiecutter.project_slug}}/gulpfile.js +++ b/{{cookiecutter.project_slug}}/gulpfile.js @@ -1,63 +1,70 @@ +//////////////////////////////// +// Setup +//////////////////////////////// -//////////////////////////////// - //Setup// -//////////////////////////////// +// Gulp and package +const { src, dest, parallel, series, watch } = require('gulp') +const pjson = require('./package.json') // Plugins -var gulp = require('gulp'), - pjson = require('./package.json'), - gutil = require('gulp-util'), - sass = require('gulp-sass'), - autoprefixer = require('gulp-autoprefixer'), - cssnano = require('gulp-cssnano'), - {% if cookiecutter.custom_bootstrap_compilation == 'y' %} - concat = require('gulp-concat'), - {% endif %} - rename = require('gulp-rename'), - del = require('del'), - plumber = require('gulp-plumber'), - pixrem = require('gulp-pixrem'), - uglify = require('gulp-uglify'), - imagemin = require('gulp-imagemin'), - spawn = require('child_process').spawn, - runSequence = require('run-sequence'), - browserSync = require('browser-sync').create(), - reload = browserSync.reload; - +const autoprefixer = require('autoprefixer') +const browserSync = require('browser-sync').create() +{% if cookiecutter.custom_bootstrap_compilation == 'y' %} +const concat = require('gulp-concat') +{% endif %} +const cssnano = require ('cssnano') +const imagemin = require('gulp-imagemin') +const pixrem = require('pixrem') +const plumber = require('gulp-plumber') +const postcss = require('gulp-postcss') +const reload = browserSync.reload +const rename = require('gulp-rename') +const sass = require('gulp-sass') +const spawn = require('child_process').spawn +const uglify = require('gulp-uglify-es').default // Relative paths function -var pathsConfig = function (appName) { - this.app = "./" + (appName || pjson.name); - var vendorsRoot = 'node_modules/'; +function pathsConfig(appName) { + this.app = `./${pjson.name}` + const vendorsRoot = 'node_modules' return { {% if cookiecutter.custom_bootstrap_compilation == 'y' %} - bootstrapSass: vendorsRoot + '/bootstrap/scss', + bootstrapSass: `${vendorsRoot}/bootstrap/scss`, vendorsJs: [ - vendorsRoot + 'jquery/dist/jquery.slim.js', - vendorsRoot + 'popper.js/dist/umd/popper.js', - vendorsRoot + 'bootstrap/dist/js/bootstrap.js' + `${vendorsRoot}/jquery/dist/jquery.slim.js`, + `${vendorsRoot}/popper.js/dist/umd/popper.js`, + `${vendorsRoot}/bootstrap/dist/js/bootstrap.js`, ], {% endif %} app: this.app, - templates: this.app + '/templates', - css: this.app + '/static/css', - sass: this.app + '/static/sass', - fonts: this.app + '/static/fonts', - images: this.app + '/static/images', - js: this.app + '/static/js' + templates: `${this.app}/templates`, + css: `${this.app}/static/css`, + sass: `${this.app}/static/sass`, + fonts: `${this.app}/static/fonts`, + images: `${this.app}/static/images`, + js: `${this.app}/static/js`, } -}; +} -var paths = pathsConfig(); +var paths = pathsConfig() //////////////////////////////// - //Tasks// +// Tasks //////////////////////////////// // Styles autoprefixing and minification -gulp.task('styles', function() { - return gulp.src(paths.sass + '/project.scss') +function styles() { + 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({ includePaths: [ {% if cookiecutter.custom_bootstrap_compilation == 'y' %} @@ -67,72 +74,86 @@ gulp.task('styles', function() { ] }).on('error', sass.logError)) .pipe(plumber()) // Checks for errors - .pipe(autoprefixer({browsers: ['last 2 versions']})) // Adds vendor prefixes - .pipe(pixrem()) // add fallbacks for rem units - .pipe(gulp.dest(paths.css)) + .pipe(postcss(processCss)) + .pipe(dest(paths.css)) .pipe(rename({ suffix: '.min' })) - .pipe(cssnano()) // Minifies the result - .pipe(gulp.dest(paths.css)); -}); + .pipe(postcss(minifyCss)) // Minifies the result + .pipe(dest(paths.css)) +} // Javascript minification -gulp.task('scripts', function() { - return gulp.src(paths.js + '/project.js') +function scripts() { + return src(`${paths.js}/project.js`) .pipe(plumber()) // Checks for errors .pipe(uglify()) // Minifies the js .pipe(rename({ suffix: '.min' })) - .pipe(gulp.dest(paths.js)); -}); - + .pipe(dest(paths.js)) +} {% if cookiecutter.custom_bootstrap_compilation == 'y' %} // Vendor Javascript minification -gulp.task('vendor-scripts', function() { - return gulp.src(paths.vendorsJs) +function vendorScripts() { + return src(paths.vendorsJs) .pipe(concat('vendors.js')) - .pipe(gulp.dest(paths.js)) + .pipe(dest(paths.js)) .pipe(plumber()) // Checks for errors .pipe(uglify()) // Minifies the js .pipe(rename({ suffix: '.min' })) - .pipe(gulp.dest(paths.js)); -}); + .pipe(dest(paths.js)) +} {% endif %} // Image compression -gulp.task('imgCompression', function(){ - return gulp.src(paths.images + '/*') +function imgCompression() { + return src(`${paths.images}/*`) .pipe(imagemin()) // Compresses PNG, JPEG, GIF and SVG images - .pipe(gulp.dest(paths.images)) -}); + .pipe(dest(paths.images)) +} // Run django server -gulp.task('runServer', function(cb) { - var cmd = spawn('python', ['manage.py', 'runserver'], {stdio: 'inherit'}); +function runServer(cb) { + var cmd = spawn('python', ['manage.py', 'runserver'], {stdio: 'inherit'}) cmd.on('close', function(code) { - console.log('runServer exited with code ' + code); - cb(code); - }); -}); + console.log('runServer exited with code ' + code) + cb(code) + }) +} // Browser sync server for live reload -gulp.task('browserSync', function() { +function initBrowserSync() { 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 -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']); - gulp.watch(paths.js + '/*.js', ['scripts']).on("change", reload); - gulp.watch(paths.images + '/*', ['imgCompression']); - gulp.watch(paths.templates + '/**/*.html').on("change", reload); +// Generate all assets +const generateAssets = parallel( + styles, + scripts, + {% if cookiecutter.custom_bootstrap_compilation == 'y' %}vendorScripts,{% endif %} + imgCompression +) -}); +// Set up dev environment +const dev = parallel( + runServer, + initBrowserSync, + watchPaths +) -// Default task -gulp.task('default', function() { - runSequence(['styles', 'scripts', {% if cookiecutter.custom_bootstrap_compilation == 'y' %}'vendor-scripts', {% endif %}'imgCompression'], ['runServer', 'browserSync', 'watch']); -}); +exports.default = series(generateAssets, dev) +exports["generate-assets"] = generateAssets +exports["dev"] = dev diff --git a/{{cookiecutter.project_slug}}/package.json b/{{cookiecutter.project_slug}}/package.json index b29d5296..a15df941 100644 --- a/{{cookiecutter.project_slug}}/package.json +++ b/{{cookiecutter.project_slug}}/package.json @@ -6,32 +6,29 @@ {% if cookiecutter.js_task_runner == 'Gulp' -%} {% if cookiecutter.custom_bootstrap_compilation == 'y' -%} "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", - {% 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", "popper.js": "1.14.3", {% 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 %} }, "engines": { - "node": ">=0.8.0" + "node": ">=8" }, + "browserslist": [ + "last 2 versions" + ], "scripts": { {% if cookiecutter.js_task_runner == 'Gulp' -%} "dev": "gulp" diff --git a/{{cookiecutter.project_slug}}/requirements/base.txt b/{{cookiecutter.project_slug}}/requirements/base.txt index 09ca8ddd..e43b70af 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -18,7 +18,7 @@ flower==0.9.2 # https://github.com/mher/flower # 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-model-utils==3.1.2 # https://github.com/jazzband/django-model-utils django-allauth==0.38.0 # https://github.com/pennersr/django-allauth