mirror of https://github.com/knative/func.git
feat: add json output to func run (#2893)
This commit is contained in:
parent
69bdcbbecd
commit
56e1b0f7f5
38
cmd/run.go
38
cmd/run.go
|
@ -2,6 +2,7 @@ package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
@ -28,7 +29,7 @@ NAME
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
{{rootCmdUse}} run [-t|--container] [-r|--registry] [-i|--image] [-e|--env]
|
{{rootCmdUse}} run [-t|--container] [-r|--registry] [-i|--image] [-e|--env]
|
||||||
[--build] [-b|--builder] [--builder-image] [-c|--confirm]
|
[--build] [-b|--builder] [--builder-image] [-c|--confirm]
|
||||||
[--address] [-v|--verbose]
|
[--address] [--json] [-v|--verbose]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
Run the function locally.
|
Run the function locally.
|
||||||
|
@ -71,9 +72,12 @@ EXAMPLES
|
||||||
|
|
||||||
o Run the function locally on a specific address.
|
o Run the function locally on a specific address.
|
||||||
$ {{rootCmdUse}} run --address=0.0.0.0:8081
|
$ {{rootCmdUse}} run --address=0.0.0.0:8081
|
||||||
|
|
||||||
|
o Run the function locally and output JSON with the service address.
|
||||||
|
$ {{rootCmdUse}} run --json
|
||||||
`,
|
`,
|
||||||
SuggestFor: []string{"rnu"},
|
SuggestFor: []string{"rnu"},
|
||||||
PreRunE: bindEnv("address", "build", "builder", "builder-image", "confirm", "container", "env", "image", "path", "registry", "start-timeout", "verbose"),
|
PreRunE: bindEnv("build", "builder", "builder-image", "confirm", "container", "env", "image", "path", "registry", "start-timeout", "verbose", "address", "json"),
|
||||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||||
return runRun(cmd, newClient)
|
return runRun(cmd, newClient)
|
||||||
},
|
},
|
||||||
|
@ -129,6 +133,7 @@ EXAMPLES
|
||||||
cmd.Flags().Lookup("build").NoOptDefVal = "true" // register `--build` as equivalient to `--build=true`
|
cmd.Flags().Lookup("build").NoOptDefVal = "true" // register `--build` as equivalient to `--build=true`
|
||||||
cmd.Flags().String("address", "",
|
cmd.Flags().String("address", "",
|
||||||
"Interface and port on which to bind and listen. Default is 127.0.0.1:8080, or an available port if 8080 is not available. ($FUNC_ADDRESS)")
|
"Interface and port on which to bind and listen. Default is 127.0.0.1:8080, or an available port if 8080 is not available. ($FUNC_ADDRESS)")
|
||||||
|
cmd.Flags().Bool("json", false, "Output as JSON. ($FUNC_JSON)")
|
||||||
|
|
||||||
// Oft-shared flags:
|
// Oft-shared flags:
|
||||||
addConfirmFlag(cmd, cfg.Confirm)
|
addConfirmFlag(cmd, cfg.Confirm)
|
||||||
|
@ -171,6 +176,11 @@ func runRun(cmd *cobra.Command, newClient ClientFactory) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ignore the verbose flag if JSON output
|
||||||
|
if cfg.JSON {
|
||||||
|
cfg.Verbose = false
|
||||||
|
}
|
||||||
|
|
||||||
// Client
|
// Client
|
||||||
clientOptions, err := cfg.clientOptions()
|
clientOptions, err := cfg.clientOptions()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -249,7 +259,27 @@ func runRun(cmd *cobra.Command, newClient ClientFactory) (err error) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// Output based on format
|
||||||
|
if cfg.JSON {
|
||||||
|
// Create JSON output structure
|
||||||
|
output := struct {
|
||||||
|
Address string `json:"address"`
|
||||||
|
Host string `json:"host"`
|
||||||
|
Port string `json:"port"`
|
||||||
|
}{
|
||||||
|
Address: fmt.Sprintf("http://%s:%s", job.Host, job.Port),
|
||||||
|
Host: job.Host,
|
||||||
|
Port: job.Port,
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonData, err := json.Marshal(output)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to marshal JSON output: %w", err)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(cmd.OutOrStdout(), string(jsonData))
|
||||||
|
} else {
|
||||||
fmt.Fprintf(cmd.OutOrStderr(), "Running on host port %v\n", job.Port)
|
fmt.Fprintf(cmd.OutOrStderr(), "Running on host port %v\n", job.Port)
|
||||||
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-cmd.Context().Done():
|
case <-cmd.Context().Done():
|
||||||
|
@ -293,6 +323,9 @@ type runConfig struct {
|
||||||
|
|
||||||
// Address is the interface and port to bind (e.g. "0.0.0.0:8081")
|
// Address is the interface and port to bind (e.g. "0.0.0.0:8081")
|
||||||
Address string
|
Address string
|
||||||
|
|
||||||
|
// JSON output format
|
||||||
|
JSON bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRunConfig(cmd *cobra.Command) (c runConfig) {
|
func newRunConfig(cmd *cobra.Command) (c runConfig) {
|
||||||
|
@ -303,6 +336,7 @@ func newRunConfig(cmd *cobra.Command) (c runConfig) {
|
||||||
Container: viper.GetBool("container"),
|
Container: viper.GetBool("container"),
|
||||||
StartTimeout: viper.GetDuration("start-timeout"),
|
StartTimeout: viper.GetDuration("start-timeout"),
|
||||||
Address: viper.GetString("address"),
|
Address: viper.GetString("address"),
|
||||||
|
JSON: viper.GetBool("json"),
|
||||||
}
|
}
|
||||||
// NOTE: .Env should be viper.GetStringSlice, but this returns unparsed
|
// NOTE: .Env should be viper.GetStringSlice, but this returns unparsed
|
||||||
// results and appears to be an open issue since 2017:
|
// results and appears to be an open issue since 2017:
|
||||||
|
|
|
@ -21,6 +21,7 @@ func TestRun_Run(t *testing.T) {
|
||||||
runError error // Set the runner to yield this error
|
runError error // Set the runner to yield this error
|
||||||
buildInvoked bool // should Builder.Build be invoked?
|
buildInvoked bool // should Builder.Build be invoked?
|
||||||
runInvoked bool // should Runner.Run be invoked?
|
runInvoked bool // should Runner.Run be invoked?
|
||||||
|
jsonOutput bool // expect JSON output format
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "run and build by default",
|
name: "run and build by default",
|
||||||
|
@ -100,6 +101,14 @@ func TestRun_Run(t *testing.T) {
|
||||||
buildInvoked: true,
|
buildInvoked: true,
|
||||||
runInvoked: false,
|
runInvoked: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "run with json output",
|
||||||
|
desc: "Should output JSON format when --json flag is used",
|
||||||
|
args: []string{"--json"},
|
||||||
|
buildInvoked: true,
|
||||||
|
runInvoked: true,
|
||||||
|
jsonOutput: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ NAME
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
func run [-t|--container] [-r|--registry] [-i|--image] [-e|--env]
|
func run [-t|--container] [-r|--registry] [-i|--image] [-e|--env]
|
||||||
[--build] [-b|--builder] [--builder-image] [-c|--confirm]
|
[--build] [-b|--builder] [--builder-image] [-c|--confirm]
|
||||||
[--address] [-v|--verbose]
|
[--address] [--json] [-v|--verbose]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
Run the function locally.
|
Run the function locally.
|
||||||
|
@ -55,6 +55,9 @@ EXAMPLES
|
||||||
o Run the function locally on a specific address.
|
o Run the function locally on a specific address.
|
||||||
$ func run --address=0.0.0.0:8081
|
$ func run --address=0.0.0.0:8081
|
||||||
|
|
||||||
|
o Run the function locally and output JSON with the service address.
|
||||||
|
$ func run --json
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
func run
|
func run
|
||||||
|
@ -72,6 +75,7 @@ func run
|
||||||
-e, --env stringArray Environment variable to set in the form NAME=VALUE. You may provide this flag multiple times for setting multiple environment variables. To unset, specify the environment variable name followed by a "-" (e.g., NAME-).
|
-e, --env stringArray Environment variable to set in the form NAME=VALUE. You may provide this flag multiple times for setting multiple environment variables. To unset, specify the environment variable name followed by a "-" (e.g., NAME-).
|
||||||
-h, --help help for run
|
-h, --help help for run
|
||||||
-i, --image string Full image name in the form [registry]/[namespace]/[name]:[tag]. This option takes precedence over --registry. Specifying tag is optional. ($FUNC_IMAGE)
|
-i, --image string Full image name in the form [registry]/[namespace]/[name]:[tag]. This option takes precedence over --registry. Specifying tag is optional. ($FUNC_IMAGE)
|
||||||
|
--json Output as JSON. ($FUNC_JSON)
|
||||||
-p, --path string Path to the function. Default is current directory ($FUNC_PATH)
|
-p, --path string Path to the function. Default is current directory ($FUNC_PATH)
|
||||||
-r, --registry string Container registry + registry namespace. (ex 'ghcr.io/myuser'). The full image name is automatically determined using this along with function name. ($FUNC_REGISTRY)
|
-r, --registry string Container registry + registry namespace. (ex 'ghcr.io/myuser'). The full image name is automatically determined using this along with function name. ($FUNC_REGISTRY)
|
||||||
-v, --verbose Print verbose logs ($FUNC_VERBOSE)
|
-v, --verbose Print verbose logs ($FUNC_VERBOSE)
|
||||||
|
|
Loading…
Reference in New Issue