feat!: change `describe` command to `info` (#474)

The describe command conflicts sematically with kubectl describe.
This commit changes the command name to `info`.

Fixes: https://github.com/knative-sandbox/kn-plugin-func/issues/337

Signed-off-by: Lance Ball <lball@redhat.com>
This commit is contained in:
Lance Ball 2021-08-16 00:43:54 -04:00 committed by GitHub
parent c8875938d7
commit 10a07578e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 66 additions and 67 deletions

View File

@ -126,10 +126,10 @@ type ProgressListener interface {
// Describer of Functions' remote deployed aspect.
type Describer interface {
// Describe the running state of the service as reported by the underlyng platform.
Describe(ctx context.Context, name string) (description Description, err error)
Describe(ctx context.Context, name string) (description Info, err error)
}
type Description struct {
type Info struct {
Name string `json:"name" yaml:"name"`
Image string `json:"image" yaml:"image"`
Namespace string `json:"namespace" yaml:"namespace"`
@ -549,9 +549,9 @@ func (c *Client) List(ctx context.Context) ([]ListItem, error) {
return c.lister.List(ctx)
}
// Describe a Function. Name takes precidence. If no name is provided,
// Info for a Function. Name takes precidence. If no name is provided,
// the Function defined at root is used.
func (c *Client) Describe(ctx context.Context, name, root string) (d Description, err error) {
func (c *Client) Info(ctx context.Context, name, root string) (d Info, err error) {
go func() {
<-ctx.Done()
c.progressListener.Stopping()

View File

@ -122,9 +122,9 @@ func runEmit(cmd *cobra.Command, _ []string, clientFn emitClientFn) (err error)
// Otherwise the value of Sink is used verbatim if defined.
func endpoint(ctx context.Context, cfg emitConfig) (url string, err error) {
var (
f fn.Function
d fn.Describer
desc fn.Description
f fn.Function
d fn.Describer
i fn.Info
)
// If the special value "local" was requested,
@ -151,18 +151,18 @@ func endpoint(ctx context.Context, cfg emitConfig) (url string, err error) {
}
// Get the current state of the function.
if desc, err = d.Describe(ctx, f.Name); err != nil {
if i, err = d.Describe(ctx, f.Name); err != nil {
return
}
// Probably wise to be defensive here:
if len(desc.Routes) == 0 {
if len(i.Routes) == 0 {
err = errors.New("function has no active routes")
return
}
// The first route should be the destination.
return desc.Routes[0], nil
return i.Routes[0], nil
}
type emitConfig struct {

View File

@ -16,10 +16,10 @@ import (
)
func init() {
root.AddCommand(NewDescribeCmd(newDescribeClient))
root.AddCommand(NewInfoCmd(newInfoClient))
}
func newDescribeClient(cfg describeConfig) (*fn.Client, error) {
func newInfoClient(cfg infoConfig) (*fn.Client, error) {
describer, err := knative.NewDescriber(cfg.Namespace)
if err != nil {
return nil, err
@ -33,11 +33,11 @@ func newDescribeClient(cfg describeConfig) (*fn.Client, error) {
), nil
}
type describeClientFn func(describeConfig) (*fn.Client, error)
type infoClientFn func(infoConfig) (*fn.Client, error)
func NewDescribeCmd(clientFn describeClientFn) *cobra.Command {
func NewInfoCmd(clientFn infoClientFn) *cobra.Command {
cmd := &cobra.Command{
Use: "describe <name>",
Use: "info <name>",
Short: "Show details of a function",
Long: `Show details of a function
@ -46,12 +46,12 @@ the current directory or from the directory specified with --path.
`,
Example: `
# Show the details of a function as declared in the local func.yaml
kn func describe
kn func info
# Show the details of the function in the myotherfunc directory with yaml output
kn func describe --output yaml --path myotherfunc
kn func info --output yaml --path myotherfunc
`,
SuggestFor: []string{"desc", "get"},
SuggestFor: []string{"ifno", "describe", "fino", "get"},
ValidArgsFunction: CompleteFunctionList,
PreRunE: bindEnv("namespace", "output", "path"),
}
@ -65,14 +65,14 @@ kn func describe --output yaml --path myotherfunc
}
cmd.RunE = func(cmd *cobra.Command, args []string) error {
return runDescribe(cmd, args, clientFn)
return runInfo(cmd, args, clientFn)
}
return cmd
}
func runDescribe(cmd *cobra.Command, args []string, clientFn describeClientFn) (err error) {
config := newDescribeConfig(args)
func runInfo(cmd *cobra.Command, args []string, clientFn infoClientFn) (err error) {
config := newInfoConfig(args)
function, err := fn.NewFunction(config.Path)
if err != nil {
@ -91,20 +91,20 @@ func runDescribe(cmd *cobra.Command, args []string, clientFn describeClientFn) (
}
// Get the description
d, err := client.Describe(cmd.Context(), config.Name, config.Path)
d, err := client.Info(cmd.Context(), config.Name, config.Path)
if err != nil {
return
}
d.Image = function.Image
write(os.Stdout, description(d), config.Output)
write(os.Stdout, info(d), config.Output)
return
}
// CLI Configuration (parameters)
// ------------------------------
type describeConfig struct {
type infoConfig struct {
Name string
Namespace string
Output string
@ -112,12 +112,12 @@ type describeConfig struct {
Verbose bool
}
func newDescribeConfig(args []string) describeConfig {
func newInfoConfig(args []string) infoConfig {
var name string
if len(args) > 0 {
name = args[0]
}
return describeConfig{
return infoConfig{
Name: deriveName(name, viper.GetString("path")),
Namespace: viper.GetString("namespace"),
Output: viper.GetString("output"),
@ -129,62 +129,62 @@ func newDescribeConfig(args []string) describeConfig {
// Output Formatting (serializers)
// -------------------------------
type description fn.Description
type info fn.Info
func (d description) Human(w io.Writer) error {
func (i info) Human(w io.Writer) error {
fmt.Fprintln(w, "Function name:")
fmt.Fprintf(w, " %v\n", d.Name)
fmt.Fprintf(w, " %v\n", i.Name)
fmt.Fprintln(w, "Function is built in image:")
fmt.Fprintf(w, " %v\n", d.Image)
fmt.Fprintf(w, " %v\n", i.Image)
fmt.Fprintln(w, "Function is deployed in namespace:")
fmt.Fprintf(w, " %v\n", d.Namespace)
fmt.Fprintf(w, " %v\n", i.Namespace)
fmt.Fprintln(w, "Routes:")
for _, route := range d.Routes {
for _, route := range i.Routes {
fmt.Fprintf(w, " %v\n", route)
}
if len(d.Subscriptions) > 0 {
if len(i.Subscriptions) > 0 {
fmt.Fprintln(w, "Subscriptions (Source, Type, Broker):")
for _, s := range d.Subscriptions {
for _, s := range i.Subscriptions {
fmt.Fprintf(w, " %v %v %v\n", s.Source, s.Type, s.Broker)
}
}
return nil
}
func (d description) Plain(w io.Writer) error {
fmt.Fprintf(w, "Name %v\n", d.Name)
fmt.Fprintf(w, "Image %v\n", d.Image)
fmt.Fprintf(w, "Namespace %v\n", d.Namespace)
func (i info) Plain(w io.Writer) error {
fmt.Fprintf(w, "Name %v\n", i.Name)
fmt.Fprintf(w, "Image %v\n", i.Image)
fmt.Fprintf(w, "Namespace %v\n", i.Namespace)
for _, route := range d.Routes {
for _, route := range i.Routes {
fmt.Fprintf(w, "Route %v\n", route)
}
if len(d.Subscriptions) > 0 {
for _, s := range d.Subscriptions {
if len(i.Subscriptions) > 0 {
for _, s := range i.Subscriptions {
fmt.Fprintf(w, "Subscription %v %v %v\n", s.Source, s.Type, s.Broker)
}
}
return nil
}
func (d description) JSON(w io.Writer) error {
return json.NewEncoder(w).Encode(d)
func (i info) JSON(w io.Writer) error {
return json.NewEncoder(w).Encode(i)
}
func (d description) XML(w io.Writer) error {
return xml.NewEncoder(w).Encode(d)
func (i info) XML(w io.Writer) error {
return xml.NewEncoder(w).Encode(i)
}
func (d description) YAML(w io.Writer) error {
return yaml.NewEncoder(w).Encode(d)
func (i info) YAML(w io.Writer) error {
return yaml.NewEncoder(w).Encode(i)
}
func (d description) URL(w io.Writer) error {
if len(d.Routes) > 0 {
fmt.Fprintf(w, "%s\n", d.Routes[0])
func (i info) URL(w io.Writer) error {
if len(i.Routes) > 0 {
fmt.Fprintf(w, "%s\n", i.Routes[0])
}
return nil
}

View File

@ -79,20 +79,20 @@ When run as a `kn` plugin.
kn func deploy [-n <namespace> -p <path> -i <image> -r <registry> -b=true|false]
```
## `describe`
## `info`
Prints the name, route and any event subscriptions for a deployed Function. The user may also specify the name of the function to describe. The namespace defaults to the value in `func.yaml` or the namespace currently active in the user's Kubernetes configuration. The namespace may be specified on the command line, and if so this will overwrite the value in `func.yaml`.
Similar `kn` command: `kn service describe NAME [flags]`. This flag provides a lot of nice information not available in `func describe`, such as revisions, age, annotations and labels. This command should be renamed to make it distinct from `kn` - e.g. `func status`.
Similar `kn` command: `kn service describe NAME [flags]`. This flag provides a lot of nice information not available in `func info`, such as revisions, age, annotations and labels.
```console
func describe [-o <output> -n <namespace> -p <path>]
func info [-o <output> -n <namespace> -p <path>]
```
When run as a `kn` plugin.
```console
kn func describe [-o <output> -n <namespace> -p <path>]
kn func info [-o <output> -n <namespace> -p <path>]
```
## `list`

View File

@ -31,7 +31,7 @@ func NewDescriber(namespaceOverride string) (describer *Describer, err error) {
// restricts to label-syntax, which is thus escaped. Therefore as a knative (kube) implementation
// detal proper full names have to be escaped on the way in and unescaped on the way out. ex:
// www.example-site.com -> www-example--site-com
func (d *Describer) Describe(ctx context.Context, name string) (description fn.Description, err error) {
func (d *Describer) Describe(ctx context.Context, name string) (description fn.Info, err error) {
servingClient, err := NewServingClient(d.namespace)
if err != nil {

View File

@ -5,10 +5,10 @@ import (
"testing"
)
// Describe runs `func describe' command basic test.
func Describe(t *testing.T, knFunc *TestShellCmdRunner, project *FunctionTestProject) {
// Info runs `func info' command basic test.
func Info(t *testing.T, knFunc *TestShellCmdRunner, project *FunctionTestProject) {
result := knFunc.Exec("describe", "--path", project.ProjectPath, "--output", "plain")
result := knFunc.Exec("info", "--path", project.ProjectPath, "--output", "plain")
if result.Error != nil {
t.Fail()
}
@ -17,18 +17,18 @@ func Describe(t *testing.T, knFunc *TestShellCmdRunner, project *FunctionTestPro
// In case we have the route stored (i.e. by deploy command tested earlier)
// we compare just to verify they match
// otherwise we take advantage and capture the route from the output
routeFromDescribe := ""
routeFromInfo := ""
matches := regexp.MustCompile("Route (http.*)").FindStringSubmatch(result.Stdout)
if len(matches) > 1 {
routeFromDescribe = matches[1]
routeFromInfo = matches[1]
}
if routeFromDescribe == "" {
if routeFromInfo == "" {
t.Fatal("Function Route not present on output")
}
if project.FunctionURL != "" && project.FunctionURL != routeFromDescribe {
t.Fatalf("Expected Route %v but found %v", project.FunctionURL, routeFromDescribe)
if project.FunctionURL != "" && project.FunctionURL != routeFromInfo {
t.Fatalf("Expected Route %v but found %v", project.FunctionURL, routeFromInfo)
}
project.FunctionURL = routeFromDescribe
project.FunctionURL = routeFromInfo
}

View File

@ -21,7 +21,7 @@ func TestHttpFunction(t *testing.T) {
Deploy(t, knFunc, &project)
defer Delete(t, knFunc, &project)
ReadyCheck(t, knFunc, project)
Describe(t, knFunc, &project)
Info(t, knFunc, &project)
DefaultFunctionHttpTest(t, knFunc, project)
Update(t, knFunc, &project)
NewRevisionFunctionHttpTest(t, knFunc, project)
@ -40,8 +40,7 @@ func TestCloudEventsFunction(t *testing.T) {
Deploy(t, knFunc, &project)
defer Delete(t, knFunc, &project)
ReadyCheck(t, knFunc, project)
Describe(t, knFunc, &project)
Info(t, knFunc, &project)
DefaultFunctionEventsTest(t, knFunc, project)
}