diff --git a/plugins/app-json/appjson.go b/plugins/app-json/appjson.go index 03525c2c9..cc5109695 100644 --- a/plugins/app-json/appjson.go +++ b/plugins/app-json/appjson.go @@ -3,12 +3,14 @@ package appjson import ( "bytes" "encoding/json" + "errors" "fmt" "io/ioutil" "os" "strings" "github.com/dokku/dokku/plugins/common" + shellquote "github.com/kballard/go-shellquote" ) type AppJson struct { @@ -133,7 +135,7 @@ func executeScript(appName string, imageTag string, phase string) error { return nil } - common.LogInfo1(fmt.Sprintf("Executing %s command from %s: %s", phase, phaseSource, command)) + common.LogInfo1(fmt.Sprintf("Executing %s task from %s: %s", phase, phaseSource, command)) isHerokuishImage := common.IsImageHerokuishBased(image, appName) script := constructScript(command, isHerokuishImage) @@ -149,12 +151,22 @@ func executeScript(appName string, imageTag string, phase string) error { } var dockerArgs []string - if b, err := common.PlugnTriggerSetup("docker-args-deploy", []string{appName, imageTag}...).SetInput("").Output(); err != nil { - dockerArgs = append(dockerArgs, strings.Split(strings.TrimSpace(string(b[:])), "\n")...) + if b, err := common.PlugnTriggerSetup("docker-args-deploy", []string{appName, imageTag}...).SetInput("").Output(); err == nil { + words, err := shellquote.Split(strings.TrimSpace(string(b[:]))) + if err != nil { + return err + } + + dockerArgs = append(dockerArgs, words...) } - if b, err := common.PlugnTriggerSetup("docker-args-process-deploy", []string{appName, imageSourceType, imageTag}...).SetInput("").Output(); err != nil { - dockerArgs = append(dockerArgs, strings.Split(strings.TrimSpace(string(b[:])), "\n")...) + if b, err := common.PlugnTriggerSetup("docker-args-process-deploy", []string{appName, imageSourceType, imageTag}...).SetInput("").Output(); err == nil { + words, err := shellquote.Split(strings.TrimSpace(string(b[:]))) + if err != nil { + return err + } + + dockerArgs = append(dockerArgs, words...) } filteredArgs := []string{"restart", "cpus", "memory", "memory-swap", "memory-reservation", "gpus"} @@ -187,12 +199,22 @@ func executeScript(appName string, imageTag string, phase string) error { } containerCommand := []string{dokkuAppShell, "-c", script} - containerID, _ := createdContainerID(appName, dockerArgs, image, containerCommand, phase) - common.LogVerboseQuietContainerLogs(containerID) - if !waitForExecution(containerID) { - common.LogFail(fmt.Sprintf("Execution of '%s' command failed: %s", phase, command)) + containerID, err := createdContainerID(appName, dockerArgs, image, containerCommand, phase) + if err != nil { + common.LogFail(fmt.Sprintf("Failed to create %s execution container: %s", phase, err.Error())) } + if !waitForExecution(containerID) { + common.LogInfo2Quiet(fmt.Sprintf("Start of %s %s task (%s) output", appName, phase, containerID[0:9])) + common.LogVerboseQuietContainerLogs(containerID) + common.LogInfo2Quiet(fmt.Sprintf("End of %s %s task (%s) output", appName, phase, containerID[0:9])) + common.LogFail(fmt.Sprintf("Execution of %s task failed: %s", phase, command)) + } + + common.LogInfo2Quiet(fmt.Sprintf("Start of %s %s task (%s) output", appName, phase, containerID[0:9])) + common.LogVerboseQuietContainerLogs(containerID) + common.LogInfo2Quiet(fmt.Sprintf("End of %s %s task (%s) output", appName, phase, containerID[0:9])) + if phase != "predeploy" { return nil } @@ -329,7 +351,7 @@ func createdContainerID(appName string, dockerArgs []string, image string, comma b, err := containerCreateCmd.Output() if err != nil { - return "", err + return "", errors.New(stderr.String()) } containerID := strings.TrimSpace(string(b)) diff --git a/plugins/app-json/go.mod b/plugins/app-json/go.mod index 125615f38..388f20ed8 100644 --- a/plugins/app-json/go.mod +++ b/plugins/app-json/go.mod @@ -3,9 +3,10 @@ module github.com/dokku/dokku/plugins/app-json go 1.14 require ( - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect - github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 - github.com/ryanuber/columnize v1.1.2-0.20190319233515-9e6335e58db3 // indirect + github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect + github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 + github.com/ryanuber/columnize v1.1.2-0.20190319233515-9e6335e58db3 // indirect ) replace github.com/dokku/dokku/plugins/common => ../common diff --git a/plugins/app-json/go.sum b/plugins/app-json/go.sum index f05068f8d..ee7942d28 100644 --- a/plugins/app-json/go.sum +++ b/plugins/app-json/go.sum @@ -2,5 +2,7 @@ github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+Bu github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 h1:HHUr4P/aKh4quafGxDT9LDasjGdlGkzLbfmmrlng3kA= github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27/go.mod h1:VQx0hjo2oUeQkQUET7wRwradO6f+fN5jzXgB/zROxxE= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/ryanuber/columnize v1.1.2-0.20190319233515-9e6335e58db3 h1:utdYOikI1XjNtTFGCwSM6OmFJblU4ld4gACoJsbadJg= github.com/ryanuber/columnize v1.1.2-0.20190319233515-9e6335e58db3/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= diff --git a/plugins/common/log.go b/plugins/common/log.go index 00983cb83..3619bbe65 100644 --- a/plugins/common/log.go +++ b/plugins/common/log.go @@ -81,7 +81,12 @@ func LogVerboseQuietContainerLogs(containerID string) { LogExclaim(fmt.Sprintf("Failed to fetch container logs: %s", containerID)) } - for _, line := range strings.Split(strings.TrimSpace(string(b)), "\n") { + output := strings.TrimSpace(string(b)) + if len(output) == 0 { + return + } + + for _, line := range strings.Split(output, "\n") { if line != "" { LogVerboseQuiet(line) } diff --git a/tests/apps/dockerfile-release/Dockerfile b/tests/apps/dockerfile-release/Dockerfile new file mode 100644 index 000000000..1c53486a3 --- /dev/null +++ b/tests/apps/dockerfile-release/Dockerfile @@ -0,0 +1,19 @@ +FROM python:3.8-buster + +RUN pip install --user pipenv +ENV PATH="${PATH}:/root/.local/bin" +ENV PIPENV_VENV_IN_PROJECT=0 + +COPY . /app + +WORKDIR /app + +RUN ls -lah + +RUN rm -rf .venv + +RUN mkdir .venv + +RUN pipenv install + +CMD pipenv run gunicorn -b 0.0.0.0:8000 --workers=3 --threads=5 project.wsgi:application diff --git a/tests/apps/dockerfile-release/Pipfile b/tests/apps/dockerfile-release/Pipfile new file mode 100644 index 000000000..26df7ab95 --- /dev/null +++ b/tests/apps/dockerfile-release/Pipfile @@ -0,0 +1,17 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[dev-packages] + +[packages] +django = "*" +gunicorn = "*" +djangorestframework = "*" +whitenoise = "*" +psycopg2-binary = "*" +dj-database-url = "*" + +[requires] +python_version = "3.8" diff --git a/tests/apps/dockerfile-release/Pipfile.lock b/tests/apps/dockerfile-release/Pipfile.lock new file mode 100644 index 000000000..89bb16b72 --- /dev/null +++ b/tests/apps/dockerfile-release/Pipfile.lock @@ -0,0 +1,120 @@ +{ + "_meta": { + "hash": { + "sha256": "6e4ab3d777dd8ead8bc254ab4bb72ee80c93d1c09537b30ad23beb21c8bfdba9" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.8" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "asgiref": { + "hashes": [ + "sha256:7e06d934a7718bf3975acbf87780ba678957b87c7adc056f13b6215d610695a0", + "sha256:ea448f92fc35a0ef4b1508f53a04c4670255a3f33d22a81c8fc9c872036adbe5" + ], + "version": "==3.2.3" + }, + "dj-database-url": { + "hashes": [ + "sha256:4aeaeb1f573c74835b0686a2b46b85990571159ffc21aa57ecd4d1e1cb334163", + "sha256:851785365761ebe4994a921b433062309eb882fedd318e1b0fcecc607ed02da9" + ], + "index": "pypi", + "version": "==0.5.0" + }, + "django": { + "hashes": [ + "sha256:4f2c913303be4f874015993420bf0bd8fd2097a9c88e6b49c6a92f9bdd3fb13a", + "sha256:8c3575f81e11390893860d97e1e0154c47512f180ea55bd84ce8fa69ba8051ca" + ], + "index": "pypi", + "version": "==3.0.2" + }, + "djangorestframework": { + "hashes": [ + "sha256:05809fc66e1c997fd9a32ea5730d9f4ba28b109b9da71fccfa5ff241201fd0a4", + "sha256:e782087823c47a26826ee5b6fa0c542968219263fb3976ec3c31edab23a4001f" + ], + "index": "pypi", + "version": "==3.11.0" + }, + "gunicorn": { + "hashes": [ + "sha256:1904bb2b8a43658807108d59c3f3d56c2b6121a701161de0ddf9ad140073c626", + "sha256:cd4a810dd51bf497552cf3f863b575dabd73d6ad6a91075b65936b151cbf4f9c" + ], + "index": "pypi", + "version": "==20.0.4" + }, + "psycopg2-binary": { + "hashes": [ + "sha256:040234f8a4a8dfd692662a8308d78f63f31a97e1c42d2480e5e6810c48966a29", + "sha256:086f7e89ec85a6704db51f68f0dcae432eff9300809723a6e8782c41c2f48e03", + "sha256:18ca813fdb17bc1db73fe61b196b05dd1ca2165b884dd5ec5568877cabf9b039", + "sha256:19dc39616850342a2a6db70559af55b22955f86667b5f652f40c0e99253d9881", + "sha256:2166e770cb98f02ed5ee2b0b569d40db26788e0bf2ec3ae1a0d864ea6f1d8309", + "sha256:3a2522b1d9178575acee4adf8fd9f979f9c0449b00b4164bb63c3475ea6528ed", + "sha256:3aa773580f85a28ffdf6f862e59cb5a3cc7ef6885121f2de3fca8d6ada4dbf3b", + "sha256:3b5deaa3ee7180585a296af33e14c9b18c218d148e735c7accf78130765a47e3", + "sha256:407af6d7e46593415f216c7f56ba087a9a42bd6dc2ecb86028760aa45b802bd7", + "sha256:4c3c09fb674401f630626310bcaf6cd6285daf0d5e4c26d6e55ca26a2734e39b", + "sha256:4c6717962247445b4f9e21c962ea61d2e884fc17df5ddf5e35863b016f8a1f03", + "sha256:50446fae5681fc99f87e505d4e77c9407e683ab60c555ec302f9ac9bffa61103", + "sha256:5057669b6a66aa9ca118a2a860159f0ee3acf837eda937bdd2a64f3431361a2d", + "sha256:5dd90c5438b4f935c9d01fcbad3620253da89d19c1f5fca9158646407ed7df35", + "sha256:659c815b5b8e2a55193ede2795c1e2349b8011497310bb936da7d4745652823b", + "sha256:69b13fdf12878b10dc6003acc8d0abf3ad93e79813fd5f3812497c1c9fb9be49", + "sha256:7a1cb80e35e1ccea3e11a48afe65d38744a0e0bde88795cc56a4d05b6e4f9d70", + "sha256:7e6e3c52e6732c219c07bd97fff6c088f8df4dae3b79752ee3a817e6f32e177e", + "sha256:7f42a8490c4fe854325504ce7a6e4796b207960dabb2cbafe3c3959cb00d1d7e", + "sha256:84156313f258eafff716b2961644a4483a9be44a5d43551d554844d15d4d224e", + "sha256:8578d6b8192e4c805e85f187bc530d0f52ba86c39172e61cd51f68fddd648103", + "sha256:890167d5091279a27e2505ff0e1fb273f8c48c41d35c5b92adbf4af80e6b2ed6", + "sha256:98e10634792ac0e9e7a92a76b4991b44c2325d3e7798270a808407355e7bb0a1", + "sha256:9aadff9032e967865f9778485571e93908d27dab21d0fdfdec0ca779bb6f8ad9", + "sha256:9f24f383a298a0c0f9b3113b982e21751a8ecde6615494a3f1470eb4a9d70e9e", + "sha256:a73021b44813b5c84eda4a3af5826dd72356a900bac9bd9dd1f0f81ee1c22c2f", + "sha256:afd96845e12638d2c44d213d4810a08f4dc4a563f9a98204b7428e567014b1cd", + "sha256:b73ddf033d8cd4cc9dfed6324b1ad2a89ba52c410ef6877998422fcb9c23e3a8", + "sha256:b8f490f5fad1767a1331df1259763b3bad7d7af12a75b950c2843ba319b2415f", + "sha256:dbc5cd56fff1a6152ca59445178652756f4e509f672e49ccdf3d79c1043113a4", + "sha256:eac8a3499754790187bb00574ab980df13e754777d346f85e0ff6df929bcd964", + "sha256:eaed1c65f461a959284649e37b5051224f4db6ebdc84e40b5e65f2986f101a08" + ], + "index": "pypi", + "version": "==2.8.4" + }, + "pytz": { + "hashes": [ + "sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d", + "sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be" + ], + "version": "==2019.3" + }, + "sqlparse": { + "hashes": [ + "sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177", + "sha256:7c3dca29c022744e95b547e867cee89f4fce4373f3549ccd8797d8eb52cdb873" + ], + "version": "==0.3.0" + }, + "whitenoise": { + "hashes": [ + "sha256:0f9137f74bd95fa54329ace88d8dc695fbe895369a632e35f7a136e003e41d73", + "sha256:62556265ec1011bd87113fb81b7516f52688887b7a010ee899ff1fd18fd22700" + ], + "index": "pypi", + "version": "==5.0.1" + } + }, + "develop": {} +} diff --git a/tests/apps/dockerfile-release/Procfile b/tests/apps/dockerfile-release/Procfile new file mode 100644 index 000000000..fc5b1ca69 --- /dev/null +++ b/tests/apps/dockerfile-release/Procfile @@ -0,0 +1 @@ +release: pipenv run python manage.py migrate diff --git a/tests/apps/dockerfile-release/app/__init__.py b/tests/apps/dockerfile-release/app/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/apps/dockerfile-release/app/admin.py b/tests/apps/dockerfile-release/app/admin.py new file mode 100644 index 000000000..8c38f3f3d --- /dev/null +++ b/tests/apps/dockerfile-release/app/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/tests/apps/dockerfile-release/app/apps.py b/tests/apps/dockerfile-release/app/apps.py new file mode 100644 index 000000000..4f29a567f --- /dev/null +++ b/tests/apps/dockerfile-release/app/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class AppMainConfig(AppConfig): + name = 'app' diff --git a/tests/apps/dockerfile-release/app/migrations/__init__.py b/tests/apps/dockerfile-release/app/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/apps/dockerfile-release/app/models.py b/tests/apps/dockerfile-release/app/models.py new file mode 100644 index 000000000..71a836239 --- /dev/null +++ b/tests/apps/dockerfile-release/app/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/tests/apps/dockerfile-release/app/tests.py b/tests/apps/dockerfile-release/app/tests.py new file mode 100644 index 000000000..7ce503c2d --- /dev/null +++ b/tests/apps/dockerfile-release/app/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/tests/apps/dockerfile-release/app/views.py b/tests/apps/dockerfile-release/app/views.py new file mode 100644 index 000000000..91ea44a21 --- /dev/null +++ b/tests/apps/dockerfile-release/app/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/tests/apps/dockerfile-release/manage.py b/tests/apps/dockerfile-release/manage.py new file mode 100755 index 000000000..0c5ebba3b --- /dev/null +++ b/tests/apps/dockerfile-release/manage.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os + + +def main(): + print("SECRET_KEY: {0}".format(os.getenv('SECRET_KEY'))) + + +if __name__ == '__main__': + main() diff --git a/tests/apps/dockerfile-release/project/__init__.py b/tests/apps/dockerfile-release/project/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/apps/dockerfile-release/project/asgi.py b/tests/apps/dockerfile-release/project/asgi.py new file mode 100644 index 000000000..46249aa11 --- /dev/null +++ b/tests/apps/dockerfile-release/project/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for project project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings') + +application = get_asgi_application() diff --git a/tests/apps/dockerfile-release/project/settings/__init__.py b/tests/apps/dockerfile-release/project/settings/__init__.py new file mode 100644 index 000000000..e7999ecf3 --- /dev/null +++ b/tests/apps/dockerfile-release/project/settings/__init__.py @@ -0,0 +1,12 @@ +import os + +environment = os.getenv('ENVIRONMENT') + +if environment == 'dev': + from .dev import * +elif environment == 'staging': + from .staging import * +elif environment == 'production': + from .staging import * +else: + raise Exception("Invalid environment") diff --git a/tests/apps/dockerfile-release/project/settings/defaults.py b/tests/apps/dockerfile-release/project/settings/defaults.py new file mode 100644 index 000000000..529aabcd1 --- /dev/null +++ b/tests/apps/dockerfile-release/project/settings/defaults.py @@ -0,0 +1,135 @@ +""" +Django settings for project project. + +Generated by 'django-admin startproject' using Django 3.0.2. + +For more information on this file, see +https://docs.djangoproject.com/en/3.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/3.0/ref/settings/ +""" + +import os +import dj_database_url + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = os.getenv('SECRET_KEY') + +if not SECRET_KEY: + raise Exception("Secret Key Required") + +ALLOWED_HOSTS = [ + "*", +] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'whitenoise.runserver_nostatic', + 'django.contrib.staticfiles', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'whitenoise.middleware.WhiteNoiseMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'project.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'project.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/3.0/ref/settings/#databases + +DATABASES = { + 'default': dj_database_url.config(conn_max_age=500, ssl_require=True) +} + +del DATABASES['default']['OPTIONS']['sslmode'] + +SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') + + +# Password validation +# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/3.0/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/3.0/howto/static-files/ + +STATIC_ROOT = os.path.join(PROJECT_ROOT, 'staticfiles') +STATIC_URL = '/static/' + +# Extra places for collectstatic to find static files. +STATICFILES_DIRS = [ + os.path.join(PROJECT_ROOT, 'static'), +] + +STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' diff --git a/tests/apps/dockerfile-release/project/settings/dev.py b/tests/apps/dockerfile-release/project/settings/dev.py new file mode 100644 index 000000000..ece308f17 --- /dev/null +++ b/tests/apps/dockerfile-release/project/settings/dev.py @@ -0,0 +1,4 @@ +from .defaults import * + + +DEBUG = True \ No newline at end of file diff --git a/tests/apps/dockerfile-release/project/settings/production.py b/tests/apps/dockerfile-release/project/settings/production.py new file mode 100644 index 000000000..dbc6ab431 --- /dev/null +++ b/tests/apps/dockerfile-release/project/settings/production.py @@ -0,0 +1 @@ +from .defaults import * \ No newline at end of file diff --git a/tests/apps/dockerfile-release/project/settings/staging.py b/tests/apps/dockerfile-release/project/settings/staging.py new file mode 100644 index 000000000..dbc6ab431 --- /dev/null +++ b/tests/apps/dockerfile-release/project/settings/staging.py @@ -0,0 +1 @@ +from .defaults import * \ No newline at end of file diff --git a/tests/apps/dockerfile-release/project/urls.py b/tests/apps/dockerfile-release/project/urls.py new file mode 100644 index 000000000..5a0c0f185 --- /dev/null +++ b/tests/apps/dockerfile-release/project/urls.py @@ -0,0 +1,21 @@ +"""project URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/3.0/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path + +urlpatterns = [ + path('admin/', admin.site.urls), +] diff --git a/tests/apps/dockerfile-release/project/wsgi.py b/tests/apps/dockerfile-release/project/wsgi.py new file mode 100644 index 000000000..eb1e0a505 --- /dev/null +++ b/tests/apps/dockerfile-release/project/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for project project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings') + +application = get_wsgi_application() diff --git a/tests/unit/app-json.bats b/tests/unit/app-json.bats index 82c806f6b..5fe2f1a36 100644 --- a/tests/unit/app-json.bats +++ b/tests/unit/app-json.bats @@ -87,3 +87,17 @@ teardown() { assert_success assert_output '["./entrypoint"]' } + +@test "(app-json) app.json dockerfile release" { + run /bin/bash -c "dokku config:set --no-restart $TEST_APP SECRET_KEY=fjdkslafjdk ENVIRONMENT=dev" + echo "output: $output" + echo "status: $status" + assert_success + + run deploy_app dockerfile-release + echo "output: $output" + echo "status: $status" + assert_output_contains "Executing release task from Procfile" + assert_output_contains "SECRET_KEY: fjdkslafjdk" + assert_success +}