From 6d40d52d7d78aa8e9a03bbd64e299b13d95dde73 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 21 Mar 2021 21:42:39 -0400 Subject: [PATCH] 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)"