From a564eae9f16b041befe8d0885bb7cec43e234ade Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 22 Jan 2017 21:39:30 -0700 Subject: [PATCH] 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 +}