From 6d40d52d7d78aa8e9a03bbd64e299b13d95dde73 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 21 Mar 2021 21:42:39 -0400 Subject: [PATCH 01/32] feat: add ability to specify a custom build directory for an app --- .../deployment/builders/builder-management.md | 39 +++++++++++++++++- docs/development/plugin-triggers.md | 25 ++++++++++++ plugins/20_events/core-post-extract | 1 + plugins/builder/Makefile | 2 +- plugins/builder/builder.go | 6 ++- plugins/builder/report.go | 25 ++++++++++-- plugins/builder/triggers.go | 40 +++++++++++++++++++ plugins/git/functions | 1 + plugins/tar/functions | 1 + 9 files changed, 133 insertions(+), 7 deletions(-) create mode 120000 plugins/20_events/core-post-extract diff --git a/docs/deployment/builders/builder-management.md b/docs/deployment/builders/builder-management.md index 72824b11d..38f2c1f7f 100644 --- a/docs/deployment/builders/builder-management.md +++ b/docs/deployment/builders/builder-management.md @@ -47,6 +47,34 @@ The default value may be set by passing an empty value for the option. dokku builder:set --global selected ``` +#### Changing the build directory + +> Warning: Please keep in mind that setting a custom build directory will result in loss of any changes to the top-level directory, such as the `git.keep-git-dir` property. + +When deploying a monorepo, it may be desirable to specify the specific build directory to use for a given app. This can be done via the `builder:set` command. + +```shell +dokku builder:set node-js-app build-dir app2 +``` + +The default value may be set by passing an empty value for the option: + +```shell +dokku builder:set node-js-app build-dir +``` + +The `build-dir` property can also be set globally. The global default is empty string, and the global value is used when no app-specific value is set. + +```shell +dokku builder:set --global build-dir app2 +``` + +The default value may be set by passing an empty value for the option. + +```shell +dokku builder:set --global build-dir +``` + ### Displaying builder reports for an app You can get a report about the app's builder status using the `builder:report` command: @@ -57,15 +85,24 @@ dokku builder:report ``` =====> node-js-app builder information - Builder computed selected: herokuish + Builder build dir: custom + Builder computed build dir: custom + Builder computed selected: herokuish + Builder global build dir: Builder global selected: herokuish Builder selected: herokuish =====> python-sample builder information + Builder build dir: + Builder computed build dir: Builder computed selected: dockerfile + Builder global build dir: Builder global selected: herokuish Builder selected: dockerfile =====> ruby-sample builder information + Builder build dir: + Builder computed build dir: Builder computed selected: herokuish + Builder global build dir: Builder global selected: herokuish Builder selected: ``` diff --git a/docs/development/plugin-triggers.md b/docs/development/plugin-triggers.md index 2fbadae2a..c75aa7c9f 100644 --- a/docs/development/plugin-triggers.md +++ b/docs/development/plugin-triggers.md @@ -342,6 +342,31 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x curl "http://httpstat.us/200" ``` +### `core-post-extract` + +> To avoid issues with community plugins, this plugin trigger should be used *only* for core plugins. Please avoid using this trigger in your own plugins. + +- Description: Allows you to modify the contents of an app *after* it has been extracted from git/tarball but *before* the image source type is detected. +- Invoked by: `dokku tar:in`, `dokku tar:from` and the `receive-app` plugin trigger +- Arguments: `$APP` `$TMP_WORK_DIR` `$REV` +- Example: + +```shell +#!/usr/bin/env bash +# Adds a clock process to an app's Procfile + +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +APP="$1" +TMP_WORK_DIR="$2" +REV="$3" # optional, may not be sent for tar-based builds + +pushd "$TMP_WORK_DIR" >/dev/null +touch Procfile +echo "clock: some-command" >> Procfile +popd &>/dev/null +``` + ### `cron-write` - Description: Force triggers writing out cron entries diff --git a/plugins/20_events/core-post-extract b/plugins/20_events/core-post-extract new file mode 120000 index 000000000..5178a749f --- /dev/null +++ b/plugins/20_events/core-post-extract @@ -0,0 +1 @@ +hook \ No newline at end of file diff --git a/plugins/builder/Makefile b/plugins/builder/Makefile index 8dce99ce8..1f9b324dd 100644 --- a/plugins/builder/Makefile +++ b/plugins/builder/Makefile @@ -1,5 +1,5 @@ SUBCOMMANDS = subcommands/report subcommands/set -TRIGGERS = triggers/builder-detect triggers/install triggers/post-delete triggers/report +TRIGGERS = triggers/builder-detect triggers/core-post-extract triggers/install triggers/post-delete triggers/report BUILD = commands subcommands triggers PLUGIN_NAME = builder diff --git a/plugins/builder/builder.go b/plugins/builder/builder.go index 22ef608b4..3d1a6d6f8 100644 --- a/plugins/builder/builder.go +++ b/plugins/builder/builder.go @@ -3,11 +3,13 @@ package builder var ( // DefaultProperties is a map of all valid network properties with corresponding default property values DefaultProperties = map[string]string{ - "selected": "", + "selected": "", + "build-dir": "", } // GlobalProperties is a map of all valid global network properties GlobalProperties = map[string]bool{ - "selected": true, + "selected": true, + "build-dir": true, } ) diff --git a/plugins/builder/report.go b/plugins/builder/report.go index 57eaf4604..3f2f9cb15 100644 --- a/plugins/builder/report.go +++ b/plugins/builder/report.go @@ -11,9 +11,12 @@ func ReportSingleApp(appName string, format string, infoFlag string) error { } flags := map[string]common.ReportFunc{ - "--builder-computed-selected": reportComputedSelected, - "--builder-global-selected": reportGlobalSelected, - "--builder-selected": reportSelected, + "--builder-computed-selected": reportComputedSelected, + "--builder-global-selected": reportGlobalSelected, + "--builder-selected": reportSelected, + "--builder-computed-build-dir": reportComputedBuildDir, + "--builder-global-build-dir": reportGlobalBuildDir, + "--builder-build-dir": reportBuildDir, } flagKeys := []string{} @@ -42,3 +45,19 @@ func reportGlobalSelected(appName string) string { func reportSelected(appName string) string { return common.PropertyGet("builder", appName, "selected") } + +func reportComputedBuildDir(appName string) string { + value := reportBuildDir(appName) + if value == "" { + value = reportGlobalBuildDir(appName) + } + + return value +} +func reportGlobalBuildDir(appName string) string { + return common.PropertyGet("builder", "--global", "build-dir") +} + +func reportBuildDir(appName string) string { + return common.PropertyGet("builder", appName, "build-dir") +} diff --git a/plugins/builder/triggers.go b/plugins/builder/triggers.go index 0cfed9837..b0c0bfe03 100644 --- a/plugins/builder/triggers.go +++ b/plugins/builder/triggers.go @@ -2,6 +2,10 @@ package builder import ( "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" "github.com/dokku/dokku/plugins/common" ) @@ -21,6 +25,42 @@ func TriggerBuilderDetect(appName string) error { return nil } +// TriggerCorePostExtract moves a configured build-dir to be in the app root dir +func TriggerCorePostExtract(appName string, sourceWorkDir string) error { + buildDir := strings.Trim(reportComputedBuildDir(appName), "/") + if buildDir == "" { + return nil + } + + newSourceWorkDir := filepath.Join(sourceWorkDir, buildDir) + if !common.DirectoryExists(newSourceWorkDir) { + return fmt.Errorf("Specified build-dir not found in sourcecode working directory: %v", buildDir) + } + + tmpWorkDir, err := ioutil.TempDir(os.TempDir(), fmt.Sprintf("dokku-%s-%s", common.MustGetEnv("DOKKU_PID"), "CorePostExtract")) + if err != nil { + return fmt.Errorf("Unable to create temporary working directory: %v", err.Error()) + } + + if err := os.RemoveAll(tmpWorkDir); err != nil { + return fmt.Errorf("Unable to clear out temporary working directory for rewrite: %v", err.Error()) + } + + if err := os.Rename(newSourceWorkDir, tmpWorkDir); err != nil { + return fmt.Errorf("Unable to move build-dir to temporary working directory: %v", err.Error()) + } + + if err := os.RemoveAll(sourceWorkDir); err != nil { + return fmt.Errorf("Unable to clear out sourcecode working directory for rewrite: %v", err.Error()) + } + + if err := os.Rename(tmpWorkDir, sourceWorkDir); err != nil { + return fmt.Errorf("Unable to move build-dir to sourcecode working directory: %v", err.Error()) + } + + return nil +} + // TriggerInstall runs the install step for the builder plugin func TriggerInstall() error { if err := common.PropertySetup("builder"); err != nil { diff --git a/plugins/git/functions b/plugins/git/functions index 16ea953a7..3f5357a33 100755 --- a/plugins/git/functions +++ b/plugins/git/functions @@ -51,6 +51,7 @@ git_trigger_build() { declare APP="$1" TMP_WORK_DIR="$2" REV="$3" local BUILDER + plugn trigger core-post-extract "$APP" "$TMP_WORK_DIR" "$REV" plugn trigger post-extract "$APP" "$TMP_WORK_DIR" "$REV" BUILDER="$(plugn trigger builder-detect "$APP" "$TMP_WORK_DIR" | head -n1 || true)" diff --git a/plugins/tar/functions b/plugins/tar/functions index fc7e6698d..27fccefed 100755 --- a/plugins/tar/functions +++ b/plugins/tar/functions @@ -43,6 +43,7 @@ tar_trigger_build() { declare APP="$1" TMP_WORK_DIR="$2" REV="$3" local BUILDER + plugn trigger core-post-extract "$APP" "$TMP_WORK_DIR" "$REV" plugn trigger post-extract "$APP" "$TMP_WORK_DIR" "$REV" BUILDER="$(plugn trigger builder-detect "$APP" "$TMP_WORK_DIR" | head -n1 || true)" From da2b54823b85043f28ed6c966e62f09d20817165 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 21 Mar 2021 21:43:53 -0400 Subject: [PATCH 02/32] feat: add ability to specify a custom Dockerfile for an app --- docs/appendices/0.25.0-migration-guide.md | 4 + docs/deployment/builders/dockerfiles.md | 82 +++++++++++++++-- plugins/builder-dockerfile/builder-build | 19 +++- plugins/builder-dockerfile/commands | 15 +++ plugins/builder-dockerfile/help-functions | 33 +++++++ plugins/builder-dockerfile/internal-commands | 91 +++++++++++++++++++ plugins/builder-dockerfile/report | 6 ++ .../builder-dockerfile/subcommands/default | 6 ++ plugins/builder-dockerfile/subcommands/report | 6 ++ plugins/builder-dockerfile/subcommands/set | 30 ++++++ 10 files changed, 284 insertions(+), 8 deletions(-) create mode 100755 plugins/builder-dockerfile/commands create mode 100755 plugins/builder-dockerfile/help-functions create mode 100755 plugins/builder-dockerfile/internal-commands create mode 100755 plugins/builder-dockerfile/report create mode 100755 plugins/builder-dockerfile/subcommands/default create mode 100755 plugins/builder-dockerfile/subcommands/report create mode 100755 plugins/builder-dockerfile/subcommands/set diff --git a/docs/appendices/0.25.0-migration-guide.md b/docs/appendices/0.25.0-migration-guide.md index 6361d512d..1e75ddbf8 100644 --- a/docs/appendices/0.25.0-migration-guide.md +++ b/docs/appendices/0.25.0-migration-guide.md @@ -3,3 +3,7 @@ ## Changes - The network plugin can now set an `initial-network` for all containers on creation. This is a replacement for specifying the `--network` flag via the `docker-options` plugin. Please see the [network documentation](/docs/networking/network.md#attaching-an-app-to-a-network) for more information. + +## Deprecations + +- In previous versions of Dokku, the only way to specify a custom `Dockerfile` was to use the `docker-options` plugin to set the `--file` flag for a docker build. As of 0.25.0, the `builder-dockerfile:set` command should be used instead, as outlined in the [docs here](/docs/deployment/builders/dockerfiles.md#changingthe-dockerfile-location). Usage of the old method should be migrated to the new method. diff --git a/docs/deployment/builders/dockerfiles.md b/docs/deployment/builders/dockerfiles.md index ef52f71fc..33b3c4c69 100644 --- a/docs/deployment/builders/dockerfiles.md +++ b/docs/deployment/builders/dockerfiles.md @@ -27,6 +27,82 @@ If an application was previously deployed via buildpacks, the following commands dokku config:unset --no-restart node-js-app DOKKU_PROXY_PORT_MAP ``` +### Changing the `Dockerfile` location + +> The previous method to perform this - via `docker-options:add` - should be removed in favor of the `builder-dockerfile:set` command outlined here. + +When deploying a monorepo, it may be desirable to specify the specific path of the `Dockerfile` file to use for a given app. This can be done via the `builder-dockerfile:set` command. + +```shell +dokku builder-dockerfile:set node-js-app dockerfile-path Dockerfile2 +``` + +The default value may be set by passing an empty value for the option: + +```shell +dokku builder-dockerfile:set node-js-app dockerfile-path +``` + +The `dockerfile-path` property can also be set globally. The global default is `Dockerfile`, and the global value is used when no app-specific value is set. + +```shell +dokku builder-dockerfile:set --global dockerfile-path Dockerfile2 +``` + +The default value may be set by passing an empty value for the option. + +```shell +dokku builder-dockerfile:set --global dockerfile-path +``` + +### Displaying builder-dockerfile reports for an app + +> New as of 0.25.0 + +You can get a report about the app's storage status using the `builder-dockerfile:report` command: + +```shell +dokku app-json:report +``` + +``` +=====> node-js-app builder-dockerfile information + Builder-dockerfile computed dockerfile path: Dockerfile2 + Builder-dockerfile global dockerfile path: Dockerfile + Builder-dockerfile dockerfile path: Dockerfile2 +=====> python-sample builder-dockerfile information + Builder-dockerfile computed dockerfile path: Dockerfile + Builder-dockerfile global dockerfile path: Dockerfile + Builder-dockerfile dockerfile path: +=====> ruby-sample builder-dockerfile information + Builder-dockerfile computed dockerfile path: Dockerfile + Builder-dockerfile global dockerfile path: Dockerfile + Builder-dockerfile dockerfile path: +``` + +You can run the command for a specific app also. + +```shell +dokku builder-dockerfile:report node-js-app +``` + +``` +=====> node-js-app builder-dockerfile information + Builder-dockerfile computed dockerfile path: Dockerfile2 + Builder-dockerfile global dockerfile path: Dockerfile + Builder-dockerfile dockerfile path: Dockerfile2 +``` + +You can pass flags which will output only the value of the specific information you want. For example: + +```shell +dokku builder-dockerfile:report node-js-app --builder-dockerfile-dockerfile-path +``` + +``` +Dockerfile2 +``` + ### Build-time configuration variables For security reasons - and as per [Docker recommendations](https://github.com/docker/docker/issues/13490) - Dockerfile-based deploys have variables available only during runtime. @@ -37,12 +113,6 @@ For users that require customization in the `build` phase, you may use build arg dokku docker-options:add node-js-app build '--build-arg NODE_ENV=production' ``` -The location of the `Dockerfile` may also be specified. If the location is changed, the repository **must also** have a `Dockerfile` in the root directory in order to trigger a dockerfile-based deploy. - -```shell -dokku docker-options:add node-js-app build '--file Dockerfile.dokku' -``` - Once set, the Dockerfile usage would be as follows: ```Dockerfile diff --git a/plugins/builder-dockerfile/builder-build b/plugins/builder-dockerfile/builder-build index 7ff239b92..6a4fc60a8 100755 --- a/plugins/builder-dockerfile/builder-build +++ b/plugins/builder-dockerfile/builder-build @@ -1,7 +1,9 @@ #!/usr/bin/env bash +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/config/functions" +source "$PLUGIN_AVAILABLE_PATH/builder-dockerfile/internal-functions" set -eo pipefail [[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_AVAILABLE_PATH/config/functions" trigger-builder-dockerfile-builder-build() { declare desc="builder-dockerfile builder-build plugin trigger" @@ -19,6 +21,19 @@ trigger-builder-dockerfile-builder-build() { pushd "$SOURCECODE_WORK_DIR" &>/dev/null + local NEW_DOCKERFILE="$(fn-builder-dockerfile-computed-dockerfile-path "$APP")" + if [[ -f "$NEW_DOCKERFILE" ]]; then + if [[ "$NEW_DOCKERFILE" != "Dockerfile" ]]; then + mv "$NEW_DOCKERFILE" Dockerfile + fi + else + rm Dockerfile + fi + + if [[ ! -f Dockerfile ]]; then + dokku_log_fail "Invalid dockerfile-path specified: $dockerfile_path" + fi + # extract first port from Dockerfile dos2unix Dockerfile local DOCKERFILE_PORTS=$(get_dockerfile_exposed_ports Dockerfile) @@ -34,7 +49,7 @@ trigger-builder-dockerfile-builder-build() { declare -a ARG_ARRAY eval "ARG_ARRAY=($DOCKER_ARGS)" - "$DOCKER_BIN" image build "${DOCKER_BUILD_LABEL_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS "${ARG_ARRAY[@]}" "${DOKKU_DOCKER_BUILD_OPTS[@]}" -t $IMAGE . + "$DOCKER_BIN" image build --file "$dockerfile_path" "${DOCKER_BUILD_LABEL_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS "${ARG_ARRAY[@]}" "${DOKKU_DOCKER_BUILD_OPTS[@]}" -t $IMAGE . plugn trigger post-build-dockerfile "$APP" } diff --git a/plugins/builder-dockerfile/commands b/plugins/builder-dockerfile/commands new file mode 100755 index 000000000..8ccfa20ee --- /dev/null +++ b/plugins/builder-dockerfile/commands @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_AVAILABLE_PATH/builder-dockerfile/help-functions" + +case "$1" in + help | builder-dockerfile:help) + cmd-builder-dockerfile-help "$@" + ;; + + *) + exit "$DOKKU_NOT_IMPLEMENTED_EXIT" + ;; + +esac diff --git a/plugins/builder-dockerfile/help-functions b/plugins/builder-dockerfile/help-functions new file mode 100755 index 000000000..ec1c52e38 --- /dev/null +++ b/plugins/builder-dockerfile/help-functions @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +cmd-builder-dockerfile-help() { + declare desc="help command" + declare CMD="$1" + local plugin_name="builder-dockerfile" + local plugin_description="Manage the dockerfile builder integration for an app" + + if [[ "$CMD" == "${plugin_name}:help" ]]; then + echo -e "Usage: dokku ${plugin_name}[:COMMAND]" + echo '' + echo "$plugin_description" + echo '' + echo 'Additional commands:' + fn-help-content | sort | column -c2 -t -s, + elif [[ $(ps -o command= $PPID) == *"--all"* ]]; then + fn-help-content + else + cat <] [], Displays a builder-dockerfile report for one or more apps + builder-dockerfile:set (), Set or clear a builder-dockerfile property for an app +help_content +} diff --git a/plugins/builder-dockerfile/internal-commands b/plugins/builder-dockerfile/internal-commands new file mode 100755 index 000000000..88503617b --- /dev/null +++ b/plugins/builder-dockerfile/internal-commands @@ -0,0 +1,91 @@ +#!/usr/bin/env bash +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +cmd-builder-dockerfile-report() { + declare desc="displays a builder-dockerfile report for one or more apps" + declare cmd="builder-dockerfile:report" + [[ "$1" == "$cmd" ]] && shift 1 + declare APP="$1" INFO_FLAG="$2" + local INSTALLED_APPS=$(dokku_apps) + + if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then + INFO_FLAG="$APP" + APP="" + fi + + if [[ -z "$APP" ]] && [[ -z "$INFO_FLAG" ]]; then + INFO_FLAG="true" + fi + + if [[ -z "$APP" ]]; then + for app in $INSTALLED_APPS; do + cmd-builder-dockerfile-report-single "$app" "$INFO_FLAG" | tee || true + done + else + cmd-builder-dockerfile-report-single "$APP" "$INFO_FLAG" + fi +} + +cmd-builder-dockerfile-report-single() { + declare APP="$1" INFO_FLAG="$2" + if [[ "$INFO_FLAG" == "true" ]]; then + INFO_FLAG="" + fi + verify_app_name "$APP" + local flag_map=( + "--builder-dockerfile-computed-dockerfile-path: $(fn-builder-dockerfile-computed-dockerfile-path "$APP")" + "--builder-dockerfile-global-dockerfile-path: $(fn-builder-dockerfile-global-dockerfile-path "$APP")" + "--builder-dockerfile-dockerfile-path: $(fn-builder-dockerfile-dockerfile-path "$APP")" + ) + + if [[ -z "$INFO_FLAG" ]]; then + dokku_log_info2_quiet "${APP} builder-dockerfile information" + for flag in "${flag_map[@]}"; do + key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')" + dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")" + done + else + local match=false + local value_exists=false + for flag in "${flag_map[@]}"; do + valid_flags="${valid_flags} $(echo "$flag" | cut -d':' -f1)" + if [[ "$flag" == "${INFO_FLAG}:"* ]]; then + value=${flag#*: } + size="${#value}" + if [[ "$size" -ne 0 ]]; then + echo "$value" && match=true && value_exists=true + else + match=true + fi + fi + done + [[ "$match" == "true" ]] || dokku_log_fail "Invalid flag passed, valid flags:${valid_flags}" + [[ "$value_exists" == "true" ]] || dokku_log_fail "not deployed" + fi +} + +fn-builder-dockerfile-computed-dockerfile-path() { + declare APP="$1" + + file="$(fn-builder-dockerfile-dockerfile-path "$APP")" + if [[ "$file" == "" ]]; then + file="$(fn-builder-dockerfile-global-dockerfile-path "$APP")" + fi + + echo "$file" +} + +fn-builder-dockerfile-global-dockerfile-path() { + declare APP="$1" + + fn-plugin-property-get "builder-dockerfile" "--global" "dockerfile-path" "Dockerfile" +} + +fn-builder-dockerfile-dockerfile-path() { + declare APP="$1" + + fn-plugin-property-get "builder-dockerfile" "$APP" "dockerfile-path" "" +} diff --git a/plugins/builder-dockerfile/report b/plugins/builder-dockerfile/report new file mode 100755 index 000000000..1f809ffca --- /dev/null +++ b/plugins/builder-dockerfile/report @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +source "$PLUGIN_AVAILABLE_PATH/builder-dockerfile/internal-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +cmd-builder-dockerfile-report-single "$@" diff --git a/plugins/builder-dockerfile/subcommands/default b/plugins/builder-dockerfile/subcommands/default new file mode 100755 index 000000000..dc15e270c --- /dev/null +++ b/plugins/builder-dockerfile/subcommands/default @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +source "$PLUGIN_AVAILABLE_PATH/builder-dockerfile/help-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +cmd-builder-dockerfile-help "builder-dockerfile:help" diff --git a/plugins/builder-dockerfile/subcommands/report b/plugins/builder-dockerfile/subcommands/report new file mode 100755 index 000000000..15f0f1769 --- /dev/null +++ b/plugins/builder-dockerfile/subcommands/report @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +source "$PLUGIN_AVAILABLE_PATH/builder-dockerfile/internal-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +cmd-builder-dockerfile-report "$@" diff --git a/plugins/builder-dockerfile/subcommands/set b/plugins/builder-dockerfile/subcommands/set new file mode 100755 index 000000000..d31b4f150 --- /dev/null +++ b/plugins/builder-dockerfile/subcommands/set @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +cmd-builder-dockerfile-set() { + declare desc="set or clear a builder-dockerfile property for an app" + declare cmd="builder-dockerfile:set" + [[ "$1" == "$cmd" ]] && shift 1 + declare APP="$1" KEY="$2" VALUE="$3" + local VALID_KEYS=("dockerfile-path") + [[ "$APP" == "--global" ]] || verify_app_name "$APP" + + [[ -z "$KEY" ]] && dokku_log_fail "No key specified" + + if ! fn-in-array "$KEY" "${VALID_KEYS[@]}"; then + dokku_log_fail "Invalid key specified, valid keys include: dockerfile-path" + fi + + if [[ -n "$VALUE" ]]; then + dokku_log_info2_quiet "Setting ${KEY} to ${VALUE}" + fn-plugin-property-write "builder-dockerfile" "$APP" "$KEY" "$VALUE" + else + dokku_log_info2_quiet "Unsetting ${KEY}" + fn-plugin-property-delete "builder-dockerfile" "$APP" "$KEY" + fi +} + +cmd-builder-dockerfile-set "$@" From 9082c51074031ff66c60a43f20ea18594637e363 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 21 Mar 2021 21:45:01 -0400 Subject: [PATCH 03/32] feat: add ability to specify a custom project.toml path --- .../builders/cloud-native-buildpacks.md | 112 +++++++++++++++--- plugins/builder-pack/builder-build | 14 ++- plugins/builder-pack/commands | 15 +++ plugins/builder-pack/help-functions | 33 ++++++ plugins/builder-pack/internal-commands | 91 ++++++++++++++ plugins/builder-pack/report | 6 + plugins/builder-pack/subcommands/default | 6 + plugins/builder-pack/subcommands/report | 6 + plugins/builder-pack/subcommands/set | 30 +++++ 9 files changed, 292 insertions(+), 21 deletions(-) create mode 100755 plugins/builder-pack/commands create mode 100755 plugins/builder-pack/help-functions create mode 100755 plugins/builder-pack/internal-commands create mode 100755 plugins/builder-pack/report create mode 100755 plugins/builder-pack/subcommands/default create mode 100755 plugins/builder-pack/subcommands/report create mode 100755 plugins/builder-pack/subcommands/set diff --git a/docs/deployment/builders/cloud-native-buildpacks.md b/docs/deployment/builders/cloud-native-buildpacks.md index a62133d91..f7e7daa06 100644 --- a/docs/deployment/builders/cloud-native-buildpacks.md +++ b/docs/deployment/builders/cloud-native-buildpacks.md @@ -12,25 +12,6 @@ Cloud Native Buildpacks are an evolution over the Buildpacks technology provided ## Usage -### Detection - -This builder will be auto-detected in either the following cases: - -- The `DOKKU_CNB_EXPERIMENTAL` app environment variable is set to `1`. - ```shell - dokku config:set --no-restart node-js-app DOKKU_CNB_EXPERIMENTAL=1 - ``` -- A `project.toml` file exists in the root of the app repository. - - This file is consumed by `pack-cli` and used to describe how the app is built. - -The builder can also be specified via the `builder:set` command: - -```shell -dokku builder:set node-js-app selected pack -``` - -> Dokku will only select the `dockerfile` builder if both the `herokuish` and `pack` builders are not detected and a Dockerfile exists. See the [dockerfile builder documentation](/docs/deployment/builders/dockerfiles.md) for more information on how that builder functions. - ### Requirements The `pack` cli tool is not included by default with Dokku or as a dependency. It must also be installed as shown on [this page](https://buildpacks.io/docs/tools/pack/). @@ -51,6 +32,99 @@ As this functionality is highly experimental, there are a number of caveats. Ple - `pack` is not currently included with Dokku, nor is it added as a package dependency. - A future version will include it as a package dependency. +### Detection + +This builder will be auto-detected in either the following cases: + +- The `DOKKU_CNB_EXPERIMENTAL` app environment variable is set to `1`. + ```shell + dokku config:set --no-restart node-js-app DOKKU_CNB_EXPERIMENTAL=1 + ``` +- A `project.toml` file exists in the root of the app repository. + - This file is consumed by `pack-cli` and used to describe how the app is built. + +The builder can also be specified via the `builder:set` command: + +```shell +dokku builder:set node-js-app selected pack +``` + +> Dokku will only select the `dockerfile` builder if both the `herokuish` and `pack` builders are not detected and a Dockerfile exists. See the [dockerfile builder documentation](/docs/deployment/builders/dockerfiles.md) for more information on how that builder functions. + +### Changing the `project.toml` location + +When deploying a monorepo, it may be desirable to specify the specific path of the `project.toml` file to use for a given app. This can be done via the `builder-pack:set` command. + +```shell +dokku builder-pack:set node-js-app projecttoml-path project2.toml +``` + +The default value may be set by passing an empty value for the option: + +```shell +dokku builder-pack:set node-js-app projecttoml-path +``` + +The `projecttoml-path` property can also be set globally. The global default is `project.toml`, and the global value is used when no app-specific value is set. + +```shell +dokku builder-pack:set --global projecttoml-path project2.toml +``` + +The default value may be set by passing an empty value for the option. + +```shell +dokku builder-pack:set --global projecttoml-path +``` + +### Displaying builder-pack reports for an app + +> New as of 0.25.0 + +You can get a report about the app's storage status using the `builder-pack:report` command: + +```shell +dokku app-json:report +``` + +``` +=====> node-js-app builder-pack information + Builder-pack computed projecttoml path: project2.toml + Builder-pack global projecttoml path: project.toml + Builder-pack projecttoml path: project2.toml +=====> python-sample builder-pack information + Builder-pack computed projecttoml path: project.toml + Builder-pack global projecttoml path: project.toml + Builder-pack projecttoml path: +=====> ruby-sample builder-pack information + Builder-pack computed projecttoml path: project.toml + Builder-pack global projecttoml path: project.json + Builder-pack projecttoml path: +``` + +You can run the command for a specific app also. + +```shell +dokku builder-pack:report node-js-app +``` + +``` +=====> node-js-app builder-pack information + Builder-pack computed projecttoml path: project2.toml + Builder-pack global projecttoml path: project.toml + Builder-pack projecttoml path: project2.toml +``` + +You can pass flags which will output only the value of the specific information you want. For example: + +```shell +dokku builder-pack:report node-js-app --builder-pack-projecttoml-path +``` + +``` +project2.toml +``` + ### Customizing the Buildpack stack builder > New as of 0.23.0 diff --git a/plugins/builder-pack/builder-build b/plugins/builder-pack/builder-build index 93dcd6b70..6a54e296f 100755 --- a/plugins/builder-pack/builder-build +++ b/plugins/builder-pack/builder-build @@ -1,8 +1,9 @@ #!/usr/bin/env bash -set -eo pipefail -[[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" +source "$PLUGIN_AVAILABLE_PATH/builder-pack/internal-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x trigger-builder-pack-builder-build() { declare desc="builder-pack builder-build plugin trigger" @@ -28,6 +29,15 @@ trigger-builder-pack-builder-build() { pushd "$SOURCECODE_WORK_DIR" &>/dev/null + local NEW_PROJECT_TOML="$(fn-builder-pack-computed-projectoml-path "$APP")" + if [[ -f "$NEW_PROJECT_TOML" ]]; then + if [[ "$NEW_DOCKERFILE" != "project.toml" ]]; then + mv "$NEW_PROJECT_TOML" project.toml + fi + else + rm project.toml + fi + local TMP_FILE=$(mktemp "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX") trap "rm -rf '$TMP_FILE' >/dev/null" RETURN INT TERM diff --git a/plugins/builder-pack/commands b/plugins/builder-pack/commands new file mode 100755 index 000000000..2b7211e4e --- /dev/null +++ b/plugins/builder-pack/commands @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_AVAILABLE_PATH/builder-pack/help-functions" + +case "$1" in + help | builder-pack:help) + cmd-builder-pack-help "$@" + ;; + + *) + exit "$DOKKU_NOT_IMPLEMENTED_EXIT" + ;; + +esac diff --git a/plugins/builder-pack/help-functions b/plugins/builder-pack/help-functions new file mode 100755 index 000000000..1191260df --- /dev/null +++ b/plugins/builder-pack/help-functions @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +cmd-builder-pack-help() { + declare desc="help command" + declare CMD="$1" + local plugin_name="builder-pack" + local plugin_description="Manage the pack builder integration for an app" + + if [[ "$CMD" == "${plugin_name}:help" ]]; then + echo -e "Usage: dokku ${plugin_name}[:COMMAND]" + echo '' + echo "$plugin_description" + echo '' + echo 'Additional commands:' + fn-help-content | sort | column -c2 -t -s, + elif [[ $(ps -o command= $PPID) == *"--all"* ]]; then + fn-help-content + else + cat <] [], Displays a builder-pack report for one or more apps + builder-pack:set (), Set or clear a builder-pack property for an app +help_content +} diff --git a/plugins/builder-pack/internal-commands b/plugins/builder-pack/internal-commands new file mode 100755 index 000000000..1cabe473d --- /dev/null +++ b/plugins/builder-pack/internal-commands @@ -0,0 +1,91 @@ +#!/usr/bin/env bash +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +cmd-builder-pack-report() { + declare desc="displays a builder-pack report for one or more apps" + declare cmd="builder-pack:report" + [[ "$1" == "$cmd" ]] && shift 1 + declare APP="$1" INFO_FLAG="$2" + local INSTALLED_APPS=$(dokku_apps) + + if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then + INFO_FLAG="$APP" + APP="" + fi + + if [[ -z "$APP" ]] && [[ -z "$INFO_FLAG" ]]; then + INFO_FLAG="true" + fi + + if [[ -z "$APP" ]]; then + for app in $INSTALLED_APPS; do + cmd-builder-pack-report-single "$app" "$INFO_FLAG" | tee || true + done + else + cmd-builder-pack-report-single "$APP" "$INFO_FLAG" + fi +} + +cmd-builder-pack-report-single() { + declare APP="$1" INFO_FLAG="$2" + if [[ "$INFO_FLAG" == "true" ]]; then + INFO_FLAG="" + fi + verify_app_name "$APP" + local flag_map=( + "--builder-pack-computed-projecttoml-path: $(fn-builder-pack-computed-projectoml-path "$APP")" + "--builder-pack-global-projecttoml-path: $(fn-builder-pack-global-projectoml-path "$APP")" + "--builder-pack-projecttoml-path: $(fn-builder-pack-projectoml-path "$APP")" + ) + + if [[ -z "$INFO_FLAG" ]]; then + dokku_log_info2_quiet "${APP} builder-pack information" + for flag in "${flag_map[@]}"; do + key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')" + dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")" + done + else + local match=false + local value_exists=false + for flag in "${flag_map[@]}"; do + valid_flags="${valid_flags} $(echo "$flag" | cut -d':' -f1)" + if [[ "$flag" == "${INFO_FLAG}:"* ]]; then + value=${flag#*: } + size="${#value}" + if [[ "$size" -ne 0 ]]; then + echo "$value" && match=true && value_exists=true + else + match=true + fi + fi + done + [[ "$match" == "true" ]] || dokku_log_fail "Invalid flag passed, valid flags:${valid_flags}" + [[ "$value_exists" == "true" ]] || dokku_log_fail "not deployed" + fi +} + +fn-builder-pack-computed-projectoml-path() { + declare APP="$1" + + file="$(fn-builder-pack-projectoml-path "$APP")" + if [[ "$file" == "" ]]; then + file="$(fn-builder-pack-global-projectoml-path "$APP")" + fi + + echo "$file" +} + +fn-builder-pack-global-projectoml-path() { + declare APP="$1" + + fn-plugin-property-get "builder-pack" "--global" "projecttoml-path" "project.toml" +} + +fn-builder-pack-projectoml-path() { + declare APP="$1" + + fn-plugin-property-get "builder-pack" "$APP" "projecttoml-path" "" +} diff --git a/plugins/builder-pack/report b/plugins/builder-pack/report new file mode 100755 index 000000000..600703509 --- /dev/null +++ b/plugins/builder-pack/report @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +source "$PLUGIN_AVAILABLE_PATH/builder-pack/internal-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +cmd-builder-pack-report-single "$@" diff --git a/plugins/builder-pack/subcommands/default b/plugins/builder-pack/subcommands/default new file mode 100755 index 000000000..f29e6dfa4 --- /dev/null +++ b/plugins/builder-pack/subcommands/default @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +source "$PLUGIN_AVAILABLE_PATH/builder-pack/help-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +cmd-builder-pack-help "builder-pack:help" diff --git a/plugins/builder-pack/subcommands/report b/plugins/builder-pack/subcommands/report new file mode 100755 index 000000000..03f6be771 --- /dev/null +++ b/plugins/builder-pack/subcommands/report @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +source "$PLUGIN_AVAILABLE_PATH/builder-pack/internal-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +cmd-builder-pack-report "$@" diff --git a/plugins/builder-pack/subcommands/set b/plugins/builder-pack/subcommands/set new file mode 100755 index 000000000..8642d829c --- /dev/null +++ b/plugins/builder-pack/subcommands/set @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +cmd-builder-pack-set() { + declare desc="set or clear a builder-pack property for an app" + declare cmd="builder-pack:set" + [[ "$1" == "$cmd" ]] && shift 1 + declare APP="$1" KEY="$2" VALUE="$3" + local VALID_KEYS=("projecttoml-path") + [[ "$APP" == "--global" ]] || verify_app_name "$APP" + + [[ -z "$KEY" ]] && dokku_log_fail "No key specified" + + if ! fn-in-array "$KEY" "${VALID_KEYS[@]}"; then + dokku_log_fail "Invalid key specified, valid keys include: projecttoml-path" + fi + + if [[ -n "$VALUE" ]]; then + dokku_log_info2_quiet "Setting ${KEY} to ${VALUE}" + fn-plugin-property-write "builder-pack" "$APP" "$KEY" "$VALUE" + else + dokku_log_info2_quiet "Unsetting ${KEY}" + fn-plugin-property-delete "builder-pack" "$APP" "$KEY" + fi +} + +cmd-builder-pack-set "$@" From c3ece32145465ee885ef5f07f1677672b3d02686 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 21 Mar 2021 21:45:46 -0400 Subject: [PATCH 04/32] feat: add ability to specify a custom Procfile path --- docs/processes/process-management.md | 35 ++++++++++++++++++++++++++++ plugins/ps/functions.go | 2 +- plugins/ps/ps.go | 5 +++- plugins/ps/report.go | 32 ++++++++++++++++++++----- plugins/ps/triggers.go | 2 +- 5 files changed, 67 insertions(+), 9 deletions(-) diff --git a/docs/processes/process-management.md b/docs/processes/process-management.md index 80c39e6b7..09f03563f 100644 --- a/docs/processes/process-management.md +++ b/docs/processes/process-management.md @@ -156,6 +156,32 @@ There are also a few other exceptions for the `web` process. - See the [nginx request proxying documentation](/docs/configuration/nginx.md#request-proxying) for more information on how nginx handles proxied requests. - Only the `web` process may be bound to an external port. +#### Changing the `Procfile` location + +When deploying a monorepo, it may be desirable to specify the specific path of the `Procfile` file to use for a given app. This can be done via the `ps:set` command. + +```shell +dokku ps:set node-js-app procfile-path Procfile2 +``` + +The default value may be set by passing an empty value for the option: + +```shell +dokku ps:set node-js-app procfile-path +``` + +The `procfile-path` property can also be set globally. The global default is `Procfile`, and the global value is used when no app-specific value is set. + +```shell +dokku ps:set --global procfile-path global-Procfile +``` + +The default value may be set by passing an empty value for the option. + +```shell +dokku ps:set --global procfile-path +``` + ### Stopping apps Deployed apps can be stopped using the `ps:stop` command. This turns off all running containers for an app, and will result in a **502 Bad Gateway** response for the default nginx proxy implementation. @@ -254,21 +280,30 @@ dokku ps:report Deployed: false Processes: 0 Ps can scale: true + Ps computed procfile path: Procfile2 + Ps global procfile path: Procfile Ps restart policy: on-failure:10 + Ps procfile path: Procfile2 Restore: true Running: false =====> python-sample ps information Deployed: false Processes: 0 Ps can scale: true + Ps computed procfile path: Procfile + Ps global procfile path: Procfile Ps restart policy: on-failure:10 + Ps procfile path: Restore: true Running: false =====> ruby-sample ps information Deployed: false Processes: 0 Ps can scale: true + Ps computed procfile path: Procfile + Ps global procfile path: Procfile Ps restart policy: on-failure:10 + Ps procfile path: Restore: true Running: false ``` diff --git a/plugins/ps/functions.go b/plugins/ps/functions.go index f6a47bbe8..713334abc 100644 --- a/plugins/ps/functions.go +++ b/plugins/ps/functions.go @@ -21,7 +21,7 @@ func canScaleApp(appName string) bool { func extractProcfile(appName, image string) error { destination := getProcfilePath(appName) - common.CopyFromImage(appName, image, "Procfile", destination) + common.CopyFromImage(appName, image, reportComputedProcfilePath(appName), destination) if !common.FileExists(destination) { common.LogInfo1Quiet("No Procfile found in app image") return nil diff --git a/plugins/ps/ps.go b/plugins/ps/ps.go index 7ca3dc5de..10699d9e5 100644 --- a/plugins/ps/ps.go +++ b/plugins/ps/ps.go @@ -15,10 +15,13 @@ var ( // DefaultProperties is a map of all valid ps properties with corresponding default property values DefaultProperties = map[string]string{ "restart-policy": "on-failure:10", + "procfile-path": "", } // GlobalProperties is a map of all valid global ps properties - GlobalProperties = map[string]bool{} + GlobalProperties = map[string]bool{ + "procfile-path": true, + } ) // Rebuild rebuilds app from base image diff --git a/plugins/ps/report.go b/plugins/ps/report.go index 6691b247b..af78b7263 100644 --- a/plugins/ps/report.go +++ b/plugins/ps/report.go @@ -15,12 +15,15 @@ func ReportSingleApp(appName string, format string, infoFlag string) error { } flags := map[string]common.ReportFunc{ - "--deployed": reportDeployed, - "--processes": reportProcesses, - "--ps-can-scale": reportCanScale, - "--ps-restart-policy": reportRestartPolicy, - "--restore": reportRestore, - "--running": reportRunningState, + "--deployed": reportDeployed, + "--processes": reportProcesses, + "--ps-can-scale": reportCanScale, + "--ps-restart-policy": reportRestartPolicy, + "--ps-computed-procfile-path": reportComputedProcfilePath, + "--ps-global-procfile-path": reportGlobalProcfilePath, + "--ps-procfile-path": reportProcfilePath, + "--restore": reportRestore, + "--running": reportRunningState, } extraFlags := addStatusFlags(appName, infoFlag) @@ -81,6 +84,23 @@ func reportCanScale(appName string) string { return canScale } +func reportComputedProcfilePath(appName string) string { + value := reportProcfilePath(appName) + if value == "" { + value = reportGlobalProcfilePath(appName) + } + + return value +} + +func reportGlobalProcfilePath(appName string) string { + return common.PropertyGetDefault("ps", "--global", "procfile-path", "Procfile") +} + +func reportProcfilePath(appName string) string { + return common.PropertyGetDefault("ps", appName, "procfile-path", "") +} + func reportDeployed(appName string) string { deployed := "false" if common.IsDeployed(appName) { diff --git a/plugins/ps/triggers.go b/plugins/ps/triggers.go index 452b417a7..90e81ac7e 100644 --- a/plugins/ps/triggers.go +++ b/plugins/ps/triggers.go @@ -142,7 +142,7 @@ func TriggerPostDelete(appName string) error { // TriggerPostExtract validates a procfile func TriggerPostExtract(appName string, tempWorkDir string) error { - procfile := filepath.Join(tempWorkDir, "Procfile") + procfile := filepath.Join(tempWorkDir, reportComputedProcfilePath(appName)) if !common.FileExists(procfile) { return nil } From a6113f88e7fd277d606f7e717fe69549aebc8a1c Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 21 Mar 2021 21:47:08 -0400 Subject: [PATCH 05/32] featfeat: add ability to specify a custom app.json path --- docs/advanced-usage/deployment-tasks.md | 84 ++++++++++++++++++- plugins/app-json/Makefile | 3 +- plugins/app-json/appjson.go | 12 +++ plugins/app-json/functions.go | 2 +- plugins/app-json/report.go | 45 ++++++++++ plugins/app-json/src/commands/commands.go | 56 +++++++++++++ .../app-json/src/subcommands/subcommands.go | 50 +++++++++++ plugins/app-json/subcommands.go | 29 +++++++ 8 files changed, 277 insertions(+), 4 deletions(-) create mode 100644 plugins/app-json/report.go create mode 100644 plugins/app-json/src/commands/commands.go create mode 100644 plugins/app-json/src/subcommands/subcommands.go create mode 100644 plugins/app-json/subcommands.go diff --git a/docs/advanced-usage/deployment-tasks.md b/docs/advanced-usage/deployment-tasks.md index fd071028d..e293751f5 100644 --- a/docs/advanced-usage/deployment-tasks.md +++ b/docs/advanced-usage/deployment-tasks.md @@ -2,6 +2,10 @@ > New as of 0.5.0 +## Usage + +### Overview + Sometimes you need to run a command on deployment time, but before an app is completely deployed. Common use cases include: - Checking a database is initialized @@ -49,7 +53,83 @@ Please keep the above in mind when utilizing deployment tasks. > To execute commands on the host during a release phase, see the [plugin creation documentation](/docs/development/plugin-creation.md) docs for more information on building your own custom plugin. -## `app.json` deployment tasks +### Changing the `app.json` location + +When deploying a monorepo, it may be desirable to specify the specific path of the `app.json` file to use for a given app. This can be done via the `app-json:set` command. + +```shell +dokku app-json:set node-js-app appjson-path second-app.json +``` + +The default value may be set by passing an empty value for the option: + +```shell +dokku app-json:set node-js-app appjson-path +``` + +The `appjson-path` property can also be set globally. The global default is `app.json`, and the global value is used when no app-specific value is set. + +```shell +dokku app-json:set --global appjson-path global-app.json +``` + +The default value may be set by passing an empty value for the option. + +```shell +dokku app-json:set --global appjson-path +``` + +### Displaying app-json reports for an app + +> New as of 0.25.0 + +You can get a report about the app's storage status using the `app-json:report` command: + +```shell +dokku app-json:report +``` + +``` +=====> node-js-app app-json information + App-json computed appjson path: app2.json + App-json global appjson path: app.json + App-json appjson path: app2.json +=====> python-sample app-json information + App-json computed appjson path: app.json + App-json global appjson path: app.json + App-json appjson path: +=====> ruby-sample app-json information + App-json computed appjson path: app.json + App-json global appjson path: app.json + App-json appjson path: +``` + +You can run the command for a specific app also. + +```shell +dokku app-json:report node-js-app +``` + +``` +=====> node-js-app app-json information + App-json computed appjson path: app2.json + App-json global appjson path: app.json + App-json appjson path: app2.json +``` + +You can pass flags which will output only the value of the specific information you want. For example: + +```shell +dokku app-json:report node-js-app --app-json-appjson-path +``` + +``` +app2.json +``` + +### Deployment tasks + +#### `app.json` deployment tasks Dokku provides limited support for the `app.json` manifest from Heroku (documentation available [here](https://devcenter.heroku.com/articles/app-json-schema)). The keys available for use with Deployment Tasks are: @@ -75,7 +155,7 @@ The following is an example `app.json` file. Please note that only the `scripts. } ``` -## Procfile Release command +#### Procfile Release command > New as of 0.14.0 diff --git a/plugins/app-json/Makefile b/plugins/app-json/Makefile index b3f6ecead..9b92fd230 100644 --- a/plugins/app-json/Makefile +++ b/plugins/app-json/Makefile @@ -1,5 +1,6 @@ +SUBCOMMANDS = subcommands/report subcommands/set TRIGGERS = triggers/install triggers/post-delete triggers/post-deploy triggers/pre-deploy -BUILD = triggers +BUILD = commands subcommands triggers PLUGIN_NAME = app-json include ../../common.mk diff --git a/plugins/app-json/appjson.go b/plugins/app-json/appjson.go index ad4871fbc..8d064210d 100644 --- a/plugins/app-json/appjson.go +++ b/plugins/app-json/appjson.go @@ -6,6 +6,18 @@ import ( "github.com/dokku/dokku/plugins/common" ) +var ( + // DefaultProperties is a map of all valid network properties with corresponding default property values + DefaultProperties = map[string]string{ + "appjson-path": "", + } + + // GlobalProperties is a map of all valid global network properties + GlobalProperties = map[string]bool{ + "appjson-path": true, + } +) + // AppJSON is a struct that represents an app.json file as understood by Dokku type AppJSON struct { Cron []CronCommand `json:"cron"` diff --git a/plugins/app-json/functions.go b/plugins/app-json/functions.go index 44175cc5a..4422542cb 100644 --- a/plugins/app-json/functions.go +++ b/plugins/app-json/functions.go @@ -448,6 +448,6 @@ func refreshAppJSON(appName string, image string) error { } } - common.CopyFromImage(appName, image, "app.json", appjsonPath) + common.CopyFromImage(appName, image, reportComputedAppjsonpath(appName), appjsonPath) return nil } diff --git a/plugins/app-json/report.go b/plugins/app-json/report.go new file mode 100644 index 000000000..511f12302 --- /dev/null +++ b/plugins/app-json/report.go @@ -0,0 +1,45 @@ +package appjson + +import ( + "github.com/dokku/dokku/plugins/common" +) + +// ReportSingleApp is an internal function that displays the builder report for one or more apps +func ReportSingleApp(appName string, format string, infoFlag string) error { + if err := common.VerifyAppName(appName); err != nil { + return err + } + + flags := map[string]common.ReportFunc{ + "--app-json-computed-selected": reportComputedAppjsonpath, + "--app-json-global-selected": reportGlobalAppjsonpath, + "--app-json-selected": reportAppjsonpath, + } + + flagKeys := []string{} + for flagKey := range flags { + flagKeys = append(flagKeys, flagKey) + } + + trimPrefix := false + uppercaseFirstCharacter := true + infoFlags := common.CollectReport(appName, infoFlag, flags) + return common.ReportSingleApp("app-json", appName, infoFlag, infoFlags, flagKeys, format, trimPrefix, uppercaseFirstCharacter) +} + +func reportComputedAppjsonpath(appName string) string { + value := reportAppjsonpath(appName) + if value == "" { + value = reportGlobalAppjsonpath(appName) + } + + return value +} + +func reportGlobalAppjsonpath(appName string) string { + return common.PropertyGetDefault("app-json", "--global", "appjson-path", "app.json") +} + +func reportAppjsonpath(appName string) string { + return common.PropertyGet("app-json", appName, "appjson-path") +} diff --git a/plugins/app-json/src/commands/commands.go b/plugins/app-json/src/commands/commands.go new file mode 100644 index 000000000..548c51e40 --- /dev/null +++ b/plugins/app-json/src/commands/commands.go @@ -0,0 +1,56 @@ +package main + +import ( + "flag" + "fmt" + "os" + "strconv" + "strings" + + "github.com/dokku/dokku/plugins/common" +) + +const ( + helpHeader = `Usage: dokku app-json[:COMMAND] + +Manage app-json settings for an app + +Additional commands:` + + helpContent = ` + app-json:report [] [], Displays a app-json report for one or more apps + app-json:set (), Set or clear a app-json property for an app +` +) + +func main() { + flag.Usage = usage + flag.Parse() + + cmd := flag.Arg(0) + switch cmd { + case "app-json", "app-json:help": + usage() + case "help": + command := common.NewShellCmd(fmt.Sprintf("ps -o command= %d", os.Getppid())) + command.ShowOutput = false + output, err := command.Output() + + if err == nil && strings.Contains(string(output), "--all") { + fmt.Println(helpContent) + } else { + fmt.Print("\n app-json, Manage app-json settings for an app\n") + } + default: + dokkuNotImplementExitCode, err := strconv.Atoi(os.Getenv("DOKKU_NOT_IMPLEMENTED_EXIT")) + if err != nil { + fmt.Println("failed to retrieve DOKKU_NOT_IMPLEMENTED_EXIT environment variable") + dokkuNotImplementExitCode = 10 + } + os.Exit(dokkuNotImplementExitCode) + } +} + +func usage() { + common.CommandUsage(helpHeader, helpContent) +} diff --git a/plugins/app-json/src/subcommands/subcommands.go b/plugins/app-json/src/subcommands/subcommands.go new file mode 100644 index 000000000..e4879e02e --- /dev/null +++ b/plugins/app-json/src/subcommands/subcommands.go @@ -0,0 +1,50 @@ +package main + +import ( + "fmt" + "os" + "strings" + + appjson "github.com/dokku/dokku/plugins/app-json" + "github.com/dokku/dokku/plugins/common" + + flag "github.com/spf13/pflag" +) + +// main entrypoint to all subcommands +func main() { + parts := strings.Split(os.Args[0], "/") + subcommand := parts[len(parts)-1] + + var err error + switch subcommand { + case "report": + args := flag.NewFlagSet("app-json:report", flag.ExitOnError) + format := args.String("format", "stdout", "format: [ stdout | json ]") + osArgs, infoFlag, flagErr := common.ParseReportArgs("appjson", os.Args[2:]) + if flagErr == nil { + args.Parse(osArgs) + appName := args.Arg(0) + err = appjson.CommandReport(appName, *format, infoFlag) + } + case "set": + args := flag.NewFlagSet("app-json:set", flag.ExitOnError) + global := args.Bool("global", false, "--global: set a global property") + args.Parse(os.Args[2:]) + appName := args.Arg(0) + property := args.Arg(1) + value := args.Arg(2) + if *global { + appName = "--global" + property = args.Arg(0) + value = args.Arg(1) + } + err = appjson.CommandSet(appName, property, value) + default: + err = fmt.Errorf("Invalid plugin subcommand call: %s", subcommand) + } + + if err != nil { + common.LogFailWithError(err) + } +} diff --git a/plugins/app-json/subcommands.go b/plugins/app-json/subcommands.go new file mode 100644 index 000000000..f402dd354 --- /dev/null +++ b/plugins/app-json/subcommands.go @@ -0,0 +1,29 @@ +package appjson + +import ( + "github.com/dokku/dokku/plugins/common" +) + +// CommandReport displays a network report for one or more apps +func CommandReport(appName string, format string, infoFlag string) error { + if len(appName) == 0 { + apps, err := common.DokkuApps() + if err != nil { + return err + } + for _, appName := range apps { + if err := ReportSingleApp(appName, format, infoFlag); err != nil { + return err + } + } + return nil + } + + return ReportSingleApp(appName, format, infoFlag) +} + +// CommandSet set or clear a builder property for an app +func CommandSet(appName string, property string, value string) error { + common.CommandPropertySet("builder", appName, property, value, DefaultProperties, GlobalProperties) + return nil +} From ae6b0b07aab3b12a661363f323f731214d552e18 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 21 Mar 2021 21:49:49 -0400 Subject: [PATCH 06/32] fix: add missing report trigger for builder-herokuish --- plugins/builder-herokuish/report | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100755 plugins/builder-herokuish/report diff --git a/plugins/builder-herokuish/report b/plugins/builder-herokuish/report new file mode 100755 index 000000000..785102c30 --- /dev/null +++ b/plugins/builder-herokuish/report @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +source "$PLUGIN_AVAILABLE_PATH/builder-herokuish/internal-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +cmd-builder-herokuish-report-single "$@" From 41f648083488e6f069b1b594f5f098e357c7cd4f Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 21 Mar 2021 21:51:14 -0400 Subject: [PATCH 07/32] fix: add missing report trigger to app-json plugin --- plugins/app-json/Makefile | 2 +- plugins/app-json/src/triggers/triggers.go | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/app-json/Makefile b/plugins/app-json/Makefile index 9b92fd230..b0372525f 100644 --- a/plugins/app-json/Makefile +++ b/plugins/app-json/Makefile @@ -1,5 +1,5 @@ SUBCOMMANDS = subcommands/report subcommands/set -TRIGGERS = triggers/install triggers/post-delete triggers/post-deploy triggers/pre-deploy +TRIGGERS = triggers/install triggers/post-delete triggers/post-deploy triggers/pre-deploy triggers/report BUILD = commands subcommands triggers PLUGIN_NAME = app-json diff --git a/plugins/app-json/src/triggers/triggers.go b/plugins/app-json/src/triggers/triggers.go index 7b1a67b1e..5268581c8 100644 --- a/plugins/app-json/src/triggers/triggers.go +++ b/plugins/app-json/src/triggers/triggers.go @@ -31,6 +31,9 @@ func main() { appName := flag.Arg(0) imageTag := flag.Arg(1) err = appjson.TriggerPreDeploy(appName, imageTag) + case "report": + appName := flag.Arg(0) + err = appjson.ReportSingleApp(appName, "", "") default: err = fmt.Errorf("Invalid plugin trigger call: %s", trigger) } From 913f709c39a6b5cd7bd1869c855fc16cb16dce92 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Mon, 22 Mar 2021 04:10:03 -0400 Subject: [PATCH 08/32] fix: add missing trigger to builder plugin --- plugins/builder/src/triggers/triggers.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/builder/src/triggers/triggers.go b/plugins/builder/src/triggers/triggers.go index ff3e4beb2..7a5fce4ed 100644 --- a/plugins/builder/src/triggers/triggers.go +++ b/plugins/builder/src/triggers/triggers.go @@ -29,6 +29,10 @@ func main() { case "report": appName := flag.Arg(0) err = builder.ReportSingleApp(appName, "", "") + case "core-post-extract": + appName := flag.Arg(0) + sourceWorkDir := flag.Arg(1) + err = builder.TriggerCorePostExtract(appName, sourceWorkDir) default: err = fmt.Errorf("Invalid plugin trigger call: %s", trigger) } From 5c04328081333e40d8f90c354b62a248f0e4fd8d Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Wed, 14 Apr 2021 13:53:57 -0400 Subject: [PATCH 09/32] fix: correct filename --- .../builder-dockerfile/{internal-commands => internal-functions} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/builder-dockerfile/{internal-commands => internal-functions} (100%) diff --git a/plugins/builder-dockerfile/internal-commands b/plugins/builder-dockerfile/internal-functions similarity index 100% rename from plugins/builder-dockerfile/internal-commands rename to plugins/builder-dockerfile/internal-functions From cb16e11cf5e999ad777c1ead25dc182df2fed5b9 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Wed, 14 Apr 2021 14:07:35 -0400 Subject: [PATCH 10/32] fix: correct filename --- plugins/builder-pack/{internal-commands => internal-functions} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/builder-pack/{internal-commands => internal-functions} (100%) diff --git a/plugins/builder-pack/internal-commands b/plugins/builder-pack/internal-functions similarity index 100% rename from plugins/builder-pack/internal-commands rename to plugins/builder-pack/internal-functions From d68473bfc296497dabbbe93dc785a417d3097863 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Wed, 14 Apr 2021 14:56:58 -0400 Subject: [PATCH 11/32] refactor: cleanup Dockerfile and project.toml lookups --- plugins/builder-dockerfile/builder-build | 15 +++++++-------- plugins/builder-pack/builder-build | 12 +++++++----- plugins/builder-pack/internal-functions | 16 ++++++++-------- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/plugins/builder-dockerfile/builder-build b/plugins/builder-dockerfile/builder-build index 6a4fc60a8..8a73960c4 100755 --- a/plugins/builder-dockerfile/builder-build +++ b/plugins/builder-dockerfile/builder-build @@ -18,20 +18,19 @@ trigger-builder-dockerfile-builder-build() { local IMAGE=$(get_app_image_name "$APP") local DOCKER_BUILD_LABEL_ARGS="--label=org.label-schema.schema-version=1.0 --label=org.label-schema.vendor=dokku --label=com.dokku.app-name=$APP" + local dockerfile_path=Dockerfile pushd "$SOURCECODE_WORK_DIR" &>/dev/null local NEW_DOCKERFILE="$(fn-builder-dockerfile-computed-dockerfile-path "$APP")" - if [[ -f "$NEW_DOCKERFILE" ]]; then + if [[ -n "$NEW_DOCKERFILE" ]]; then + if [[ ! -f "$NEW_DOCKERFILE" ]]; then + dokku_log_fail "Invalid dockerfile-path specified: $NEW_DOCKERFILE" + fi + if [[ "$NEW_DOCKERFILE" != "Dockerfile" ]]; then mv "$NEW_DOCKERFILE" Dockerfile fi - else - rm Dockerfile - fi - - if [[ ! -f Dockerfile ]]; then - dokku_log_fail "Invalid dockerfile-path specified: $dockerfile_path" fi # extract first port from Dockerfile @@ -49,7 +48,7 @@ trigger-builder-dockerfile-builder-build() { declare -a ARG_ARRAY eval "ARG_ARRAY=($DOCKER_ARGS)" - "$DOCKER_BIN" image build --file "$dockerfile_path" "${DOCKER_BUILD_LABEL_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS "${ARG_ARRAY[@]}" "${DOKKU_DOCKER_BUILD_OPTS[@]}" -t $IMAGE . + "$DOCKER_BIN" image build "${DOCKER_BUILD_LABEL_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS "${ARG_ARRAY[@]}" "${DOKKU_DOCKER_BUILD_OPTS[@]}" -t $IMAGE . plugn trigger post-build-dockerfile "$APP" } diff --git a/plugins/builder-pack/builder-build b/plugins/builder-pack/builder-build index 6a54e296f..cc943e674 100755 --- a/plugins/builder-pack/builder-build +++ b/plugins/builder-pack/builder-build @@ -29,13 +29,15 @@ trigger-builder-pack-builder-build() { pushd "$SOURCECODE_WORK_DIR" &>/dev/null - local NEW_PROJECT_TOML="$(fn-builder-pack-computed-projectoml-path "$APP")" - if [[ -f "$NEW_PROJECT_TOML" ]]; then - if [[ "$NEW_DOCKERFILE" != "project.toml" ]]; then + local NEW_PROJECT_TOML="$(fn-builder-pack-computed-projecttoml-path "$APP")" + if [[ -n "$NEW_PROJECT_TOML" ]]; then + if [[ ! -f "$NEW_PROJECT_TOML" ]]; then + dokku_log_fail "Invalid projecttoml-path specified: $NEW_PROJECT_TOML" + fi + + if [[ "$NEW_PROJECT_TOML" != "project.toml" ]]; then mv "$NEW_PROJECT_TOML" project.toml fi - else - rm project.toml fi local TMP_FILE=$(mktemp "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX") diff --git a/plugins/builder-pack/internal-functions b/plugins/builder-pack/internal-functions index 1cabe473d..72c4b73f4 100755 --- a/plugins/builder-pack/internal-functions +++ b/plugins/builder-pack/internal-functions @@ -36,9 +36,9 @@ cmd-builder-pack-report-single() { fi verify_app_name "$APP" local flag_map=( - "--builder-pack-computed-projecttoml-path: $(fn-builder-pack-computed-projectoml-path "$APP")" - "--builder-pack-global-projecttoml-path: $(fn-builder-pack-global-projectoml-path "$APP")" - "--builder-pack-projecttoml-path: $(fn-builder-pack-projectoml-path "$APP")" + "--builder-pack-computed-projecttoml-path: $(fn-builder-pack-computed-projecttoml-path "$APP")" + "--builder-pack-global-projecttoml-path: $(fn-builder-pack-global-projecttoml-path "$APP")" + "--builder-pack-projecttoml-path: $(fn-builder-pack-projecttoml-path "$APP")" ) if [[ -z "$INFO_FLAG" ]]; then @@ -67,24 +67,24 @@ cmd-builder-pack-report-single() { fi } -fn-builder-pack-computed-projectoml-path() { +fn-builder-pack-computed-projecttoml-path() { declare APP="$1" - file="$(fn-builder-pack-projectoml-path "$APP")" + file="$(fn-builder-pack-projecttoml-path "$APP")" if [[ "$file" == "" ]]; then - file="$(fn-builder-pack-global-projectoml-path "$APP")" + file="$(fn-builder-pack-global-projecttoml-path "$APP")" fi echo "$file" } -fn-builder-pack-global-projectoml-path() { +fn-builder-pack-global-projecttoml-path() { declare APP="$1" fn-plugin-property-get "builder-pack" "--global" "projecttoml-path" "project.toml" } -fn-builder-pack-projectoml-path() { +fn-builder-pack-projecttoml-path() { declare APP="$1" fn-plugin-property-get "builder-pack" "$APP" "projecttoml-path" "" From 326031d28939a63f5569927b28a6a22c1f00228b Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 23 May 2021 17:35:40 -0400 Subject: [PATCH 12/32] fix: drop unnecessary report hook --- plugins/builder-herokuish/report | 6 ------ 1 file changed, 6 deletions(-) delete mode 100755 plugins/builder-herokuish/report diff --git a/plugins/builder-herokuish/report b/plugins/builder-herokuish/report deleted file mode 100755 index 785102c30..000000000 --- a/plugins/builder-herokuish/report +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash -source "$PLUGIN_AVAILABLE_PATH/builder-herokuish/internal-functions" -set -eo pipefail -[[ $DOKKU_TRACE ]] && set -x - -cmd-builder-herokuish-report-single "$@" From 79cd7e4cabb7a788ab8731c0529e917ef2c0cfeb Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 23 May 2021 18:01:29 -0400 Subject: [PATCH 13/32] feat: do not fail build when missing project.toml --- plugins/builder-pack/builder-build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/builder-pack/builder-build b/plugins/builder-pack/builder-build index cc943e674..1ea07c4e3 100755 --- a/plugins/builder-pack/builder-build +++ b/plugins/builder-pack/builder-build @@ -31,7 +31,7 @@ trigger-builder-pack-builder-build() { local NEW_PROJECT_TOML="$(fn-builder-pack-computed-projecttoml-path "$APP")" if [[ -n "$NEW_PROJECT_TOML" ]]; then - if [[ ! -f "$NEW_PROJECT_TOML" ]]; then + if [[ ! -f "$NEW_PROJECT_TOML" ]] && [[ "$NEW_PROJECT_TOML" != "project.toml" ]]; then dokku_log_fail "Invalid projecttoml-path specified: $NEW_PROJECT_TOML" fi From f62373c3fa00a8ebfe28da4472a92a651dd73f7f Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 23 May 2021 18:03:33 -0400 Subject: [PATCH 14/32] docs: add notes for what happens if the specified values do not exist --- docs/advanced-usage/deployment-tasks.md | 2 +- docs/deployment/builders/builder-management.md | 2 +- docs/deployment/builders/cloud-native-buildpacks.md | 2 +- docs/deployment/builders/dockerfiles.md | 2 +- docs/processes/process-management.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/advanced-usage/deployment-tasks.md b/docs/advanced-usage/deployment-tasks.md index e293751f5..6b18c7f7f 100644 --- a/docs/advanced-usage/deployment-tasks.md +++ b/docs/advanced-usage/deployment-tasks.md @@ -55,7 +55,7 @@ Please keep the above in mind when utilizing deployment tasks. ### Changing the `app.json` location -When deploying a monorepo, it may be desirable to specify the specific path of the `app.json` file to use for a given app. This can be done via the `app-json:set` command. +When deploying a monorepo, it may be desirable to specify the specific path of the `app.json` file to use for a given app. This can be done via the `app-json:set` command. If a value is specified and that file does not exist within the repository, Dokku will continue the build process as if the repository has no `app.json` file. ```shell dokku app-json:set node-js-app appjson-path second-app.json diff --git a/docs/deployment/builders/builder-management.md b/docs/deployment/builders/builder-management.md index 38f2c1f7f..fe28fa2a7 100644 --- a/docs/deployment/builders/builder-management.md +++ b/docs/deployment/builders/builder-management.md @@ -51,7 +51,7 @@ dokku builder:set --global selected > Warning: Please keep in mind that setting a custom build directory will result in loss of any changes to the top-level directory, such as the `git.keep-git-dir` property. -When deploying a monorepo, it may be desirable to specify the specific build directory to use for a given app. This can be done via the `builder:set` command. +When deploying a monorepo, it may be desirable to specify the specific build directory to use for a given app. This can be done via the `builder:set` command. If a value is specified and that directory does not exist within the repository, the build will fail. ```shell dokku builder:set node-js-app build-dir app2 diff --git a/docs/deployment/builders/cloud-native-buildpacks.md b/docs/deployment/builders/cloud-native-buildpacks.md index f7e7daa06..e20a01fac 100644 --- a/docs/deployment/builders/cloud-native-buildpacks.md +++ b/docs/deployment/builders/cloud-native-buildpacks.md @@ -53,7 +53,7 @@ dokku builder:set node-js-app selected pack ### Changing the `project.toml` location -When deploying a monorepo, it may be desirable to specify the specific path of the `project.toml` file to use for a given app. This can be done via the `builder-pack:set` command. +When deploying a monorepo, it may be desirable to specify the specific path of the `project.toml` file to use for a given app. This can be done via the `builder-pack:set` command. If a value other than `project.toml` is specified and that file does not exist in the app's build directory, then the build will fail. ```shell dokku builder-pack:set node-js-app projecttoml-path project2.toml diff --git a/docs/deployment/builders/dockerfiles.md b/docs/deployment/builders/dockerfiles.md index 33b3c4c69..f8aac829a 100644 --- a/docs/deployment/builders/dockerfiles.md +++ b/docs/deployment/builders/dockerfiles.md @@ -31,7 +31,7 @@ dokku config:unset --no-restart node-js-app DOKKU_PROXY_PORT_MAP > The previous method to perform this - via `docker-options:add` - should be removed in favor of the `builder-dockerfile:set` command outlined here. -When deploying a monorepo, it may be desirable to specify the specific path of the `Dockerfile` file to use for a given app. This can be done via the `builder-dockerfile:set` command. +When deploying a monorepo, it may be desirable to specify the specific path of the `Dockerfile` file to use for a given app. This can be done via the `builder-dockerfile:set` command. If a value is specified and that file does not exist in the app's build directory, then the build will fail. ```shell dokku builder-dockerfile:set node-js-app dockerfile-path Dockerfile2 diff --git a/docs/processes/process-management.md b/docs/processes/process-management.md index 09f03563f..8b29bfb7d 100644 --- a/docs/processes/process-management.md +++ b/docs/processes/process-management.md @@ -158,7 +158,7 @@ There are also a few other exceptions for the `web` process. #### Changing the `Procfile` location -When deploying a monorepo, it may be desirable to specify the specific path of the `Procfile` file to use for a given app. This can be done via the `ps:set` command. +When deploying a monorepo, it may be desirable to specify the specific path of the `Procfile` file to use for a given app. This can be done via the `ps:set` command. If a value is specified and that file does not exist within the repository, Dokku will continue the build process as if the repository has no `Procfile`. ```shell dokku ps:set node-js-app procfile-path Procfile2 From bdfb1ee549231109151bb3cc662ffa8c976acbc9 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Fri, 9 Jul 2021 23:15:39 -0400 Subject: [PATCH 15/32] fix: add entries to app-json gitignore --- plugins/app-json/.gitignore | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/plugins/app-json/.gitignore b/plugins/app-json/.gitignore index f7dc085bc..abe58586d 100644 --- a/plugins/app-json/.gitignore +++ b/plugins/app-json/.gitignore @@ -1,5 +1,8 @@ -/triggers/* -/triggers -/pre-* -/post-* +/commands /install +/post-* +/pre-* +/report +/subcommands/* +/triggers +/triggers/* From 0bd6970b4b69e717ed157f9f1808e9bda6458773 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Fri, 9 Jul 2021 23:15:56 -0400 Subject: [PATCH 16/32] chore: update go.sum --- plugins/app-json/go.sum | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/app-json/go.sum b/plugins/app-json/go.sum index 9fdb858d0..c8010149d 100644 --- a/plugins/app-json/go.sum +++ b/plugins/app-json/go.sum @@ -6,6 +6,7 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNU 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= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= From 5901c57bde32398b274c325a0d97fbc5e9bc36f1 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Fri, 9 Jul 2021 23:21:17 -0400 Subject: [PATCH 17/32] docs: fix style issues --- docs/development/plugin-triggers.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/development/plugin-triggers.md b/docs/development/plugin-triggers.md index c75aa7c9f..a9d211c34 100644 --- a/docs/development/plugin-triggers.md +++ b/docs/development/plugin-triggers.md @@ -344,9 +344,9 @@ curl "http://httpstat.us/200" ### `core-post-extract` -> To avoid issues with community plugins, this plugin trigger should be used *only* for core plugins. Please avoid using this trigger in your own plugins. +> To avoid issues with community plugins, this plugin trigger should be used _only_ for core plugins. Please avoid using this trigger in your own plugins. -- Description: Allows you to modify the contents of an app *after* it has been extracted from git/tarball but *before* the image source type is detected. +- Description: Allows you to modify the contents of an app _after_ it has been extracted from git/tarball but _before_ the image source type is detected. - Invoked by: `dokku tar:in`, `dokku tar:from` and the `receive-app` plugin trigger - Arguments: `$APP` `$TMP_WORK_DIR` `$REV` - Example: From 0ab135b03437dffa6c2c83c70341697c49e5241d Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Fri, 9 Jul 2021 23:56:22 -0400 Subject: [PATCH 18/32] tests: add test for app-json:set --- plugins/app-json/subcommands.go | 2 +- tests/apps/python/app2.json | 8 ++++++++ tests/unit/app-json.bats | 26 ++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 tests/apps/python/app2.json diff --git a/plugins/app-json/subcommands.go b/plugins/app-json/subcommands.go index f402dd354..b2f396281 100644 --- a/plugins/app-json/subcommands.go +++ b/plugins/app-json/subcommands.go @@ -24,6 +24,6 @@ func CommandReport(appName string, format string, infoFlag string) error { // CommandSet set or clear a builder property for an app func CommandSet(appName string, property string, value string) error { - common.CommandPropertySet("builder", appName, property, value, DefaultProperties, GlobalProperties) + common.CommandPropertySet("app-json", appName, property, value, DefaultProperties, GlobalProperties) return nil } diff --git a/tests/apps/python/app2.json b/tests/apps/python/app2.json new file mode 100644 index 000000000..dddcc032b --- /dev/null +++ b/tests/apps/python/app2.json @@ -0,0 +1,8 @@ +{ + "scripts": { + "dokku": { + "predeploy": "touch /app/predeploy2.test", + "postdeploy": "touch /app/postdeploy.test" + } + } +} diff --git a/tests/unit/app-json.bats b/tests/unit/app-json.bats index 31d99d365..5e297ed21 100644 --- a/tests/unit/app-json.bats +++ b/tests/unit/app-json.bats @@ -151,3 +151,29 @@ teardown() { echo "status: $status" assert_success } + +@test "(app-json:set)" { + run /bin/bash -c "dokku app-json:set $TEST_APP appjson-path app2.json" + echo "output: $output" + echo "status: $status" + assert_success + + run deploy_app python + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "touch /app/predeploy2.test" + + run /bin/bash -c "dokku app-json:set $TEST_APP appjson-path" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:rebuild $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "touch /app/predeploy.test" + assert_output_contains "touch /app/predeploy2.test" 0 + +} From 441d1c267682ff9cf01b555df3f1ce4e35a62ecb Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sat, 10 Jul 2021 00:06:00 -0400 Subject: [PATCH 19/32] tests: add test for non-existent file --- tests/unit/app-json.bats | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/unit/app-json.bats b/tests/unit/app-json.bats index 5e297ed21..12fefc8f9 100644 --- a/tests/unit/app-json.bats +++ b/tests/unit/app-json.bats @@ -153,7 +153,7 @@ teardown() { } @test "(app-json:set)" { - run /bin/bash -c "dokku app-json:set $TEST_APP appjson-path app2.json" + run /bin/bash -c "dokku app-json:set $TEST_APP appjson-path app-nonexistent.json" echo "output: $output" echo "status: $status" assert_success @@ -162,6 +162,17 @@ teardown() { echo "output: $output" echo "status: $status" assert_success + assert_output_contains "touch /app/predeploy.test" 0 + + run /bin/bash -c "dokku app-json:set $TEST_APP appjson-path app2.json" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:rebuild $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success assert_output_contains "touch /app/predeploy2.test" run /bin/bash -c "dokku app-json:set $TEST_APP appjson-path" @@ -175,5 +186,4 @@ teardown() { assert_success assert_output_contains "touch /app/predeploy.test" assert_output_contains "touch /app/predeploy2.test" 0 - } From fda75cbaa5c10e673523d719ceb8e4247d4ec3ac Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sat, 10 Jul 2021 00:47:27 -0400 Subject: [PATCH 20/32] fix: gitignore correct file --- plugins/builder/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/builder/.gitignore b/plugins/builder/.gitignore index 6e17f68a7..6f788ece8 100644 --- a/plugins/builder/.gitignore +++ b/plugins/builder/.gitignore @@ -1,5 +1,5 @@ /commands -/core-post-deploy +/core-post-extract /subcommands/* /triggers/* /triggers From 377ca5ca2201a89bb7ff4d00dcdf064a277d74af Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sat, 10 Jul 2021 00:48:47 -0400 Subject: [PATCH 21/32] fix: properly handle directory replacement The previous version _also_ deleted the temp working dir, causing issues with subsequent directory access. --- plugins/builder/functions.go | 20 ++++++++++++++++++++ plugins/builder/go.mod | 9 +++++---- plugins/builder/go.sum | 6 ++++++ plugins/builder/triggers.go | 9 +++++---- 4 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 plugins/builder/functions.go diff --git a/plugins/builder/functions.go b/plugins/builder/functions.go new file mode 100644 index 000000000..eb90e10ab --- /dev/null +++ b/plugins/builder/functions.go @@ -0,0 +1,20 @@ +package builder + +import ( + "io/ioutil" + "os" + "path" +) + +func removeAllContents(basePath string) error { + dir, err := ioutil.ReadDir(basePath) + if err != nil { + return err + } + + for _, d := range dir { + os.RemoveAll(path.Join([]string{basePath, d.Name()}...)) + } + + return nil +} diff --git a/plugins/builder/go.mod b/plugins/builder/go.mod index a382f3f9c..e96f12bc1 100644 --- a/plugins/builder/go.mod +++ b/plugins/builder/go.mod @@ -3,10 +3,11 @@ module github.com/dokku/dokku/plugins/builder go 1.15 require ( - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 - github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 - github.com/spf13/pflag v1.0.5 // indirect + github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 + github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 + github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 + github.com/otiai10/copy v1.6.0 + github.com/spf13/pflag v1.0.5 // indirect ) replace github.com/dokku/dokku/plugins/common => ../common diff --git a/plugins/builder/go.sum b/plugins/builder/go.sum index 58c904707..0b2bcb52a 100644 --- a/plugins/builder/go.sum +++ b/plugins/builder/go.sum @@ -2,6 +2,12 @@ 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/otiai10/copy v1.6.0 h1:IinKAryFFuPONZ7cm6T6E2QX/vcJwSnlaA5lfoaXIiQ= +github.com/otiai10/copy v1.6.0/go.mod h1:XWfuS3CrI0R6IE0FbgHsEazaXO8G0LpMp9o8tos0x4E= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/otiai10/mint v1.3.2/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= 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= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= diff --git a/plugins/builder/triggers.go b/plugins/builder/triggers.go index b0c0bfe03..b711f8a7c 100644 --- a/plugins/builder/triggers.go +++ b/plugins/builder/triggers.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/dokku/dokku/plugins/common" + "github.com/otiai10/copy" ) // TriggerBuilderDetect outputs a manually selected builder for the app @@ -42,19 +43,19 @@ func TriggerCorePostExtract(appName string, sourceWorkDir string) error { return fmt.Errorf("Unable to create temporary working directory: %v", err.Error()) } - if err := os.RemoveAll(tmpWorkDir); err != nil { + if err := removeAllContents(tmpWorkDir); err != nil { return fmt.Errorf("Unable to clear out temporary working directory for rewrite: %v", err.Error()) } - if err := os.Rename(newSourceWorkDir, tmpWorkDir); err != nil { + if err := copy.Copy(newSourceWorkDir, tmpWorkDir); err != nil { return fmt.Errorf("Unable to move build-dir to temporary working directory: %v", err.Error()) } - if err := os.RemoveAll(sourceWorkDir); err != nil { + if err := removeAllContents(sourceWorkDir); err != nil { return fmt.Errorf("Unable to clear out sourcecode working directory for rewrite: %v", err.Error()) } - if err := os.Rename(tmpWorkDir, sourceWorkDir); err != nil { + if err := copy.Copy(tmpWorkDir, sourceWorkDir); err != nil { return fmt.Errorf("Unable to move build-dir to sourcecode working directory: %v", err.Error()) } From 2580ad305c1aa394c8aefa06d12ed4aca94a9561 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sat, 10 Jul 2021 00:49:23 -0400 Subject: [PATCH 22/32] tests: ensure app deploys successfully by default in appjson-path test --- tests/unit/app-json.bats | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/unit/app-json.bats b/tests/unit/app-json.bats index 12fefc8f9..09aa65597 100644 --- a/tests/unit/app-json.bats +++ b/tests/unit/app-json.bats @@ -153,12 +153,17 @@ teardown() { } @test "(app-json:set)" { + run deploy_app python + echo "output: $output" + echo "status: $status" + assert_success + run /bin/bash -c "dokku app-json:set $TEST_APP appjson-path app-nonexistent.json" echo "output: $output" echo "status: $status" assert_success - run deploy_app python + run /bin/bash -c "dokku ps:rebuild $TEST_APP" echo "output: $output" echo "status: $status" assert_success From d4016223d551eb79bb7468b3abc726552912601a Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sat, 10 Jul 2021 00:49:36 -0400 Subject: [PATCH 23/32] tests: add tests for build-dir --- tests/apps/python/sub-app/Procfile | 2 ++ tests/apps/python/sub-app/null | 0 tests/apps/python/sub-app/release.py | 10 +++++++ tests/apps/python/sub-app/web.py | 23 ++++++++++++++++ tests/unit/builder.bats | 39 ++++++++++++++++++++++++++++ 5 files changed, 74 insertions(+) create mode 100644 tests/apps/python/sub-app/Procfile create mode 100644 tests/apps/python/sub-app/null create mode 100644 tests/apps/python/sub-app/release.py create mode 100644 tests/apps/python/sub-app/web.py diff --git a/tests/apps/python/sub-app/Procfile b/tests/apps/python/sub-app/Procfile new file mode 100644 index 000000000..bb1e3346a --- /dev/null +++ b/tests/apps/python/sub-app/Procfile @@ -0,0 +1,2 @@ +web: python3 web.py +release: python3 release.py diff --git a/tests/apps/python/sub-app/null b/tests/apps/python/sub-app/null new file mode 100644 index 000000000..e69de29bb diff --git a/tests/apps/python/sub-app/release.py b/tests/apps/python/sub-app/release.py new file mode 100644 index 000000000..0fc4d2495 --- /dev/null +++ b/tests/apps/python/sub-app/release.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +import os + + +def main(): + print("SECRET_KEYS: {0}".format(os.getenv('SECRET_KEY'))) + + +if __name__ == '__main__': + main() diff --git a/tests/apps/python/sub-app/web.py b/tests/apps/python/sub-app/web.py new file mode 100644 index 000000000..c7c3d36a3 --- /dev/null +++ b/tests/apps/python/sub-app/web.py @@ -0,0 +1,23 @@ +import http.server +import json +import os + + +class GetHandler(http.server.BaseHTTPRequestHandler): + def do_GET(self): + self.send_response(200) + self.send_header("Content-Type", "text/plain; charset=utf-8") + self.end_headers() + + if self.path == '/': + self.wfile.write("python/http.server".encode("utf-8")) + else: + data = json.dumps(dict(os.environ), sort_keys=True, indent=4) + self.wfile.write(data.encode("utf-8")) + + +if __name__ == "__main__": + port = int(os.getenv("PORT", 5000)) + server = http.server.HTTPServer(("0.0.0.0", port), GetHandler) + print("Listening on port {0}".format(port)) + server.serve_forever() diff --git a/tests/unit/builder.bats b/tests/unit/builder.bats index 3ee605314..9caf52f3c 100644 --- a/tests/unit/builder.bats +++ b/tests/unit/builder.bats @@ -187,3 +187,42 @@ teardown() { assert_success assert_line 0 "herokuish" } + +@test "(builder:set)" { + run deploy_app python + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku builder:set $TEST_APP build-dir nonexistent-app" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:rebuild $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_failure + + run /bin/bash -c "dokku builder:set $TEST_APP build-dir sub-app" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:rebuild $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains 'SECRET_KEYS:' + + run /bin/bash -c "dokku builder:set $TEST_APP build-dir" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:rebuild $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains 'SECRET_KEY:' +} From a4b024d6f988e5deadb24d1973db29e82cd32154 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sat, 10 Jul 2021 01:04:32 -0400 Subject: [PATCH 24/32] tests: add a test for dockerfile-path --- tests/apps/dockerfile/second.Dockerfile | 15 ++++++++ tests/unit/builder-dockerfile.bats | 50 +++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 tests/apps/dockerfile/second.Dockerfile create mode 100644 tests/unit/builder-dockerfile.bats diff --git a/tests/apps/dockerfile/second.Dockerfile b/tests/apps/dockerfile/second.Dockerfile new file mode 100644 index 000000000..d765110a5 --- /dev/null +++ b/tests/apps/dockerfile/second.Dockerfile @@ -0,0 +1,15 @@ +FROM node:4-alpine + +RUN apk add --no-cache bash + +EXPOSE 3001/udp +EXPOSE 3000/tcp +EXPOSE 3003 + +COPY . /var/www/html +WORKDIR /var/www/html +RUN npm install + +RUN echo hi + +CMD npm start diff --git a/tests/unit/builder-dockerfile.bats b/tests/unit/builder-dockerfile.bats new file mode 100644 index 000000000..b9138e16f --- /dev/null +++ b/tests/unit/builder-dockerfile.bats @@ -0,0 +1,50 @@ +#!/usr/bin/env bats + +load test_helper + +setup() { + create_app +} + +teardown() { + destroy_app +} + +@test "(builder-dockerfile:set)" { + run deploy_app dockerfile + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku builder-dockerfile:set $TEST_APP dockerfile-path nonexistent-dockerfile" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:rebuild $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_failure + + run /bin/bash -c "dokku builder-dockerfile:set $TEST_APP dockerfile-path second.Dockerfile" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:rebuild $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains 'echo hi' + + run /bin/bash -c "dokku builder-dockerfile:set $TEST_APP dockerfile-path" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:rebuild $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains 'echo hi' 0 +} From a22391b7ada8dada9027040bd6e864bc176cd01a Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sat, 10 Jul 2021 01:32:57 -0400 Subject: [PATCH 25/32] fix: copy the specified Procfile into place at the earliest possibility --- plugins/ps/.gitignore | 15 ++++++++------- plugins/ps/Makefile | 2 +- plugins/ps/functions.go | 2 +- plugins/ps/go.mod | 3 ++- plugins/ps/go.sum | 6 ++++++ plugins/ps/src/triggers/triggers.go | 4 ++++ plugins/ps/triggers.go | 27 ++++++++++++++++++++++++++- 7 files changed, 48 insertions(+), 11 deletions(-) diff --git a/plugins/ps/.gitignore b/plugins/ps/.gitignore index 528524b69..413fc555d 100644 --- a/plugins/ps/.gitignore +++ b/plugins/ps/.gitignore @@ -1,12 +1,13 @@ +/app-restart /commands -/subcommands/* -/triggers/* -/triggers -/proxy-* +/core-post-deploy +/core-post-extract /install /post-* -/report /pre-* /procfile-* -/app-restart -/core-post-deploy +/proxy-* +/report +/subcommands/* +/triggers +/triggers/* diff --git a/plugins/ps/Makefile b/plugins/ps/Makefile index b45ea6d12..0761c2505 100644 --- a/plugins/ps/Makefile +++ b/plugins/ps/Makefile @@ -1,5 +1,5 @@ SUBCOMMANDS = subcommands/inspect subcommands/rebuild subcommands/report subcommands/restart subcommands/restore subcommands/retire subcommands/scale subcommands/set subcommands/start subcommands/stop -TRIGGERS = triggers/app-restart triggers/core-post-deploy triggers/install triggers/post-app-clone triggers/post-app-clone-setup triggers/post-app-rename triggers/post-app-rename-setup triggers/post-create triggers/post-delete triggers/post-extract triggers/post-stop triggers/pre-deploy triggers/procfile-extract triggers/procfile-get-command triggers/procfile-remove triggers/report +TRIGGERS = triggers/app-restart triggers/core-post-deploy triggers/core-post-extract triggers/install triggers/post-app-clone triggers/post-app-clone-setup triggers/post-app-rename triggers/post-app-rename-setup triggers/post-create triggers/post-delete triggers/post-extract triggers/post-stop triggers/pre-deploy triggers/procfile-extract triggers/procfile-get-command triggers/procfile-remove triggers/report BUILD = commands subcommands triggers PLUGIN_NAME = ps diff --git a/plugins/ps/functions.go b/plugins/ps/functions.go index 713334abc..f6a47bbe8 100644 --- a/plugins/ps/functions.go +++ b/plugins/ps/functions.go @@ -21,7 +21,7 @@ func canScaleApp(appName string) bool { func extractProcfile(appName, image string) error { destination := getProcfilePath(appName) - common.CopyFromImage(appName, image, reportComputedProcfilePath(appName), destination) + common.CopyFromImage(appName, image, "Procfile", destination) if !common.FileExists(destination) { common.LogInfo1Quiet("No Procfile found in app image") return nil diff --git a/plugins/ps/go.mod b/plugins/ps/go.mod index 946afcefc..4655cac06 100644 --- a/plugins/ps/go.mod +++ b/plugins/ps/go.mod @@ -8,8 +8,9 @@ require ( github.com/dokku/dokku/plugins/config v0.0.0-00010101000000-000000000000 github.com/dokku/dokku/plugins/docker-options v0.0.0-00010101000000-000000000000 github.com/gofrs/flock v0.8.0 + github.com/otiai10/copy v1.6.0 github.com/ryanuber/columnize v1.1.2-0.20190319233515-9e6335e58db3 - github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/pflag v1.0.5 // indirect ) replace github.com/dokku/dokku/plugins/common => ../common diff --git a/plugins/ps/go.sum b/plugins/ps/go.sum index c6f028d99..625b68248 100644 --- a/plugins/ps/go.sum +++ b/plugins/ps/go.sum @@ -8,6 +8,12 @@ github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14j github.com/joho/godotenv v1.2.0 h1:vGTvz69FzUFp+X4/bAkb0j5BoLC+9bpqTWY8mjhA9pc= github.com/joho/godotenv v1.2.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/otiai10/copy v1.6.0 h1:IinKAryFFuPONZ7cm6T6E2QX/vcJwSnlaA5lfoaXIiQ= +github.com/otiai10/copy v1.6.0/go.mod h1:XWfuS3CrI0R6IE0FbgHsEazaXO8G0LpMp9o8tos0x4E= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/otiai10/mint v1.3.2/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= 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= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= diff --git a/plugins/ps/src/triggers/triggers.go b/plugins/ps/src/triggers/triggers.go index d60afa0c4..35d3bc675 100644 --- a/plugins/ps/src/triggers/triggers.go +++ b/plugins/ps/src/triggers/triggers.go @@ -24,6 +24,10 @@ func main() { case "core-post-deploy": appName := flag.Arg(0) err = ps.TriggerCorePostDeploy(appName) + case "core-post-extract": + appName := flag.Arg(0) + sourceWorkDir := flag.Arg(1) + err = ps.TriggerCorePostExtract(appName, sourceWorkDir) case "install": err = ps.TriggerInstall() case "post-app-clone": diff --git a/plugins/ps/triggers.go b/plugins/ps/triggers.go index 90e81ac7e..af6fd2cca 100644 --- a/plugins/ps/triggers.go +++ b/plugins/ps/triggers.go @@ -3,6 +3,7 @@ package ps import ( "fmt" "os" + "path" "path/filepath" "strings" @@ -10,6 +11,7 @@ import ( "github.com/dokku/dokku/plugins/common" "github.com/dokku/dokku/plugins/config" dockeroptions "github.com/dokku/dokku/plugins/docker-options" + "github.com/otiai10/copy" ) // TriggerAppRestart restarts an app @@ -29,6 +31,29 @@ func TriggerCorePostDeploy(appName string) error { }) } +// TriggerCorePostExtract ensures that the main Procfile is the one specified by procfile-path +func TriggerCorePostExtract(appName string, sourceWorkDir string) error { + procfilePath := strings.Trim(reportComputedProcfilePath(appName), "/") + if procfilePath == "" || procfilePath == "Procfile" { + return nil + } + + if err := os.Remove(path.Join(sourceWorkDir, "Procfile")); err != nil { + return fmt.Errorf("Unable to remove existing Procfile: %v", err.Error()) + } + + fullProcfilePath := path.Join(sourceWorkDir, procfilePath) + if !common.FileExists(fullProcfilePath) { + return nil + } + + if err := copy.Copy(fullProcfilePath, path.Join(sourceWorkDir, "Procfile")); err != nil { + return fmt.Errorf("Unable to move specified Procfile into place: %v", err.Error()) + } + + return nil +} + // TriggerInstall initializes app restart policies func TriggerInstall() error { if err := common.PropertySetup("ps"); err != nil { @@ -142,7 +167,7 @@ func TriggerPostDelete(appName string) error { // TriggerPostExtract validates a procfile func TriggerPostExtract(appName string, tempWorkDir string) error { - procfile := filepath.Join(tempWorkDir, reportComputedProcfilePath(appName)) + procfile := filepath.Join(tempWorkDir, "Procfile") if !common.FileExists(procfile) { return nil } From 135e78c868233fe528c1b40bb5c516568b77b47a Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sat, 10 Jul 2021 01:45:37 -0400 Subject: [PATCH 26/32] tests: add test for procfile-path --- tests/apps/dockerfile-procfile/Procfile | 1 + tests/apps/dockerfile-procfile/release.js | 3 ++ .../apps/dockerfile-procfile/second.Procfile | 8 ++++ tests/apps/python/second.Procfile | 1 + tests/unit/ps-general.bats | 41 +++++++++++++++++++ 5 files changed, 54 insertions(+) create mode 100644 tests/apps/dockerfile-procfile/release.js create mode 100644 tests/apps/dockerfile-procfile/second.Procfile create mode 100644 tests/apps/python/second.Procfile diff --git a/tests/apps/dockerfile-procfile/Procfile b/tests/apps/dockerfile-procfile/Procfile index 9c49227a7..a0e5c7d45 100644 --- a/tests/apps/dockerfile-procfile/Procfile +++ b/tests/apps/dockerfile-procfile/Procfile @@ -6,3 +6,4 @@ cron: node worker.js web: node web.js worker: node worker.js +release: node release.js diff --git a/tests/apps/dockerfile-procfile/release.js b/tests/apps/dockerfile-procfile/release.js new file mode 100644 index 000000000..0cc2afc3a --- /dev/null +++ b/tests/apps/dockerfile-procfile/release.js @@ -0,0 +1,3 @@ +var secret = process.env.SECRET_KEY || ""; + +console.log('SECRET_KEY: ' + secret); diff --git a/tests/apps/dockerfile-procfile/second.Procfile b/tests/apps/dockerfile-procfile/second.Procfile new file mode 100644 index 000000000..9c49227a7 --- /dev/null +++ b/tests/apps/dockerfile-procfile/second.Procfile @@ -0,0 +1,8 @@ +############################### +# DEVELOPMENT # +############################### + +# Procfile for development using the new threaded worker (scheduler, twitter stream and delayed job) +cron: node worker.js +web: node web.js +worker: node worker.js diff --git a/tests/apps/python/second.Procfile b/tests/apps/python/second.Procfile new file mode 100644 index 000000000..b03a168c7 --- /dev/null +++ b/tests/apps/python/second.Procfile @@ -0,0 +1 @@ +web: python3 web.py diff --git a/tests/unit/ps-general.bats b/tests/unit/ps-general.bats index ebe719428..0fed2d3fc 100644 --- a/tests/unit/ps-general.bats +++ b/tests/unit/ps-general.bats @@ -198,3 +198,44 @@ EOF assert_success assert_output_contains "bar" } + + +@test "(ps:set) procfile-path" { + run deploy_app dockerfile-procfile + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:set $TEST_APP procfile-path nonexistent-procfile" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:rebuild $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_failure + assert_output_contains "Could not start due to" + + run /bin/bash -c "dokku ps:set $TEST_APP procfile-path second.Procfile" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:rebuild $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains 'SECRET_KEY:' 0 + + run /bin/bash -c "dokku ps:set $TEST_APP procfile-path" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:rebuild $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains 'SECRET_KEY:' +} From 4022ebd31c62d46b9f494c0ef955a8596dc30df9 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sat, 10 Jul 2021 01:56:37 -0400 Subject: [PATCH 27/32] refactor: allow missing project.toml We should treat the project.toml as an optional file, as is the Procfile. Additionally, moving the file into place early will ensure there is no chance of selecting the wrong file. --- .../builders/cloud-native-buildpacks.md | 2 +- plugins/builder-pack/builder-build | 12 -------- plugins/builder-pack/core-post-extract | 30 +++++++++++++++++++ 3 files changed, 31 insertions(+), 13 deletions(-) create mode 100755 plugins/builder-pack/core-post-extract diff --git a/docs/deployment/builders/cloud-native-buildpacks.md b/docs/deployment/builders/cloud-native-buildpacks.md index e20a01fac..572a6d2c4 100644 --- a/docs/deployment/builders/cloud-native-buildpacks.md +++ b/docs/deployment/builders/cloud-native-buildpacks.md @@ -53,7 +53,7 @@ dokku builder:set node-js-app selected pack ### Changing the `project.toml` location -When deploying a monorepo, it may be desirable to specify the specific path of the `project.toml` file to use for a given app. This can be done via the `builder-pack:set` command. If a value other than `project.toml` is specified and that file does not exist in the app's build directory, then the build will fail. +When deploying a monorepo, it may be desirable to specify the specific path of the `project.toml` file to use for a given app. This can be done via the `builder-pack:set` command. If a value other than `project.toml` is specified and that file does not exist in the app's build directory, Dokku will continue the build process as if the repository has no `project.toml`. ```shell dokku builder-pack:set node-js-app projecttoml-path project2.toml diff --git a/plugins/builder-pack/builder-build b/plugins/builder-pack/builder-build index 1ea07c4e3..7a9644d14 100755 --- a/plugins/builder-pack/builder-build +++ b/plugins/builder-pack/builder-build @@ -1,7 +1,6 @@ #!/usr/bin/env bash source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" -source "$PLUGIN_AVAILABLE_PATH/builder-pack/internal-functions" set -eo pipefail [[ $DOKKU_TRACE ]] && set -x @@ -29,17 +28,6 @@ trigger-builder-pack-builder-build() { pushd "$SOURCECODE_WORK_DIR" &>/dev/null - local NEW_PROJECT_TOML="$(fn-builder-pack-computed-projecttoml-path "$APP")" - if [[ -n "$NEW_PROJECT_TOML" ]]; then - if [[ ! -f "$NEW_PROJECT_TOML" ]] && [[ "$NEW_PROJECT_TOML" != "project.toml" ]]; then - dokku_log_fail "Invalid projecttoml-path specified: $NEW_PROJECT_TOML" - fi - - if [[ "$NEW_PROJECT_TOML" != "project.toml" ]]; then - mv "$NEW_PROJECT_TOML" project.toml - fi - fi - local TMP_FILE=$(mktemp "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX") trap "rm -rf '$TMP_FILE' >/dev/null" RETURN INT TERM diff --git a/plugins/builder-pack/core-post-extract b/plugins/builder-pack/core-post-extract new file mode 100755 index 000000000..83ea6540e --- /dev/null +++ b/plugins/builder-pack/core-post-extract @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/builder-pack/internal-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +trigger-builder-pack-core-post-extract() { + declare desc="builder-pack post-extract plugin trigger" + declare trigger="post-extract" + declare APP="$1" SOURCECODE_WORK_DIR="$2" + local NEW_PROJECT_TOML="$(fn-builder-pack-computed-projecttoml-path "$APP")" + + pushd "$TMP_WORK_DIR" >/dev/null + + if [[ -z "$NEW_PROJECT_TOML" ]]; then + return + fi + + if [[ ! -f "$NEW_PROJECT_TOML" ]]; then + rm -f project.toml + return + fi + + if [[ "$NEW_PROJECT_TOML" != "project.toml" ]]; then + mv "$NEW_PROJECT_TOML" project.toml + fi + popd &>/dev/null +} + +trigger-builder-pack-post-extract "$@" From 24905e74a59612ab550d3fa54a4bae0797705110 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sat, 10 Jul 2021 01:56:50 -0400 Subject: [PATCH 28/32] chore: drop unused variable --- plugins/builder-dockerfile/builder-build | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/builder-dockerfile/builder-build b/plugins/builder-dockerfile/builder-build index 8a73960c4..7830eae68 100755 --- a/plugins/builder-dockerfile/builder-build +++ b/plugins/builder-dockerfile/builder-build @@ -18,7 +18,6 @@ trigger-builder-dockerfile-builder-build() { local IMAGE=$(get_app_image_name "$APP") local DOCKER_BUILD_LABEL_ARGS="--label=org.label-schema.schema-version=1.0 --label=org.label-schema.vendor=dokku --label=com.dokku.app-name=$APP" - local dockerfile_path=Dockerfile pushd "$SOURCECODE_WORK_DIR" &>/dev/null From 84ca9ff7e5a3e0edf15f3babd6265794f47b2374 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sat, 10 Jul 2021 02:11:54 -0400 Subject: [PATCH 29/32] fix: call correct function --- plugins/builder-pack/core-post-extract | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/builder-pack/core-post-extract b/plugins/builder-pack/core-post-extract index 83ea6540e..a3fe85b95 100755 --- a/plugins/builder-pack/core-post-extract +++ b/plugins/builder-pack/core-post-extract @@ -27,4 +27,4 @@ trigger-builder-pack-core-post-extract() { popd &>/dev/null } -trigger-builder-pack-post-extract "$@" +trigger-builder-pack-core-post-extract "$@" From 7292eaefc3b5374df165eee2e56c752aa395796e Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sat, 10 Jul 2021 15:32:59 -0400 Subject: [PATCH 30/32] tests: add test for builder-pack:set projectoml-path --- tests/apps/python/cnb/1/bin/build | 15 +++++ tests/apps/python/cnb/1/bin/detect | 3 + tests/apps/python/cnb/1/buildpack.toml | 9 +++ tests/apps/python/cnb/2/bin/build | 21 +++++++ tests/apps/python/cnb/2/bin/detect | 3 + tests/apps/python/cnb/2/buildpack.toml | 9 +++ tests/apps/python/project2.toml | 10 ++++ tests/unit/builder-pack.bats | 81 ++++++++++++++++++++++++++ 8 files changed, 151 insertions(+) create mode 100755 tests/apps/python/cnb/1/bin/build create mode 100755 tests/apps/python/cnb/1/bin/detect create mode 100644 tests/apps/python/cnb/1/buildpack.toml create mode 100755 tests/apps/python/cnb/2/bin/build create mode 100755 tests/apps/python/cnb/2/bin/detect create mode 100644 tests/apps/python/cnb/2/buildpack.toml create mode 100644 tests/apps/python/project2.toml create mode 100644 tests/unit/builder-pack.bats diff --git a/tests/apps/python/cnb/1/bin/build b/tests/apps/python/cnb/1/bin/build new file mode 100755 index 000000000..93a8d56ae --- /dev/null +++ b/tests/apps/python/cnb/1/bin/build @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +layers_dir=$1 + +echo "Building with buildpack 1" +bp_layer=$layers_dir/1 +bp_env_dir=$bp_layer/env +mkdir -p $bp_env_dir + +echo "TESTENV_1" > $bp_env_dir/TESTENV + +echo "[types]" > ${bp_layer}.toml +echo "launch = true" >> ${bp_layer}.toml +echo "build = true" >> ${bp_layer}.toml +echo "cache = true" >> ${bp_layer}.toml diff --git a/tests/apps/python/cnb/1/bin/detect b/tests/apps/python/cnb/1/bin/detect new file mode 100755 index 000000000..98668b00f --- /dev/null +++ b/tests/apps/python/cnb/1/bin/detect @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +echo "1" && exit 0 diff --git a/tests/apps/python/cnb/1/buildpack.toml b/tests/apps/python/cnb/1/buildpack.toml new file mode 100644 index 000000000..f89645558 --- /dev/null +++ b/tests/apps/python/cnb/1/buildpack.toml @@ -0,0 +1,9 @@ +api = "0.6" + +[buildpack] +id = "1" +version = "0.1.0" +name = "1 Packages Buildpack" + +[[stacks]] +id = "heroku-20" diff --git a/tests/apps/python/cnb/2/bin/build b/tests/apps/python/cnb/2/bin/build new file mode 100755 index 000000000..7de333ff7 --- /dev/null +++ b/tests/apps/python/cnb/2/bin/build @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +layers_dir=$1 + +echo "Building with buildpack 2" +bp_layer=$layers_dir/2 +bp_env_dir=$bp_layer/env +mkdir -p $bp_env_dir + +export TESTENV="$TESTENV:anotherenv" + +echo "===> env start" +env +echo "===> env end" + +echo "TESTENV_2" > $bp_env_dir/TESTENV + +echo "[types]" > ${bp_layer}.toml +echo "launch = true" >> ${bp_layer}.toml +echo "build = true" >> ${bp_layer}.toml +echo "cache = true" >> ${bp_layer}.toml diff --git a/tests/apps/python/cnb/2/bin/detect b/tests/apps/python/cnb/2/bin/detect new file mode 100755 index 000000000..48d7cb887 --- /dev/null +++ b/tests/apps/python/cnb/2/bin/detect @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +echo "2" && exit 0 diff --git a/tests/apps/python/cnb/2/buildpack.toml b/tests/apps/python/cnb/2/buildpack.toml new file mode 100644 index 000000000..c15695e03 --- /dev/null +++ b/tests/apps/python/cnb/2/buildpack.toml @@ -0,0 +1,9 @@ +api = "0.6" + +[buildpack] +id = "2" +version = "0.1.0" +name = "2 Packages Buildpack" + +[[stacks]] +id = "heroku-20" diff --git a/tests/apps/python/project2.toml b/tests/apps/python/project2.toml new file mode 100644 index 000000000..e1a066cac --- /dev/null +++ b/tests/apps/python/project2.toml @@ -0,0 +1,10 @@ +[project] +id = "python" +name = "python" +version = "1.0.0" + +[[build.buildpacks]] +uri = "./cnb/1" + +[[build.buildpacks]] +uri = "./cnb/1" diff --git a/tests/unit/builder-pack.bats b/tests/unit/builder-pack.bats new file mode 100644 index 000000000..3835fcd03 --- /dev/null +++ b/tests/unit/builder-pack.bats @@ -0,0 +1,81 @@ +#!/usr/bin/env bats + +load test_helper + +setup_file() { + 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() { + create_app +} + +teardown() { + destroy_app +} + +@test "(builder-pack:set)" { + run /bin/bash -c "dokku builder:set $TEST_APP selected pack" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku buildpacks:set-property $TEST_APP stack heroku/buildpacks:20" + echo "output: $output" + echo "status: $status" + assert_success + + run deploy_app python dokku@dokku.me:$TEST_APP inject_requirements_txt + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains 'Building with buildpack 1' 0 + assert_output_contains 'Installing requirements with pip' + + run /bin/bash -c "dokku builder-pack:set $TEST_APP projecttoml-path nonexistent.toml" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:rebuild $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains 'Building with buildpack 1' 0 + assert_output_contains 'Installing requirements with pip' + + run /bin/bash -c "dokku builder-pack:set $TEST_APP projecttoml-path project2.toml" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:rebuild $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains 'Building with buildpack 1' + assert_output_contains 'Installing requirements with pip' 0 + + run /bin/bash -c "dokku builder-pack:set $TEST_APP projecttoml-path" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:rebuild $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains 'Building with buildpack 1' 0 + assert_output_contains 'Installing requirements with pip' +} + +inject_requirements_txt() { + local APP="$1" + local APP_REPO_DIR="$2" + [[ -z "$APP" ]] && local APP="$TEST_APP" + echo "flask" >>"$APP_REPO_DIR/requirements.txt" +} From be6c4dc6dfec2117b7d1905944d93195709f1a3f Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sat, 10 Jul 2021 15:38:19 -0400 Subject: [PATCH 31/32] fix: correct shfmt and shellcheck warnings --- tests/apps/python/cnb/1/bin/build | 12 +++++++----- tests/apps/python/cnb/2/bin/build | 12 +++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/tests/apps/python/cnb/1/bin/build b/tests/apps/python/cnb/1/bin/build index 93a8d56ae..cd76d5ea9 100755 --- a/tests/apps/python/cnb/1/bin/build +++ b/tests/apps/python/cnb/1/bin/build @@ -7,9 +7,11 @@ bp_layer=$layers_dir/1 bp_env_dir=$bp_layer/env mkdir -p $bp_env_dir -echo "TESTENV_1" > $bp_env_dir/TESTENV +echo "TESTENV_1" >$bp_env_dir/TESTENV -echo "[types]" > ${bp_layer}.toml -echo "launch = true" >> ${bp_layer}.toml -echo "build = true" >> ${bp_layer}.toml -echo "cache = true" >> ${bp_layer}.toml +{ + echo "[types] + echo "launch = true" + echo "build = true" + echo "cache = true" +} >"${bp_layer}.toml" diff --git a/tests/apps/python/cnb/2/bin/build b/tests/apps/python/cnb/2/bin/build index 7de333ff7..96abf03de 100755 --- a/tests/apps/python/cnb/2/bin/build +++ b/tests/apps/python/cnb/2/bin/build @@ -13,9 +13,11 @@ echo "===> env start" env echo "===> env end" -echo "TESTENV_2" > $bp_env_dir/TESTENV +echo "TESTENV_2" >$bp_env_dir/TESTENV -echo "[types]" > ${bp_layer}.toml -echo "launch = true" >> ${bp_layer}.toml -echo "build = true" >> ${bp_layer}.toml -echo "cache = true" >> ${bp_layer}.toml +{ + echo "[types] + echo "launch = true" + echo "build = true" + echo "cache = true" +} >"${bp_layer}.toml" From 19f9648b4084153e5f872131c4b03913df6090cc Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sat, 10 Jul 2021 15:44:41 -0400 Subject: [PATCH 32/32] fix: correct shfmt and shellcheck warnings --- tests/apps/python/cnb/1/bin/build | 2 +- tests/apps/python/cnb/2/bin/build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/apps/python/cnb/1/bin/build b/tests/apps/python/cnb/1/bin/build index cd76d5ea9..faa85823c 100755 --- a/tests/apps/python/cnb/1/bin/build +++ b/tests/apps/python/cnb/1/bin/build @@ -10,7 +10,7 @@ mkdir -p $bp_env_dir echo "TESTENV_1" >$bp_env_dir/TESTENV { - echo "[types] + echo "[types]" echo "launch = true" echo "build = true" echo "cache = true" diff --git a/tests/apps/python/cnb/2/bin/build b/tests/apps/python/cnb/2/bin/build index 96abf03de..f307e3efb 100755 --- a/tests/apps/python/cnb/2/bin/build +++ b/tests/apps/python/cnb/2/bin/build @@ -16,7 +16,7 @@ echo "===> env end" echo "TESTENV_2" >$bp_env_dir/TESTENV { - echo "[types] + echo "[types]" echo "launch = true" echo "build = true" echo "cache = true"