From 04c9fe974eda021a6dcac6f2ccbdaf1b59ab3e53 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 21 Apr 2019 17:00:04 -0400 Subject: [PATCH] feat: add json output to config:export This change adds json output as both key/value as well as a list of objects. The former can be used in quick scripting environments, while the latter allows higher-level languages to have a bit more structure around how environment variables are declared. Specifically, systems such as kubernetes understand the latter method, while the former can be used within Nomad job files. --- plugins/config/environment.go | 44 +++++++++++++++++-- .../config/src/subcommands/export/export.go | 2 +- plugins/config/subcommands.go | 4 ++ tests/unit/20_config.bats | 28 +++++++++++- 4 files changed, 72 insertions(+), 6 deletions(-) diff --git a/plugins/config/environment.go b/plugins/config/environment.go index eaabf08d2..a4bb1063f 100644 --- a/plugins/config/environment.go +++ b/plugins/config/environment.go @@ -1,17 +1,16 @@ package config import ( + "archive/tar" + "encoding/json" "errors" "fmt" "io" + "os" "path/filepath" "sort" "strings" - "archive/tar" - - "os" - "github.com/dokku/dokku/plugins/common" "github.com/joho/godotenv" "github.com/ryanuber/columnize" @@ -31,6 +30,10 @@ const ( ExportFormatShell //ExportFormatPretty format: pretty-printed in columns ExportFormatPretty + //ExportFormatJSON format: json key/value output + ExportFormatJSON + //ExportFormatJSONList format: json output as a list of objects + ExportFormatJSONList ) //Env is a representation for global or app environment @@ -168,6 +171,10 @@ func (e *Env) Export(format ExportFormat) string { return e.ShellString() case ExportFormatPretty: return prettyPrintEnvEntries("", e.Map()) + case ExportFormatJSON: + return e.JSONString() + case ExportFormatJSONList: + return e.JSONListString() default: common.LogFail(fmt.Sprintf("Unknown export format: %v", format)) return "" @@ -190,6 +197,35 @@ func (e *Env) DockerArgsString() string { return e.stringWithPrefixAndSeparator("--env=", " ") } +//JSONString returns the contents of this Env as a key/value json object +func (e *Env) JSONString() string { + data, err := json.Marshal(e.Map()) + if err != nil { + return "{}" + } + + return string(data) +} + +//JSONListString returns the contents of this Env as a json list of objects containing the name and the value of the env var +func (e *Env) JSONListString() string { + var list []map[string]string + for _, key := range e.Keys() { + value, _ := e.Get(key) + list = append(list, map[string]string{ + "name": key, + "value": value, + }) + } + + data, err := json.Marshal(list) + if err != nil { + return "[]" + } + + return string(data) +} + //ShellString gets the contents of this Env in the form "KEY='value' KEY2='value'" // for passing the environment in the shell func (e *Env) ShellString() string { diff --git a/plugins/config/src/subcommands/export/export.go b/plugins/config/src/subcommands/export/export.go index 86fd8df8f..c83f8a6f6 100644 --- a/plugins/config/src/subcommands/export/export.go +++ b/plugins/config/src/subcommands/export/export.go @@ -14,7 +14,7 @@ func main() { args := flag.NewFlagSet("config:export", flag.ExitOnError) global := args.Bool("global", false, "--global: use the global environment") merged := args.Bool("merged", false, "--merged: merge app environment and global environment") - format := args.String("format", "exports", "--format: [ exports | envfile | docker-args | shell ] which format to export as)") + format := args.String("format", "exports", "--format: [ exports | envfile | docker-args | shell | pretty | json | json-list ] which format to export as)") args.Parse(os.Args[2:]) config.CommandExport(args.Args(), *global, *merged, *format) } diff --git a/plugins/config/subcommands.go b/plugins/config/subcommands.go index eaae77b8f..c2cc061bb 100644 --- a/plugins/config/subcommands.go +++ b/plugins/config/subcommands.go @@ -117,6 +117,10 @@ func CommandExport(args []string, global bool, merged bool, format string) { suffix = " " case "pretty": exportType = ExportFormatPretty + case "json": + exportType = ExportFormatJSON + case "json-list": + exportType = ExportFormatJSONList default: common.LogFail(fmt.Sprintf("Unknown export format: %v", format)) } diff --git a/tests/unit/20_config.bats b/tests/unit/20_config.bats index d62972353..754ed78a9 100644 --- a/tests/unit/20_config.bats +++ b/tests/unit/20_config.bats @@ -155,6 +155,32 @@ teardown() { run /bin/bash -c "dokku --app $TEST_APP config:show" echo "output: $output" echo "status: "$stat - assert_output "=====> $TEST_APP env vars"$'\nBKEY: true\naKey: true\nbKey: true\nzKey: true' } + +@test "(config) config:export" { + run /bin/bash -c "dokku --app $TEST_APP config:set zKey=true bKey=true BKEY=true aKey=true" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku config:export --format docker-args $TEST_APP" + echo "output: $output" + echo "status: "$stat + assert_output "--env=BKEY='true' --env=aKey='true' --env=bKey='true' --env=zKey='true'" + + run /bin/bash -c "dokku config:export --format shell $TEST_APP" + echo "output: $output" + echo "status: "$stat + assert_output "BKEY='true' aKey='true' bKey='true' zKey='true' " + + run /bin/bash -c "dokku config:export --format json $TEST_APP" + echo "output: $output" + echo "status: "$stat + assert_output '{"BKEY":"true","aKey":"true","bKey":"true","zKey":"true"}' + + run /bin/bash -c "dokku config:export --format json-list $TEST_APP" + echo "output: $output" + echo "status: "$stat + assert_output '[{"name":"BKEY","value":"true"},{"name":"aKey","value":"true"},{"name":"bKey","value":"true"},{"name":"zKey","value":"true"}]' +}