Merge pull request #4502 from dokku/4501-monorepo-support

Add monorepo support
This commit is contained in:
Jose Diaz-Gonzalez
2021-07-10 17:07:23 -04:00
committed by GitHub
76 changed files with 1560 additions and 65 deletions

View File

@@ -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

View File

@@ -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.

View File

@@ -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:
```

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
```

View File

@@ -0,0 +1 @@
hook

View File

@@ -1,5 +1,8 @@
/triggers/*
/triggers
/pre-*
/post-*
/commands
/install
/post-*
/pre-*
/report
/subcommands/*
/triggers
/triggers/*

View File

@@ -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

View File

@@ -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"`

View File

@@ -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
}

View File

@@ -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=

View File

@@ -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")
}

View File

@@ -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 [<app>] [<flag>], Displays a app-json report for one or more apps
app-json:set <app> <property> (<value>), 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)
}

View File

@@ -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)
}
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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

View File

@@ -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 <<help_desc
$plugin_name, $plugin_description
help_desc
fi
}
fn-help-content() {
declare desc="return help content"
cat <<help_content
builder-dockerfile:report [<app>] [<flag>], Displays a builder-dockerfile report for one or more apps
builder-dockerfile:set <app> <property> (<value>), Set or clear a builder-dockerfile property for an app
help_content
}

View File

@@ -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" ""
}

View File

@@ -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 "$@"

View File

@@ -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"

View File

@@ -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 "$@"

View File

@@ -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 "$@"

View File

@@ -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"

15
plugins/builder-pack/commands Executable file
View File

@@ -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

View File

@@ -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 "$@"

View File

@@ -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 <<help_desc
$plugin_name, $plugin_description
help_desc
fi
}
fn-help-content() {
declare desc="return help content"
cat <<help_content
builder-pack:report [<app>] [<flag>], Displays a builder-pack report for one or more apps
builder-pack:set <app> <property> (<value>), Set or clear a builder-pack property for an app
help_content
}

View File

@@ -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" ""
}

6
plugins/builder-pack/report Executable file
View File

@@ -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 "$@"

View File

@@ -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"

View File

@@ -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 "$@"

View File

@@ -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 "$@"

View File

@@ -1,5 +1,5 @@
/commands
/core-post-deploy
/core-post-extract
/subcommands/*
/triggers/*
/triggers

View File

@@ -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

View File

@@ -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,
}
)

View File

@@ -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
}

View File

@@ -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

View File

@@ -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=

View File

@@ -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")
}

View File

@@ -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)
}

View File

@@ -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 {

View File

@@ -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)"

15
plugins/ps/.gitignore vendored
View File

@@ -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/*

View File

@@ -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

View File

@@ -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

View File

@@ -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=

View File

@@ -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

View File

@@ -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) {

View File

@@ -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":

View File

@@ -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 {

View File

@@ -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)"

View File

@@ -6,3 +6,4 @@
cron: node worker.js
web: node web.js
worker: node worker.js
release: node release.js

View File

@@ -0,0 +1,3 @@
var secret = process.env.SECRET_KEY || "";
console.log('SECRET_KEY: ' + secret);

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,8 @@
{
"scripts": {
"dokku": {
"predeploy": "touch /app/predeploy2.test",
"postdeploy": "touch /app/postdeploy.test"
}
}
}

View File

@@ -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"

View File

@@ -0,0 +1,3 @@
#!/usr/bin/env bash
echo "1" && exit 0

View File

@@ -0,0 +1,9 @@
api = "0.6"
[buildpack]
id = "1"
version = "0.1.0"
name = "1 Packages Buildpack"
[[stacks]]
id = "heroku-20"

View File

@@ -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"

View File

@@ -0,0 +1,3 @@
#!/usr/bin/env bash
echo "2" && exit 0

View File

@@ -0,0 +1,9 @@
api = "0.6"
[buildpack]
id = "2"
version = "0.1.0"
name = "2 Packages Buildpack"
[[stacks]]
id = "heroku-20"

View File

@@ -0,0 +1,10 @@
[project]
id = "python"
name = "python"
version = "1.0.0"
[[build.buildpacks]]
uri = "./cnb/1"
[[build.buildpacks]]
uri = "./cnb/1"

View File

@@ -0,0 +1 @@
web: python3 web.py

View File

@@ -0,0 +1,2 @@
web: python3 web.py
release: python3 release.py

View File

View File

@@ -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()

View File

@@ -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()

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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"
}

View File

@@ -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:'
}

View File

@@ -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:'
}