diff --git a/docs/advanced-usage/deployment-tasks.md b/docs/advanced-usage/deployment-tasks.md index fd071028d..6b18c7f7f 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. 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 +``` + +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/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/builder-management.md b/docs/deployment/builders/builder-management.md index 72824b11d..fe28fa2a7 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. 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 +``` + +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/deployment/builders/cloud-native-buildpacks.md b/docs/deployment/builders/cloud-native-buildpacks.md index a62133d91..572a6d2c4 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. 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 +``` + +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/docs/deployment/builders/dockerfiles.md b/docs/deployment/builders/dockerfiles.md index ef52f71fc..f8aac829a 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. 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 +``` + +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/docs/development/plugin-triggers.md b/docs/development/plugin-triggers.md index 2fbadae2a..a9d211c34 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/docs/processes/process-management.md b/docs/processes/process-management.md index 80c39e6b7..8b29bfb7d 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. 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 +``` + +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/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/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/* diff --git a/plugins/app-json/Makefile b/plugins/app-json/Makefile index b3f6ecead..b0372525f 100644 --- a/plugins/app-json/Makefile +++ b/plugins/app-json/Makefile @@ -1,5 +1,6 @@ -TRIGGERS = triggers/install triggers/post-delete triggers/post-deploy triggers/pre-deploy -BUILD = triggers +SUBCOMMANDS = subcommands/report subcommands/set +TRIGGERS = triggers/install triggers/post-delete triggers/post-deploy triggers/pre-deploy triggers/report +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/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= 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/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) } diff --git a/plugins/app-json/subcommands.go b/plugins/app-json/subcommands.go new file mode 100644 index 000000000..b2f396281 --- /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("app-json", appName, property, value, DefaultProperties, GlobalProperties) + return nil +} diff --git a/plugins/builder-dockerfile/builder-build b/plugins/builder-dockerfile/builder-build index 7ff239b92..7830eae68 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,17 @@ trigger-builder-dockerfile-builder-build() { pushd "$SOURCECODE_WORK_DIR" &>/dev/null + local NEW_DOCKERFILE="$(fn-builder-dockerfile-computed-dockerfile-path "$APP")" + 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 + fi + # extract first port from Dockerfile dos2unix Dockerfile local DOCKERFILE_PORTS=$(get_dockerfile_exposed_ports Dockerfile) 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-functions b/plugins/builder-dockerfile/internal-functions new file mode 100755 index 000000000..88503617b --- /dev/null +++ b/plugins/builder-dockerfile/internal-functions @@ -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 "$@" diff --git a/plugins/builder-pack/builder-build b/plugins/builder-pack/builder-build index 93dcd6b70..7a9644d14 100755 --- a/plugins/builder-pack/builder-build +++ b/plugins/builder-pack/builder-build @@ -1,8 +1,8 @@ #!/usr/bin/env bash -set -eo pipefail -[[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x trigger-builder-pack-builder-build() { declare desc="builder-pack builder-build plugin trigger" 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/core-post-extract b/plugins/builder-pack/core-post-extract new file mode 100755 index 000000000..a3fe85b95 --- /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-core-post-extract "$@" 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-functions b/plugins/builder-pack/internal-functions new file mode 100755 index 000000000..72c4b73f4 --- /dev/null +++ b/plugins/builder-pack/internal-functions @@ -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-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 + 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-projecttoml-path() { + declare APP="$1" + + file="$(fn-builder-pack-projecttoml-path "$APP")" + if [[ "$file" == "" ]]; then + file="$(fn-builder-pack-global-projecttoml-path "$APP")" + fi + + echo "$file" +} + +fn-builder-pack-global-projecttoml-path() { + declare APP="$1" + + fn-plugin-property-get "builder-pack" "--global" "projecttoml-path" "project.toml" +} + +fn-builder-pack-projecttoml-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 "$@" 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 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/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/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/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) } diff --git a/plugins/builder/triggers.go b/plugins/builder/triggers.go index 0cfed9837..b711f8a7c 100644 --- a/plugins/builder/triggers.go +++ b/plugins/builder/triggers.go @@ -2,8 +2,13 @@ package builder import ( "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" "github.com/dokku/dokku/plugins/common" + "github.com/otiai10/copy" ) // TriggerBuilderDetect outputs a manually selected builder for the app @@ -21,6 +26,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 := removeAllContents(tmpWorkDir); err != nil { + return fmt.Errorf("Unable to clear out temporary working directory for rewrite: %v", err.Error()) + } + + 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 := removeAllContents(sourceWorkDir); err != nil { + return fmt.Errorf("Unable to clear out sourcecode working directory for rewrite: %v", err.Error()) + } + + if err := copy.Copy(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/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/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/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/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 452b417a7..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 { 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)" 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/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/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/apps/python/cnb/1/bin/build b/tests/apps/python/cnb/1/bin/build new file mode 100755 index 000000000..faa85823c --- /dev/null +++ b/tests/apps/python/cnb/1/bin/build @@ -0,0 +1,17 @@ +#!/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]" + echo "launch = true" + echo "build = true" + 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..f307e3efb --- /dev/null +++ b/tests/apps/python/cnb/2/bin/build @@ -0,0 +1,23 @@ +#!/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]" + echo "launch = true" + echo "build = true" + 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/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/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/app-json.bats b/tests/unit/app-json.bats index 31d99d365..09aa65597 100644 --- a/tests/unit/app-json.bats +++ b/tests/unit/app-json.bats @@ -151,3 +151,44 @@ teardown() { echo "status: $status" assert_success } + +@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 /bin/bash -c "dokku ps:rebuild $TEST_APP" + 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" + 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 +} 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 +} 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" +} 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:' +} 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:' +}