From a564eae9f16b041befe8d0885bb7cec43e234ade Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 22 Jan 2017 21:39:30 -0700 Subject: [PATCH 1/6] feat: implement application cloning Application cloning can be used to setup review applications based on an existing application. This is useful in CI/CD pipelines where a developer may wish to verify code in a custom environment without overwriting a shared staging environment. --- docs/deployment/application-management.md | 23 +++++++++++++ plugins/apps/commands | 1 + plugins/apps/subcommands/clone | 39 +++++++++++++++++++++++ tests/unit/10_apps.bats | 33 +++++++++++++++++++ 4 files changed, 96 insertions(+) create mode 100755 plugins/apps/subcommands/clone diff --git a/docs/deployment/application-management.md b/docs/deployment/application-management.md index 9b44c3ebc..7f7add379 100644 --- a/docs/deployment/application-management.md +++ b/docs/deployment/application-management.md @@ -4,6 +4,7 @@ ``` apps # List your apps +apps:clone # Clone an app apps:create # Create a new app apps:destroy # Permanently destroy an app apps:rename # Rename an app @@ -112,3 +113,25 @@ Renaming node-js-app to io-js-app... done ``` This will copy all of your app's contents into a new app directory with the name of your choice, delete your old app, then rebuild the new version of the app and deploy it. All of your config variables, including database urls, will be preserved. + +### Cloning an existing app + +> New as of 0.8.1 + +You can clone an existing app using the `apps:clone` command. Note that the application *must* have been deployed at least once, or the rename will not complete successfully: + +```shell +dokku apps:clone node-js-app io-js-app +``` + +``` +Cloning node-js-app to io-js-app... done +``` + +This will copy all of your app's contents into a new app directory with the name of your choice and then rebuild the new version of the app and deploy it. All of your config variables, including database urls, will be preserved. + +By default, Dokku will deploy this new application, though you can skip the deploy by using the `--skip-deploy` flag: + +```shell +dokku apps:clone --skip-deploy node-js-app io-js-app +``` diff --git a/plugins/apps/commands b/plugins/apps/commands index c46d255b1..660d799fb 100755 --- a/plugins/apps/commands +++ b/plugins/apps/commands @@ -8,6 +8,7 @@ case "$1" in declare desc="return apps plugin help content" cat< , Clone an app apps:create , Create a new app apps:destroy , Permanently destroy an app apps:rename , Rename an app diff --git a/plugins/apps/subcommands/clone b/plugins/apps/subcommands/clone new file mode 100755 index 000000000..4f1a4c38d --- /dev/null +++ b/plugins/apps/subcommands/clone @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/apps/functions" +source "$PLUGIN_AVAILABLE_PATH/ps/functions" + +apps_clone_cmd() { + declare desc="renames an app" + declare OLD_APP="$2" NEW_APP="$3" + local cmd="apps:rename" + local SKIP_REBUILD=false + + if [[ "$2" == "--skip-deploy" ]]; then + SKIP_REBUILD=true + OLD_APP="$3" + NEW_APP="$4" + fi + + [[ -z "$OLD_APP" ]] && dokku_log_fail "Please specify an app to run the command on" + [[ -d "$DOKKU_ROOT/$NEW_APP" ]] && dokku_log_fail "Name is already taken" + local NEW_CACHE_DIR="$DOKKU_ROOT/$NEW_APP/cache" + + apps_create "$NEW_APP" + cp -a "$DOKKU_ROOT/$OLD_APP/." "$DOKKU_ROOT/$NEW_APP" + + if [[ -d "$NEW_CACHE_DIR" ]] && ! rmdir "$NEW_CACHE_DIR"; then + docker run "$DOKKU_GLOBAL_RUN_ARGS" --rm -v "$NEW_CACHE_DIR:/cache" "dokku/$OLD_APP" chmod 777 -R /cache + fi + rm -rf "$NEW_CACHE_DIR" + + [[ -f "$DOKKU_ROOT/$NEW_APP/URLS" ]] && sed -i -e "s/$OLD_APP/$NEW_APP/g" "$DOKKU_ROOT/$NEW_APP/URLS" + [[ -f "$DOKKU_ROOT/$NEW_APP/VHOST" ]] && sed -i -e "s/$OLD_APP/$NEW_APP/g" "$DOKKU_ROOT/$NEW_APP/VHOST" + [[ -f "$DOKKU_ROOT/$NEW_APP/hooks/pre-receive" ]] && sed -i -e "s/git-hook $OLD_APP/git-hook $NEW_APP/g" "$DOKKU_ROOT/$NEW_APP/hooks/pre-receive" + [[ "$SKIP_REBUILD" == "false" ]] || ps_rebuild "$NEW_APP" + plugn trigger post-app-clone "$OLD_APP" "$NEW_APP" + echo "Cloning $OLD_APP to $NEW_APP... done" +} + +apps_clone_cmd "$@" diff --git a/tests/unit/10_apps.bats b/tests/unit/10_apps.bats index 9558b3e9b..17ed29be3 100644 --- a/tests/unit/10_apps.bats +++ b/tests/unit/10_apps.bats @@ -90,3 +90,36 @@ teardown () { echo "status: "$status assert_success } + +@test "(apps) apps:clone" { + deploy_app + run bash -c "dokku apps:clone $TEST_APP great-test-name" + echo "output: "$output + echo "status: "$status + assert_success + run bash -c "dokku apps | grep $TEST_APP" + echo "output: "$output + echo "status: "$status + assert_success + run bash -c "curl --silent --write-out '%{http_code}\n' `dokku url great-test-name` | grep 404" + echo "output: "$output + echo "status: "$status + assert_output "" + run bash -c "dokku --force apps:destroy great-test-name" + echo "output: "$output + echo "status: "$status + assert_success + + run bash -c "dokku apps:clone --skip-deploy $TEST_APP great-test-name" + echo "output: "$output + echo "status: "$status + assert_success + run bash -c "curl --silent --write-out '%{http_code}\n' `dokku url great-test-name` | grep 404" + echo "output: "$output + echo "status: "$status + assert_failure + run bash -c "dokku --force apps:destroy great-test-name" + echo "output: "$output + echo "status: "$status + assert_success +} From 143b4802c30274e4f78cd47a6ea2853697c73f1b Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 22 Jan 2017 22:55:09 -0700 Subject: [PATCH 2/6] fix: use correct verb [ci skip] --- plugins/apps/subcommands/clone | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/apps/subcommands/clone b/plugins/apps/subcommands/clone index 4f1a4c38d..565ed13bc 100755 --- a/plugins/apps/subcommands/clone +++ b/plugins/apps/subcommands/clone @@ -5,9 +5,9 @@ source "$PLUGIN_AVAILABLE_PATH/apps/functions" source "$PLUGIN_AVAILABLE_PATH/ps/functions" apps_clone_cmd() { - declare desc="renames an app" + declare desc="clones an app" declare OLD_APP="$2" NEW_APP="$3" - local cmd="apps:rename" + local cmd="apps:clone" local SKIP_REBUILD=false if [[ "$2" == "--skip-deploy" ]]; then From dd517a3dd11a283f82e0aac02e2a5aa9881f4550 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 22 Jan 2017 22:55:28 -0700 Subject: [PATCH 3/6] Update application-management.md [ci skip] --- docs/deployment/application-management.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/deployment/application-management.md b/docs/deployment/application-management.md index 7f7add379..3ee69f6a9 100644 --- a/docs/deployment/application-management.md +++ b/docs/deployment/application-management.md @@ -4,7 +4,7 @@ ``` apps # List your apps -apps:clone # Clone an app +apps:clone # Clones an app apps:create # Create a new app apps:destroy # Permanently destroy an app apps:rename # Rename an app From 33a7619eac98b6ecba0504c61a537daa8bbc5d1f Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 22 Jan 2017 22:55:40 -0700 Subject: [PATCH 4/6] Update commands [ci skip] --- plugins/apps/commands | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/apps/commands b/plugins/apps/commands index 660d799fb..234108cdf 100755 --- a/plugins/apps/commands +++ b/plugins/apps/commands @@ -8,7 +8,7 @@ case "$1" in declare desc="return apps plugin help content" cat< , Clone an app + apps:clone , Clones an app apps:create , Create a new app apps:destroy , Permanently destroy an app apps:rename , Rename an app From d473c1635fbb4faf5ac0f941843c17689a8b3173 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Mon, 23 Jan 2017 12:03:16 -0700 Subject: [PATCH 5/6] docs: add a note about errors that can occur for non-generic config [ci skip] --- docs/deployment/application-management.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/deployment/application-management.md b/docs/deployment/application-management.md index 3ee69f6a9..1ddf5715a 100644 --- a/docs/deployment/application-management.md +++ b/docs/deployment/application-management.md @@ -130,6 +130,8 @@ Cloning node-js-app to io-js-app... done This will copy all of your app's contents into a new app directory with the name of your choice and then rebuild the new version of the app and deploy it. All of your config variables, including database urls, will be preserved. +> Warning: If you have exposed specific ports via docker-options, added generic domains, or performed anything that cannot be done against multiple applications, `apps:clone` may result in errors. + By default, Dokku will deploy this new application, though you can skip the deploy by using the `--skip-deploy` flag: ```shell From c82c9562b633063510987936c7381c02a6ffca3f Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Tue, 24 Jan 2017 02:54:26 -0700 Subject: [PATCH 6/6] fix: use correct check for skipping a rebuild --- plugins/apps/subcommands/clone | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/apps/subcommands/clone b/plugins/apps/subcommands/clone index 565ed13bc..829882c2c 100755 --- a/plugins/apps/subcommands/clone +++ b/plugins/apps/subcommands/clone @@ -31,7 +31,7 @@ apps_clone_cmd() { [[ -f "$DOKKU_ROOT/$NEW_APP/URLS" ]] && sed -i -e "s/$OLD_APP/$NEW_APP/g" "$DOKKU_ROOT/$NEW_APP/URLS" [[ -f "$DOKKU_ROOT/$NEW_APP/VHOST" ]] && sed -i -e "s/$OLD_APP/$NEW_APP/g" "$DOKKU_ROOT/$NEW_APP/VHOST" [[ -f "$DOKKU_ROOT/$NEW_APP/hooks/pre-receive" ]] && sed -i -e "s/git-hook $OLD_APP/git-hook $NEW_APP/g" "$DOKKU_ROOT/$NEW_APP/hooks/pre-receive" - [[ "$SKIP_REBUILD" == "false" ]] || ps_rebuild "$NEW_APP" + [[ "$SKIP_REBUILD" == "true" ]] || ps_rebuild "$NEW_APP" plugn trigger post-app-clone "$OLD_APP" "$NEW_APP" echo "Cloning $OLD_APP to $NEW_APP... done" }