From a6113f88e7fd277d606f7e717fe69549aebc8a1c Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 21 Mar 2021 21:47:08 -0400 Subject: [PATCH] featfeat: add ability to specify a custom app.json path --- docs/advanced-usage/deployment-tasks.md | 84 ++++++++++++++++++- plugins/app-json/Makefile | 3 +- plugins/app-json/appjson.go | 12 +++ plugins/app-json/functions.go | 2 +- plugins/app-json/report.go | 45 ++++++++++ plugins/app-json/src/commands/commands.go | 56 +++++++++++++ .../app-json/src/subcommands/subcommands.go | 50 +++++++++++ plugins/app-json/subcommands.go | 29 +++++++ 8 files changed, 277 insertions(+), 4 deletions(-) create mode 100644 plugins/app-json/report.go create mode 100644 plugins/app-json/src/commands/commands.go create mode 100644 plugins/app-json/src/subcommands/subcommands.go create mode 100644 plugins/app-json/subcommands.go diff --git a/docs/advanced-usage/deployment-tasks.md b/docs/advanced-usage/deployment-tasks.md index fd071028d..e293751f5 100644 --- a/docs/advanced-usage/deployment-tasks.md +++ b/docs/advanced-usage/deployment-tasks.md @@ -2,6 +2,10 @@ > New as of 0.5.0 +## Usage + +### Overview + Sometimes you need to run a command on deployment time, but before an app is completely deployed. Common use cases include: - Checking a database is initialized @@ -49,7 +53,83 @@ Please keep the above in mind when utilizing deployment tasks. > To execute commands on the host during a release phase, see the [plugin creation documentation](/docs/development/plugin-creation.md) docs for more information on building your own custom plugin. -## `app.json` deployment tasks +### Changing the `app.json` location + +When deploying a monorepo, it may be desirable to specify the specific path of the `app.json` file to use for a given app. This can be done via the `app-json:set` command. + +```shell +dokku app-json:set node-js-app appjson-path second-app.json +``` + +The default value may be set by passing an empty value for the option: + +```shell +dokku app-json:set node-js-app appjson-path +``` + +The `appjson-path` property can also be set globally. The global default is `app.json`, and the global value is used when no app-specific value is set. + +```shell +dokku app-json:set --global appjson-path global-app.json +``` + +The default value may be set by passing an empty value for the option. + +```shell +dokku app-json:set --global appjson-path +``` + +### Displaying app-json reports for an app + +> New as of 0.25.0 + +You can get a report about the app's storage status using the `app-json:report` command: + +```shell +dokku app-json:report +``` + +``` +=====> node-js-app app-json information + App-json computed appjson path: app2.json + App-json global appjson path: app.json + App-json appjson path: app2.json +=====> python-sample app-json information + App-json computed appjson path: app.json + App-json global appjson path: app.json + App-json appjson path: +=====> ruby-sample app-json information + App-json computed appjson path: app.json + App-json global appjson path: app.json + App-json appjson path: +``` + +You can run the command for a specific app also. + +```shell +dokku app-json:report node-js-app +``` + +``` +=====> node-js-app app-json information + App-json computed appjson path: app2.json + App-json global appjson path: app.json + App-json appjson path: app2.json +``` + +You can pass flags which will output only the value of the specific information you want. For example: + +```shell +dokku app-json:report node-js-app --app-json-appjson-path +``` + +``` +app2.json +``` + +### Deployment tasks + +#### `app.json` deployment tasks Dokku provides limited support for the `app.json` manifest from Heroku (documentation available [here](https://devcenter.heroku.com/articles/app-json-schema)). The keys available for use with Deployment Tasks are: @@ -75,7 +155,7 @@ The following is an example `app.json` file. Please note that only the `scripts. } ``` -## Procfile Release command +#### Procfile Release command > New as of 0.14.0 diff --git a/plugins/app-json/Makefile b/plugins/app-json/Makefile index b3f6ecead..9b92fd230 100644 --- a/plugins/app-json/Makefile +++ b/plugins/app-json/Makefile @@ -1,5 +1,6 @@ +SUBCOMMANDS = subcommands/report subcommands/set TRIGGERS = triggers/install triggers/post-delete triggers/post-deploy triggers/pre-deploy -BUILD = triggers +BUILD = commands subcommands triggers PLUGIN_NAME = app-json include ../../common.mk diff --git a/plugins/app-json/appjson.go b/plugins/app-json/appjson.go index ad4871fbc..8d064210d 100644 --- a/plugins/app-json/appjson.go +++ b/plugins/app-json/appjson.go @@ -6,6 +6,18 @@ import ( "github.com/dokku/dokku/plugins/common" ) +var ( + // DefaultProperties is a map of all valid network properties with corresponding default property values + DefaultProperties = map[string]string{ + "appjson-path": "", + } + + // GlobalProperties is a map of all valid global network properties + GlobalProperties = map[string]bool{ + "appjson-path": true, + } +) + // AppJSON is a struct that represents an app.json file as understood by Dokku type AppJSON struct { Cron []CronCommand `json:"cron"` diff --git a/plugins/app-json/functions.go b/plugins/app-json/functions.go index 44175cc5a..4422542cb 100644 --- a/plugins/app-json/functions.go +++ b/plugins/app-json/functions.go @@ -448,6 +448,6 @@ func refreshAppJSON(appName string, image string) error { } } - common.CopyFromImage(appName, image, "app.json", appjsonPath) + common.CopyFromImage(appName, image, reportComputedAppjsonpath(appName), appjsonPath) return nil } diff --git a/plugins/app-json/report.go b/plugins/app-json/report.go new file mode 100644 index 000000000..511f12302 --- /dev/null +++ b/plugins/app-json/report.go @@ -0,0 +1,45 @@ +package appjson + +import ( + "github.com/dokku/dokku/plugins/common" +) + +// ReportSingleApp is an internal function that displays the builder report for one or more apps +func ReportSingleApp(appName string, format string, infoFlag string) error { + if err := common.VerifyAppName(appName); err != nil { + return err + } + + flags := map[string]common.ReportFunc{ + "--app-json-computed-selected": reportComputedAppjsonpath, + "--app-json-global-selected": reportGlobalAppjsonpath, + "--app-json-selected": reportAppjsonpath, + } + + flagKeys := []string{} + for flagKey := range flags { + flagKeys = append(flagKeys, flagKey) + } + + trimPrefix := false + uppercaseFirstCharacter := true + infoFlags := common.CollectReport(appName, infoFlag, flags) + return common.ReportSingleApp("app-json", appName, infoFlag, infoFlags, flagKeys, format, trimPrefix, uppercaseFirstCharacter) +} + +func reportComputedAppjsonpath(appName string) string { + value := reportAppjsonpath(appName) + if value == "" { + value = reportGlobalAppjsonpath(appName) + } + + return value +} + +func reportGlobalAppjsonpath(appName string) string { + return common.PropertyGetDefault("app-json", "--global", "appjson-path", "app.json") +} + +func reportAppjsonpath(appName string) string { + return common.PropertyGet("app-json", appName, "appjson-path") +} diff --git a/plugins/app-json/src/commands/commands.go b/plugins/app-json/src/commands/commands.go new file mode 100644 index 000000000..548c51e40 --- /dev/null +++ b/plugins/app-json/src/commands/commands.go @@ -0,0 +1,56 @@ +package main + +import ( + "flag" + "fmt" + "os" + "strconv" + "strings" + + "github.com/dokku/dokku/plugins/common" +) + +const ( + helpHeader = `Usage: dokku app-json[:COMMAND] + +Manage app-json settings for an app + +Additional commands:` + + helpContent = ` + app-json:report [] [], Displays a app-json report for one or more apps + app-json:set (), Set or clear a app-json property for an app +` +) + +func main() { + flag.Usage = usage + flag.Parse() + + cmd := flag.Arg(0) + switch cmd { + case "app-json", "app-json:help": + usage() + case "help": + command := common.NewShellCmd(fmt.Sprintf("ps -o command= %d", os.Getppid())) + command.ShowOutput = false + output, err := command.Output() + + if err == nil && strings.Contains(string(output), "--all") { + fmt.Println(helpContent) + } else { + fmt.Print("\n app-json, Manage app-json settings for an app\n") + } + default: + dokkuNotImplementExitCode, err := strconv.Atoi(os.Getenv("DOKKU_NOT_IMPLEMENTED_EXIT")) + if err != nil { + fmt.Println("failed to retrieve DOKKU_NOT_IMPLEMENTED_EXIT environment variable") + dokkuNotImplementExitCode = 10 + } + os.Exit(dokkuNotImplementExitCode) + } +} + +func usage() { + common.CommandUsage(helpHeader, helpContent) +} diff --git a/plugins/app-json/src/subcommands/subcommands.go b/plugins/app-json/src/subcommands/subcommands.go new file mode 100644 index 000000000..e4879e02e --- /dev/null +++ b/plugins/app-json/src/subcommands/subcommands.go @@ -0,0 +1,50 @@ +package main + +import ( + "fmt" + "os" + "strings" + + appjson "github.com/dokku/dokku/plugins/app-json" + "github.com/dokku/dokku/plugins/common" + + flag "github.com/spf13/pflag" +) + +// main entrypoint to all subcommands +func main() { + parts := strings.Split(os.Args[0], "/") + subcommand := parts[len(parts)-1] + + var err error + switch subcommand { + case "report": + args := flag.NewFlagSet("app-json:report", flag.ExitOnError) + format := args.String("format", "stdout", "format: [ stdout | json ]") + osArgs, infoFlag, flagErr := common.ParseReportArgs("appjson", os.Args[2:]) + if flagErr == nil { + args.Parse(osArgs) + appName := args.Arg(0) + err = appjson.CommandReport(appName, *format, infoFlag) + } + case "set": + args := flag.NewFlagSet("app-json:set", flag.ExitOnError) + global := args.Bool("global", false, "--global: set a global property") + args.Parse(os.Args[2:]) + appName := args.Arg(0) + property := args.Arg(1) + value := args.Arg(2) + if *global { + appName = "--global" + property = args.Arg(0) + value = args.Arg(1) + } + err = appjson.CommandSet(appName, property, value) + default: + err = fmt.Errorf("Invalid plugin subcommand call: %s", subcommand) + } + + if err != nil { + common.LogFailWithError(err) + } +} diff --git a/plugins/app-json/subcommands.go b/plugins/app-json/subcommands.go new file mode 100644 index 000000000..f402dd354 --- /dev/null +++ b/plugins/app-json/subcommands.go @@ -0,0 +1,29 @@ +package appjson + +import ( + "github.com/dokku/dokku/plugins/common" +) + +// CommandReport displays a network report for one or more apps +func CommandReport(appName string, format string, infoFlag string) error { + if len(appName) == 0 { + apps, err := common.DokkuApps() + if err != nil { + return err + } + for _, appName := range apps { + if err := ReportSingleApp(appName, format, infoFlag); err != nil { + return err + } + } + return nil + } + + return ReportSingleApp(appName, format, infoFlag) +} + +// CommandSet set or clear a builder property for an app +func CommandSet(appName string, property string, value string) error { + common.CommandPropertySet("builder", appName, property, value, DefaultProperties, GlobalProperties) + return nil +}