diff --git a/docs/advanced-usage/deployment-tasks.md b/docs/advanced-usage/deployment-tasks.md index 5c62a8ae0..bce01efab 100644 --- a/docs/advanced-usage/deployment-tasks.md +++ b/docs/advanced-usage/deployment-tasks.md @@ -38,7 +38,12 @@ Each "phase" has different expectations and limitations: - Priming or invalidating cache stores - Running database migrations -Additionally, if using a Dockerfile with an `ENTRYPOINT`, the deployment task is passed to that entrypoint as is. +Additionally, if using a Dockerfile with an `ENTRYPOINT`, the deployment task is passed to that entrypoint as is. The exceptions are if the entrypoint is one of the following: + +- `["/tini", "--"]` +- `["/bin/tini", "--"]` +- `["/usr/bin/tini", "--"]` +- `["/usr/local/bin/tini", "--"]` Please keep the above in mind when utilizing deployment tasks. diff --git a/plugins/app-json/functions.go b/plugins/app-json/functions.go index c8b3f58f0..289c107cf 100644 --- a/plugins/app-json/functions.go +++ b/plugins/app-json/functions.go @@ -16,8 +16,16 @@ import ( "golang.org/x/sync/errgroup" ) -func constructScript(command string, shell string, isHerokuishImage bool, isCnbImage bool, hasEntrypoint bool) []string { - if hasEntrypoint { +func constructScript(command string, shell string, isHerokuishImage bool, isCnbImage bool, dockerfileEntrypoint string) []string { + nonSkippableEntrypoints := map[string]bool{ + "ENTRYPOINT [\"/tini\",\"--\"]": true, + "ENTRYPOINT [\"/bin/tini\",\"--\"]": true, + "ENTRYPOINT [\"/usr/bin/tini\",\"--\"]": true, + "ENTRYPOINT [\"/usr/local/bin/tini\",\"--\"]": true, + } + + cannotSkip := nonSkippableEntrypoints[dockerfileEntrypoint] + if dockerfileEntrypoint != "" && !cannotSkip { words, err := shellquote.Split(strings.TrimSpace(command)) if err != nil { common.LogWarn(fmt.Sprintf("Skipping command construction for app with ENTRYPOINT: %v", err.Error())) @@ -180,9 +188,8 @@ func executeScript(appName string, image string, imageTag string, phase string) dockerfileCommand, _ = getCommandFromImage(image) } - hasEntrypoint := dockerfileEntrypoint != "" dokkuAppShell := getDokkuAppShell(appName) - script := constructScript(command, dokkuAppShell, isHerokuishImage, isCnbImage, hasEntrypoint) + script := constructScript(command, dokkuAppShell, isHerokuishImage, isCnbImage, dockerfileEntrypoint) imageSourceType := "dockerfile" if isHerokuishImage { diff --git a/tests/unit/app-json-2.bats b/tests/unit/app-json-2.bats new file mode 100644 index 000000000..88efdded1 --- /dev/null +++ b/tests/unit/app-json-2.bats @@ -0,0 +1,68 @@ +#!/usr/bin/env bats +load test_helper + +setup() { + global_setup + create_app +} + +teardown() { + destroy_app + global_teardown +} + +@test "(app-json) app.json dockerfile cmd" { + run deploy_app dockerfile-procfile + echo "output: $output" + echo "status: $status" + assert_success + + run docker inspect "dokku/${TEST_APP}:latest" --format "{{json .Config.Cmd}}" + echo "output: $output" + echo "status: $status" + assert_success + assert_output '["/bin/sh","-c","npm start"]' + + run docker inspect "dokku/${TEST_APP}:latest" --format "{{json .Config.Entrypoint}}" + echo "output: $output" + echo "status: $status" + assert_success + assert_output 'null' +} + +@test "(app-json) app.json dockerfile release" { + run /bin/bash -c "dokku config:set --no-restart $TEST_APP SECRET_KEY=fjdkslafjdk ENVIRONMENT=dev DATABASE_URL=sqlite:///db.sqlite3" + 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 +} + +@test "(app-json) app.json dockerfile entrypoint release" { + run deploy_app dockerfile-entrypoint dokku@dokku.me:$TEST_APP add_release_command + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "touch /app/release.test" 2 +} + +@test "(app-json) app.json dockerfile entrypoint predeploy" { + run deploy_app dockerfile-entrypoint + echo "output: $output" + echo "status: $status" + assert_output_contains "Executing predeploy task from app.json" + assert_output_contains "entrypoint script started with arguments touch /app/predeploy.test" + assert_success + + run /bin/bash -c "dokku --rm run $TEST_APP ls /app/predeploy.test" + echo "output: $output" + echo "status: $status" + assert_success +} + diff --git a/tests/unit/app-json.bats b/tests/unit/app-json.bats index 5e291a506..31d99d365 100644 --- a/tests/unit/app-json.bats +++ b/tests/unit/app-json.bats @@ -2,9 +2,11 @@ load test_helper setup_file() { - add-apt-repository --yes ppa:cncf-buildpacks/pack-cli - apt-get update - apt-get --yes install pack-cli + if ! command -v "pack" &>/dev/null; then + add-apt-repository --yes ppa:cncf-buildpacks/pack-cli + apt-get update + apt-get --yes install pack-cli + fi } setup() { @@ -48,7 +50,6 @@ teardown() { assert_success } - @test "(app-json) app.json scripts postdeploy" { run deploy_app python dokku@dokku.me:$TEST_APP add_postdeploy_command echo "output: $output" @@ -65,61 +66,6 @@ teardown() { assert_success } -@test "(app-json) app.json dockerfile cmd" { - run deploy_app dockerfile-procfile - echo "output: $output" - echo "status: $status" - assert_success - - run docker inspect "dokku/${TEST_APP}:latest" --format "{{json .Config.Cmd}}" - echo "output: $output" - echo "status: $status" - assert_success - assert_output '["/bin/sh","-c","npm start"]' - - run docker inspect "dokku/${TEST_APP}:latest" --format "{{json .Config.Entrypoint}}" - echo "output: $output" - echo "status: $status" - assert_success - assert_output 'null' -} - -@test "(app-json) app.json dockerfile release" { - run /bin/bash -c "dokku config:set --no-restart $TEST_APP SECRET_KEY=fjdkslafjdk ENVIRONMENT=dev DATABASE_URL=sqlite:///db.sqlite3" - 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 -} - -@test "(app-json) app.json dockerfile entrypoint release" { - run deploy_app dockerfile-entrypoint dokku@dokku.me:$TEST_APP add_release_command - echo "output: $output" - echo "status: $status" - assert_success - assert_output_contains "touch /app/release.test" 2 -} - -@test "(app-json) app.json dockerfile entrypoint predeploy" { - run deploy_app dockerfile-entrypoint - echo "output: $output" - echo "status: $status" - assert_output_contains "Executing predeploy task from app.json" - assert_output_contains "entrypoint script started with arguments touch /app/predeploy.test" - assert_success - - run /bin/bash -c "dokku --rm run $TEST_APP ls /app/predeploy.test" - echo "output: $output" - echo "status: $status" - assert_success -} - @test "(app-json) app.json cnb release" { run /bin/bash -c "dokku config:set --no-restart $TEST_APP DOKKU_CNB_EXPERIMENTAL=1 SECRET_KEY=fjdkslafjdk" echo "output: $output" @@ -139,3 +85,69 @@ teardown() { assert_success assert_output_contains '"SECRET_KEY": "fjdkslafjdk"' } + +@test "(app-json) tini test" { + if ! dokku plugin:installed postgres; then + run /bin/bash -c "dokku plugin:install https://github.com/dokku/dokku-postgres.git" + echo "output: $output" + echo "status: $status" + assert_success + fi + + if ! dokku plugin:installed redis; then + run /bin/bash -c "dokku plugin:install https://github.com/dokku/dokku-redis.git" + echo "output: $output" + echo "status: $status" + assert_success + fi + + run /bin/bash -c "dokku config:set $TEST_APP SECRET_KEY_BASE=derp OTP_SECRET=1234" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku postgres:create $TEST_APP $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku postgres:link $TEST_APP $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku redis:create $TEST_APP $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku redis:link $TEST_APP $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku git:from-image $TEST_APP tootsuite/mastodon:v3.3.0" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku postgres:unlink $TEST_APP $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku redis:unlink $TEST_APP $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku --force postgres:destroy $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku --force redis:destroy $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success +} diff --git a/tests/unit/ps-cnb.bats b/tests/unit/ps-cnb.bats index b7045ee9a..7d98ba0a6 100644 --- a/tests/unit/ps-cnb.bats +++ b/tests/unit/ps-cnb.bats @@ -3,9 +3,11 @@ load test_helper setup_file() { - add-apt-repository --yes ppa:cncf-buildpacks/pack-cli - apt-get update - apt-get --yes install pack-cli + if ! command -v "pack" &>/dev/null; then + add-apt-repository --yes ppa:cncf-buildpacks/pack-cli + apt-get update + apt-get --yes install pack-cli + fi } setup() {