diff --git a/docs/appendices/0.24.0-migration-guide.md b/docs/appendices/0.24.0-migration-guide.md index fb104995d..4815728f8 100644 --- a/docs/appendices/0.24.0-migration-guide.md +++ b/docs/appendices/0.24.0-migration-guide.md @@ -7,4 +7,4 @@ ## Deprecations -- The 1.0.0 release of Dokku will no longer select buildpack builders over dockerfile builders if both builders match. Instead, Dokku will choose the first builder that responds to the `builder-detect` trigger. +- The 1.0.0 release of Dokku will no longer select buildpack builders over dockerfile builders if both builders match. Instead, Dokku will choose the first builder that responds to the `builder-detect` trigger. Users that wish to use a specific builder may set a builder using the `builder:set` command, which will force Dokku to use the specified builder regardless of what might be auto-detected. diff --git a/docs/deployment/builders/builder-management.md b/docs/deployment/builders/builder-management.md new file mode 100644 index 000000000..72824b11d --- /dev/null +++ b/docs/deployment/builders/builder-management.md @@ -0,0 +1,108 @@ +# Builder Management + +> New as of 0.24.0 + +``` +builder:report [] [] # Displays a builder report for one or more apps +builder:set () # Set or clear a builder property for an app +``` + +Builders are a way of customizing how an app is built from a source, allowing users flexibility in how artifacts are created for later scheduling. + +## Usage + +### Builder selection + +Dokku supports the following built-in builders: + +- `builder-dockerfile`: Builds apps using a `Dockerfile` via `docker build`. See the [dockerfile builder documentation](/docs/deployment/builders/dockerfiles.md) for more information on how this builder functions. +- `builder-herokuish`: Builds apps with Heroku's v2a Buildpack specification via `gliderlabs/herokuish`. See the [herokuish builder documentation](/docs/deployment/builders/herokuish-buildpacks.md) for more information on how this builder functions. +- `builder-pack`: Builds apps with Cloud Native Buildpacks via the `pack-cli` tool. See the [cloud native buildpacks builder documentation](/docs/deployment/builders/cloud-native-buildpacks.md) for more information on how this builder functions. + +Builders run a detection script against a source code repository, and the first detected builder will be used to build the app artifact. The exception to this is when a `Dockerfile` is detected and the app is also able to use either `herokuish` or `pack-cli` for building, in which case one of the latter will be chosen. + +### Overriding the auto-selected builder + +If desired, the builder can be specified via the `builder:set` command by speifying a value for `selected`. The selected builder will always be used. + +```shell +dokku builder:set node-js-app selected dockerfile +``` + +The default value may be set by passing an empty value for the option: + +```shell +dokku builder:set node-js-app selected +``` + +The `selected` property can also be set globally. The global default is an empty string, and auto-detection will be performed when no value is set per-app or globally. + +```shell +dokku builder:set --global selected herokuish +``` + +The default value may be set by passing an empty value for the option. + +```shell +dokku builder:set --global selected +``` + +### Displaying builder reports for an app + +You can get a report about the app's builder status using the `builder:report` command: + +```shell +dokku builder:report +``` + +``` +=====> node-js-app builder information + Builder computed selected: herokuish + Builder global selected: herokuish + Builder selected: herokuish +=====> python-sample builder information + Builder computed selected: dockerfile + Builder global selected: herokuish + Builder selected: dockerfile +=====> ruby-sample builder information + Builder computed selected: herokuish + Builder global selected: herokuish + Builder selected: +``` + +You can run the command for a specific app also. + +```shell +dokku builder:report node-js-app +``` + +``` +=====> node-js-app builder information + Builder selected: herokuish +``` + +You can pass flags which will output only the value of the specific information you want. For example: + +```shell +dokku builder:report node-js-app --builder-selected +``` + +### Custom builders + +To create a custom builder, the following triggers must be implemented: + +- `builder-build`: + - arguments: `BUILDER_TYPE` `APP` `SOURCECODE_WORK_DIR` + - description: Creates a docker image named with the output of `common#get_app_image_name $APP`. +- `builder-detect`: + - arguments: `APP` `SOURCECODE_WORK_DIR` + - description: Outputs the name of the builder (without the `builder-` prefix) to use to build the app. +- `builder-release`: + - arguments: `BUILDER_TYPE` `APP` `IMAGE_AG` + - description: A post-build, pre-release trigger that can be used to post-process the image. Usually simply tags and labels the image appropriately. + +Custom plugins names _must_ have the prefix `builder-` or builder overriding via `builder:set` may not function as expected. + +Builders can use any tools available on the system to build the docker image, and may even be used to schedule building off-server. The only current requirement is that the image must exist on the server at the end of the `builder-build` command, though this requirement may be relaxed in a future release. + +For a simple example of how to implement this trigger, see `builder-pack`, which utilizes a cli tool - `pack-cli` - to generate an OCI image that is compatible with Docker and can be scheduled by the official scheduling plugins. diff --git a/docs/deployment/methods/cloud-native-buildpacks.md b/docs/deployment/builders/cloud-native-buildpacks.md similarity index 78% rename from docs/deployment/methods/cloud-native-buildpacks.md rename to docs/deployment/builders/cloud-native-buildpacks.md index ce1588b45..95df0b51a 100644 --- a/docs/deployment/methods/cloud-native-buildpacks.md +++ b/docs/deployment/builders/cloud-native-buildpacks.md @@ -5,23 +5,39 @@ ``` buildpacks:set-property [--global|] # Set or clear a buildpacks property for an app ``` + Cloud Native Buildpacks are an evolution over the Buildpacks technology provided by the Herokuish builder. See the [herokuish buildpacks documentation](/docs/deployment/methods/herokuish-buildpacks.md) for more information on how to clear buildpack build cache for an application. > Warning: This functionality uses the `pack` cli from the [Cloud Native Buildpacks](https://buildpacks.io) project to build apps. As the integration is experimental in Dokku, it is likely to change over time. ## Usage -To use this builder instead of either `Dockerfile` or `herokuish`, you must set the `DOKKU_CNB_EXPERIMENTAL` environment variable for your app to `1`. +### 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 config:set --no-restart node-js-app DOKKU_CNB_EXPERIMENTAL=1 +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/). Builds will proceed with the `pack` cli for the app from then on. -## Caveats +### Caveats As this functionality is highly experimental, there are a number of caveats. Please note that not all issuesare listed below. diff --git a/docs/deployment/methods/dockerfiles.md b/docs/deployment/builders/dockerfiles.md similarity index 86% rename from docs/deployment/methods/dockerfiles.md rename to docs/deployment/builders/dockerfiles.md index 0a7465345..581fb41e2 100644 --- a/docs/deployment/methods/dockerfiles.md +++ b/docs/deployment/builders/dockerfiles.md @@ -6,12 +6,20 @@ While Dokku normally defaults to using [Heroku buildpacks](https://devcenter.her > Dockerfile support is considered a *power user* feature. By using Dockerfile-based deployment, you agree that you will not have the same comfort as that enjoyed by buildpack users, and Dokku features may work differently. Differences between the two systems will be documented here. -To use a Dockerfile for deployment, commit a valid `Dockerfile` to the root of your repository and push the repository to your Dokku installation. If this file is detected, Dokku will default to using it to construct containers *except* in the following two cases: +## Usage -- The application has a `BUILDPACK_URL` environment variable set via the `dokku config:set` command or in a committed `.env` file. In this case, Dokku will use your specified buildpack. -- The application has a `.buildpacks` file in the root of the repository. In this case, Dokku will use your specified buildpack(s). +### Detection -## Switching from buildpack deployments +This builder will be auto-detected in the following case: + +- A `Dockerfile` exists in the root of the app repository. + +Dokku will only select the `dockerfile` builder if both the `herokuish` and `pack` builders are not detected and a Dockerfile exists. For more information on how those are detected, see the following links: + +- [Cloud Native Buildpacks documentation](/docs/deployment/builders/cloud-native-buildpacks.md#detection) +- [Herokuish documentation](/docs/deployment/builders/herokuish-buildpacks.md#detection) + +### Switching from buildpack deployments If an application was previously deployed via buildpacks, the following commands should be run before a Dockerfile deploy will succeed: @@ -19,7 +27,7 @@ If an application was previously deployed via buildpacks, the following commands dokku config:unset --no-restart node-js-app DOKKU_PROXY_PORT_MAP ``` -## Build-time configuration variables +### 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. @@ -65,11 +73,11 @@ ENV NODE_ENV ${NODE_ENV} RUN echo $NODE_ENV ``` -## Building images with Docker Buildkit +### Building images with Docker Buildkit If your Dockerfile is using Docker engine's [buildkit](https://docs.docker.com/develop/develop-images/build_enhancements/) (not to be confused with buildpacks), then the `DOCKER_BUILDKIT=1` environment variable needs to be set. One way to do this is to edit `/etc/environment` on your dokku host and reboot your instance. Note, for complete build log output, you should also set `BUILDKIT_PROGRESS=plain` in the same file. -## Customizing the run command +### Customizing the run command By default no arguments are passed to `docker run` when deploying the container and the `CMD` or `ENTRYPOINT` defined in the `Dockerfile` are executed. You can take advantage of docker ability of overriding the `CMD` or passing parameters to your `ENTRYPOINT` setting `$DOKKU_DOCKERFILE_START_CMD`. Let's say for example you are deploying a base Node.js image, with the following `ENTRYPOINT`: @@ -118,6 +126,6 @@ started by running `docker run bin/run-worker.sh` (the actual `docker run` comma complex, but this is the basic idea). If you use an `ENTRYPOINT` in your `Dockerfile`, the lines in your `Procfile` will be passed as arguments to the `ENTRYPOINT` script instead of being executed. -## Exposed ports +### Exposed ports See the [port management documentation](/docs/networking/port-management.md) for more information on how Dokku exposes ports for applications and how you can configure these for your app. diff --git a/docs/deployment/methods/herokuish-buildpacks.md b/docs/deployment/builders/herokuish-buildpacks.md similarity index 92% rename from docs/deployment/methods/herokuish-buildpacks.md rename to docs/deployment/builders/herokuish-buildpacks.md index 3803d536b..c6f40dfff 100644 --- a/docs/deployment/methods/herokuish-buildpacks.md +++ b/docs/deployment/builders/herokuish-buildpacks.md @@ -25,6 +25,23 @@ This page will cover usage of the `buildpacks` plugin. ## Usage +### Detection + +This builder will be auto-detected in either the following cases: + +- The `BUILDPACK_URL` app environment variable is set. + - This can be done via `dokku config:set` or via a committed `.env` file in the root of the repository. See the [environment variable documentation](/docs/configuration/environment-variables.md) for more details. +- A `.buildpacks` file exists in the root of the app repository. + - This can be via a committed `.buildpacks` file or managed via the `buildpacks` plugin commands. + +The builder can also be specified via the `builder:set` command: + +```shell +dokku builder:set node-js-app selected herokuish +``` + +> 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. + ### Listing Buildpacks in Use The `buildpacks:list` command can be used to show buildpacks that have been set for an app. This will omit any auto-detected buildpacks. diff --git a/docs/template.html b/docs/template.html index 24c9f4c25..f5522334e 100644 --- a/docs/template.html +++ b/docs/template.html @@ -127,11 +127,14 @@ User Management Zero Downtime Deploy Checks - Deployment Methods + Builders - Cloud Native Buildpacks - Herokuish Buildpacks - Dockerfile Deployment + Builder Management + Cloud Native Buildpacks + Herokuish Buildpacks + Dockerfile Deployment + + Deployment Methods Docker Image Deployment Git Deployment Tarfile Deployment diff --git a/docs/viewdocs.json b/docs/viewdocs.json index 6cacc72cc..7d13a1828 100644 --- a/docs/viewdocs.json +++ b/docs/viewdocs.json @@ -16,6 +16,15 @@ "deployment/buildpacks": "deployment/methods/herokuish-buildpacks/", "deployment/methods/buildpacks": "deployment/methods/herokuish-buildpacks/", "deployment/dockerfiles": "deployment/methods/dockerfiles/", + + "deployment/buildpacks": "deployment/builders/herokuish-buildpacks/", + "deployment/methods/buildpacks": "deployment/builders/herokuish-buildpacks/", + "deployment/dockerfiles": "deployment/builders/dockerfiles/", + + "deployment/methods/cloud-native-buildpacks": "deployment/builders/cloud-native-buildpacks/", + "deployment/methods/dockerfiles": "deployment/builders/dockerfiles/", + "deployment/methods/herokuish-buildpacks": "deployment/builders/herokuish-buildpacks/", + "deployment/images": "deployment/methods/images/", "configuration-management": "configuration/environment-variables/", "deployment/ssl-configuration": "configuration/ssl/", diff --git a/plugins/builder/.gitignore b/plugins/builder/.gitignore new file mode 100644 index 000000000..dee017e8f --- /dev/null +++ b/plugins/builder/.gitignore @@ -0,0 +1,9 @@ +/commands +/core-post-deploy +/subcommands/* +/triggers/* +/triggers +/network-* +/install +/post-* +/report diff --git a/plugins/builder/Makefile b/plugins/builder/Makefile new file mode 100644 index 000000000..8dce99ce8 --- /dev/null +++ b/plugins/builder/Makefile @@ -0,0 +1,6 @@ +SUBCOMMANDS = subcommands/report subcommands/set +TRIGGERS = triggers/builder-detect triggers/install triggers/post-delete triggers/report +BUILD = commands subcommands triggers +PLUGIN_NAME = builder + +include ../../common.mk diff --git a/plugins/builder/builder-detect b/plugins/builder/builder-detect new file mode 120000 index 000000000..fa05d2b3e --- /dev/null +++ b/plugins/builder/builder-detect @@ -0,0 +1 @@ +triggers \ No newline at end of file diff --git a/plugins/builder/builder.go b/plugins/builder/builder.go new file mode 100644 index 000000000..22ef608b4 --- /dev/null +++ b/plugins/builder/builder.go @@ -0,0 +1,13 @@ +package builder + +var ( + // DefaultProperties is a map of all valid network properties with corresponding default property values + DefaultProperties = map[string]string{ + "selected": "", + } + + // GlobalProperties is a map of all valid global network properties + GlobalProperties = map[string]bool{ + "selected": true, + } +) diff --git a/plugins/builder/go.mod b/plugins/builder/go.mod new file mode 100644 index 000000000..a382f3f9c --- /dev/null +++ b/plugins/builder/go.mod @@ -0,0 +1,12 @@ +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 +) + +replace github.com/dokku/dokku/plugins/common => ../common diff --git a/plugins/builder/go.sum b/plugins/builder/go.sum new file mode 100644 index 000000000..58c904707 --- /dev/null +++ b/plugins/builder/go.sum @@ -0,0 +1,10 @@ +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q= +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/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/builder/plugin.toml b/plugins/builder/plugin.toml new file mode 100644 index 000000000..138b6348a --- /dev/null +++ b/plugins/builder/plugin.toml @@ -0,0 +1,4 @@ +[plugin] +description = "dokku core builder plugin" +version = "0.23.9" +[plugin.config] diff --git a/plugins/builder/report.go b/plugins/builder/report.go new file mode 100644 index 000000000..57eaf4604 --- /dev/null +++ b/plugins/builder/report.go @@ -0,0 +1,44 @@ +package builder + +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{ + "--builder-computed-selected": reportComputedSelected, + "--builder-global-selected": reportGlobalSelected, + "--builder-selected": reportSelected, + } + + flagKeys := []string{} + for flagKey := range flags { + flagKeys = append(flagKeys, flagKey) + } + + trimPrefix := false + uppercaseFirstCharacter := true + infoFlags := common.CollectReport(appName, infoFlag, flags) + return common.ReportSingleApp("builder", appName, infoFlag, infoFlags, flagKeys, format, trimPrefix, uppercaseFirstCharacter) +} + +func reportComputedSelected(appName string) string { + value := reportSelected(appName) + if value == "" { + value = reportGlobalSelected(appName) + } + + return value +} +func reportGlobalSelected(appName string) string { + return common.PropertyGet("builder", "--global", "selected") +} + +func reportSelected(appName string) string { + return common.PropertyGet("builder", appName, "selected") +} diff --git a/plugins/builder/src/commands/commands.go b/plugins/builder/src/commands/commands.go new file mode 100644 index 000000000..55169ef42 --- /dev/null +++ b/plugins/builder/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 builder[:COMMAND] + +Manage builder settings for an app + +Additional commands:` + + helpContent = ` + builder:report [] [], Displays a builder report for one or more apps + builder:set (), Set or clear a builder property for an app +` +) + +func main() { + flag.Usage = usage + flag.Parse() + + cmd := flag.Arg(0) + switch cmd { + case "builder", "builder: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 builder, Manage builder 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/builder/src/subcommands/subcommands.go b/plugins/builder/src/subcommands/subcommands.go new file mode 100644 index 000000000..e6d692691 --- /dev/null +++ b/plugins/builder/src/subcommands/subcommands.go @@ -0,0 +1,50 @@ +package main + +import ( + "fmt" + "os" + "strings" + + "github.com/dokku/dokku/plugins/builder" + "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("builder:report", flag.ExitOnError) + format := args.String("format", "stdout", "format: [ stdout | json ]") + osArgs, infoFlag, flagErr := common.ParseReportArgs("builder", os.Args[2:]) + if flagErr == nil { + args.Parse(osArgs) + appName := args.Arg(0) + err = builder.CommandReport(appName, *format, infoFlag) + } + case "set": + args := flag.NewFlagSet("builder: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 = builder.CommandSet(appName, property, value) + default: + err = fmt.Errorf("Invalid plugin subcommand call: %s", subcommand) + } + + if err != nil { + common.LogFailWithError(err) + } +} diff --git a/plugins/builder/src/triggers/triggers.go b/plugins/builder/src/triggers/triggers.go new file mode 100644 index 000000000..ff3e4beb2 --- /dev/null +++ b/plugins/builder/src/triggers/triggers.go @@ -0,0 +1,39 @@ +package main + +import ( + "flag" + "fmt" + "os" + "strings" + + "github.com/dokku/dokku/plugins/builder" + "github.com/dokku/dokku/plugins/common" +) + +// main entrypoint to all triggers +func main() { + parts := strings.Split(os.Args[0], "/") + trigger := parts[len(parts)-1] + flag.Parse() + + var err error + switch trigger { + case "builder-detect": + appName := flag.Arg(0) + err = builder.TriggerBuilderDetect(appName) + case "install": + err = builder.TriggerInstall() + case "post-delete": + appName := flag.Arg(0) + err = builder.TriggerPostDelete(appName) + case "report": + appName := flag.Arg(0) + err = builder.ReportSingleApp(appName, "", "") + default: + err = fmt.Errorf("Invalid plugin trigger call: %s", trigger) + } + + if err != nil { + common.LogFailWithError(err) + } +} diff --git a/plugins/builder/subcommands.go b/plugins/builder/subcommands.go new file mode 100644 index 000000000..18e04ac0e --- /dev/null +++ b/plugins/builder/subcommands.go @@ -0,0 +1,29 @@ +package builder + +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 +} diff --git a/plugins/builder/triggers.go b/plugins/builder/triggers.go new file mode 100644 index 000000000..0cfed9837 --- /dev/null +++ b/plugins/builder/triggers.go @@ -0,0 +1,36 @@ +package builder + +import ( + "fmt" + + "github.com/dokku/dokku/plugins/common" +) + +// TriggerBuilderDetect outputs a manually selected builder for the app +func TriggerBuilderDetect(appName string) error { + if builder := common.PropertyGet("builder", appName, "selected"); builder != "" { + fmt.Println(builder) + return nil + } + + if builder := common.PropertyGet("builder", "--global", "selected"); builder != "" { + fmt.Println(builder) + return nil + } + + return nil +} + +// TriggerInstall runs the install step for the builder plugin +func TriggerInstall() error { + if err := common.PropertySetup("builder"); err != nil { + return fmt.Errorf("Unable to install the builder plugin: %s", err.Error()) + } + + return nil +} + +// TriggerPostDelete destroys the builder property for a given app container +func TriggerPostDelete(appName string) error { + return common.PropertyDestroy("builder", appName) +} diff --git a/tests/unit/builder.bats b/tests/unit/builder.bats index f978bb73d..3ee605314 100644 --- a/tests/unit/builder.bats +++ b/tests/unit/builder.bats @@ -10,6 +10,74 @@ teardown() { destroy_app } +@test "(builder) builder-detect [set]" { + local TMP=$(mktemp -d "/tmp/dokku.me.XXXXX") + trap 'popd &>/dev/null || true; rm -rf "$TMP"' INT TERM + + # test project.toml + run touch "$TMP/project.toml" + echo "output: $output" + echo "status: $status" + assert_success + + chown -R dokku:dokku "$TMP" + + run /bin/bash -c "dokku builder:set --global selected pack" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku plugin:trigger builder-detect $TEST_APP $TMP" + echo "output: $output" + echo "status: $status" + assert_success + assert_line 0 "pack" + + run /bin/bash -c "dokku builder:set $TEST_APP selected pack" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku plugin:trigger builder-detect $TEST_APP $TMP" + echo "output: $output" + echo "status: $status" + assert_success + assert_line 0 "pack" + + run /bin/bash -c "dokku builder:set --global selected other" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku plugin:trigger builder-detect $TEST_APP $TMP" + echo "output: $output" + echo "status: $status" + assert_success + assert_line 0 "pack" + + run /bin/bash -c "dokku builder:set $TEST_APP selected" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku plugin:trigger builder-detect $TEST_APP $TMP" + echo "output: $output" + echo "status: $status" + assert_success + assert_line 0 "other" + + run /bin/bash -c "dokku builder:set --global selected" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku plugin:trigger builder-detect $TEST_APP $TMP" + echo "output: $output" + echo "status: $status" + assert_success + assert_line 0 "pack" +} + @test "(builder) builder-detect [pack]" { local TMP=$(mktemp -d "/tmp/dokku.me.XXXXX") trap 'popd &>/dev/null || true; rm -rf "$TMP"' INT TERM @@ -21,11 +89,11 @@ teardown() { assert_success chown -R dokku:dokku "$TMP" - run /bin/bash -c "dokku plugin:trigger builder-detect $TEST_APP $TMP | head -n1" + run /bin/bash -c "dokku plugin:trigger builder-detect $TEST_APP $TMP" echo "output: $output" echo "status: $status" assert_success - assert_output "pack" + assert_line 0 "pack" sudo rm -rf $TMP/* echo "output: $output" @@ -39,11 +107,11 @@ teardown() { assert_success chown -R dokku:dokku "$TMP" - run /bin/bash -c "dokku plugin:trigger builder-detect $TEST_APP $TMP | head -n1" + run /bin/bash -c "dokku plugin:trigger builder-detect $TEST_APP $TMP" echo "output: $output" echo "status: $status" assert_success - assert_output "pack" + assert_line 0 "pack" } @test "(builder) builder-detect [dockerfile]" { @@ -56,11 +124,11 @@ teardown() { assert_success chown -R dokku:dokku "$TMP" - run /bin/bash -c "dokku plugin:trigger builder-detect $TEST_APP $TMP | head -n1" + run /bin/bash -c "dokku plugin:trigger builder-detect $TEST_APP $TMP" echo "output: $output" echo "status: $status" assert_success - assert_output "dockerfile" + assert_line 0 "dockerfile" } @test "(builder) builder-detect [herokuish]" { @@ -77,11 +145,11 @@ teardown() { assert_success chown -R dokku:dokku "$TMP" - run /bin/bash -c "dokku plugin:trigger builder-detect $TEST_APP $TMP | head -n1" + run /bin/bash -c "dokku plugin:trigger builder-detect $TEST_APP $TMP" echo "output: $output" echo "status: $status" assert_success - assert_output "herokuish" + assert_line 0 "herokuish" sudo rm -rf $TMP/* echo "output: $output" @@ -95,11 +163,11 @@ teardown() { assert_success chown -R dokku:dokku "$TMP" - run /bin/bash -c "dokku plugin:trigger builder-detect $TEST_APP $TMP | head -n1" + run /bin/bash -c "dokku plugin:trigger builder-detect $TEST_APP $TMP" echo "output: $output" echo "status: $status" assert_success - assert_output "herokuish" + assert_line 0 "herokuish" sudo rm -rf $TMP/* echo "output: $output" @@ -113,9 +181,9 @@ teardown() { assert_success chown -R dokku:dokku "$TMP" - run /bin/bash -c "dokku plugin:trigger builder-detect $TEST_APP $TMP | head -n1" + run /bin/bash -c "dokku plugin:trigger builder-detect $TEST_APP $TMP" echo "output: $output" echo "status: $status" assert_success - assert_output "herokuish" + assert_line 0 "herokuish" }