Skip to content

Commit

Permalink
Add get command (#85)
Browse files Browse the repository at this point in the history
  • Loading branch information
zhilingc authored and feast-ci-bot committed Jan 18, 2019
1 parent e81358f commit 172a0eb
Show file tree
Hide file tree
Showing 6 changed files with 343 additions and 31 deletions.
100 changes: 100 additions & 0 deletions cli/feast/cmd/get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package cmd

import (
"context"
"errors"
"fmt"

"github.com/gojek/feast/cli/feast/pkg/printer"
"github.com/gojek/feast/protos/generated/go/feast/core"
"github.com/spf13/cobra"
)

// listCmd represents the list command
var getCmd = &cobra.Command{
Use: "get [resource] [id]",
Short: "Get and print the details of the desired resource.",
Long: `Get and print the details of the desired resource.
Valid resources include:
- entity
- feature
- storage
- job
Examples:
- feast get entity myentity`,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return cmd.Help()
}

if len(args) != 2 {
return errors.New("invalid number of arguments for list command")
}

initConn()
err := get(args[0], args[1])
if err != nil {
return fmt.Errorf("failed to list %s: %v", args[0], err)
}
return nil
},
}

func init() {
rootCmd.AddCommand(getCmd)
}

func get(resource string, id string) error {
ctx := context.Background()

switch resource {
case "feature":
return getFeature(ctx, core.NewUIServiceClient(coreConn), id)
case "entity":
return getEntity(ctx, core.NewUIServiceClient(coreConn), id)
case "storage":
return getStorage(ctx, core.NewUIServiceClient(coreConn), id)
case "job":
return getJob(ctx, core.NewJobServiceClient(coreConn), id)
default:
return fmt.Errorf("invalid resource %s: please choose one of [features, entities, storage, jobs]", resource)
}
}

func getFeature(ctx context.Context, cli core.UIServiceClient, id string) error {
response, err := cli.GetFeature(ctx, &core.UIServiceTypes_GetFeatureRequest{Id: id})
if err != nil {
return err
}
printer.PrintFeatureDetail(response.GetFeature())
return nil
}

func getEntity(ctx context.Context, cli core.UIServiceClient, id string) error {
response, err := cli.GetEntity(ctx, &core.UIServiceTypes_GetEntityRequest{Id: id})
if err != nil {
return err
}
printer.PrintEntityDetail(response.GetEntity())
return nil
}

func getStorage(ctx context.Context, cli core.UIServiceClient, id string) error {
response, err := cli.GetStorage(ctx, &core.UIServiceTypes_GetStorageRequest{Id: id})
if err != nil {
return err
}
printer.PrintStorageDetail(response.GetStorage())
return nil
}

func getJob(ctx context.Context, cli core.JobServiceClient, id string) error {
response, err := cli.GetJob(ctx, &core.JobServiceTypes_GetJobRequest{Id: id})
if err != nil {
return err
}
printer.PrintJobDetail(response.GetJob())
return nil
}
28 changes: 0 additions & 28 deletions cli/feast/cmd/jobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"io/ioutil"

"github.com/gojek/feast/cli/feast/pkg/parse"
"github.com/gojek/feast/cli/feast/pkg/printer"
"github.com/gojek/feast/protos/generated/go/feast/core"

"github.com/spf13/cobra"
Expand All @@ -48,21 +47,6 @@ var jobsRunCmd = &cobra.Command{
},
}

var jobsInfoCmd = &cobra.Command{
Use: "info [job_id]",
Short: "Get details for a single job",
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return cmd.Help()
}
if len(args) > 1 {
return errors.New("invalid number of arguments for jobs info command")
}
ctx := context.Background()
return getJob(ctx, args[0])
},
}

var jobsAbortCmd = &cobra.Command{
Use: "stop [job_id]",
Short: "Stop the given job",
Expand All @@ -80,7 +64,6 @@ var jobsAbortCmd = &cobra.Command{

func init() {
jobsCmd.AddCommand(jobsRunCmd)
jobsCmd.AddCommand(jobsInfoCmd)
jobsCmd.AddCommand(jobsAbortCmd)
rootCmd.AddCommand(jobsCmd)
}
Expand All @@ -106,17 +89,6 @@ func runJob(ctx context.Context, path string) error {
return nil
}

func getJob(ctx context.Context, id string) error {
initConn()
jobsClient := core.NewJobServiceClient(coreConn)
response, err := jobsClient.GetJob(ctx, &core.JobServiceTypes_GetJobRequest{Id: id})
if err != nil {
return err
}
printer.PrintJobDetail(response.GetJob())
return nil
}

func abortJob(ctx context.Context, id string) error {
initConn()
jobsClient := core.NewJobServiceClient(coreConn)
Expand Down
9 changes: 6 additions & 3 deletions cli/feast/pkg/printer/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ import (
"github.com/gojek/feast/protos/generated/go/feast/core"
)

// PrintJobDetail pretty prints the given job detail
func PrintJobDetail(jobDetail *core.JobServiceTypes_JobDetail) {
// PrintJobDetail pretty prints the given job detail.
// Prints and returns the resultant formatted string.
func PrintJobDetail(jobDetail *core.JobServiceTypes_JobDetail) string {
lines := []string{fmt.Sprintf("%s:\t%s", "Id", jobDetail.GetId()),
fmt.Sprintf("%s:\t%s", "Ext Id", jobDetail.GetExtId()),
fmt.Sprintf("%s:\t%s", "Type", jobDetail.GetType()),
Expand All @@ -46,7 +47,9 @@ func PrintJobDetail(jobDetail *core.JobServiceTypes_JobDetail) {
for _, feature := range jobDetail.GetFeatures() {
lines = append(lines, printFeature(feature, jobDetail.GetMetrics()))
}
fmt.Println(strings.Join(lines, "\n"))
out := strings.Join(lines, "\n")
fmt.Println(out)
return out
}

func printEntity(entityName string, metrics map[string]float64) string {
Expand Down
146 changes: 146 additions & 0 deletions cli/feast/pkg/printer/printer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package printer

import (
"testing"

"github.com/golang/protobuf/ptypes/timestamp"

"github.com/gojek/feast/protos/generated/go/feast/core"
"github.com/gojek/feast/protos/generated/go/feast/specs"
"github.com/gojek/feast/protos/generated/go/feast/types"
)

func TestPrintFeature(t *testing.T) {
tt := []struct {
name string
input *core.UIServiceTypes_FeatureDetail
expected string
}{
{
name: "with storage",
input: &core.UIServiceTypes_FeatureDetail{
Spec: &specs.FeatureSpec{
Id: "test.none.test_feature_two",
Owner: "[email protected]",
Name: "test_feature_two",
Description: "testing feature",
Uri: "https://github.com/bob/example",
Granularity: types.Granularity_NONE,
ValueType: types.ValueType_INT64,
Entity: "test",
DataStores: &specs.DataStores{
Serving: &specs.DataStore{
Id: "REDIS",
},
Warehouse: &specs.DataStore{
Id: "BIGQUERY",
},
},
},
BigqueryView: "bqurl",
Jobs: []string{"job1", "job2"},
LastUpdated: &timestamp.Timestamp{Seconds: 1},
Created: &timestamp.Timestamp{Seconds: 1},
},
expected: `Id: test.none.test_feature_two
Entity: test
Owner: [email protected]
Description: testing feature
ValueType: INT64
Uri: https://github.com/bob/example
DataStores:
Serving: REDIS
Warehouse: BIGQUERY
Created: 1970-01-01T07:30:01+07:30
LastUpdated: 1970-01-01T07:30:01+07:30
Related Jobs:
- job1
- job2`,
}, {
name: "no storage",
input: &core.UIServiceTypes_FeatureDetail{
Spec: &specs.FeatureSpec{
Id: "test.none.test_feature_two",
Owner: "[email protected]",
Name: "test_feature_two",
Description: "testing feature",
Uri: "https://github.com/bob/example",
Granularity: types.Granularity_NONE,
ValueType: types.ValueType_INT64,
Entity: "test",
},
BigqueryView: "bqurl",
Jobs: []string{"job1", "job2"},
LastUpdated: &timestamp.Timestamp{Seconds: 1},
Created: &timestamp.Timestamp{Seconds: 1},
},
expected: `Id: test.none.test_feature_two
Entity: test
Owner: [email protected]
Description: testing feature
ValueType: INT64
Uri: https://github.com/bob/example
Created: 1970-01-01T07:30:01+07:30
LastUpdated: 1970-01-01T07:30:01+07:30
Related Jobs:
- job1
- job2`,
},
}

for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
out := PrintFeatureDetail(tc.input)
if out != tc.expected {
t.Errorf("Expected output:\n%s \nActual:\n%s \n", tc.expected, out)
}
})
}
}

func TestPrintEntity(t *testing.T) {
entityDetail := &core.UIServiceTypes_EntityDetail{
Spec: &specs.EntitySpec{
Name: "test",
Description: "my test entity",
Tags: []string{"tag1", "tag2"},
},
Jobs: []string{"job1", "job2"},
LastUpdated: &timestamp.Timestamp{Seconds: 1},
}
out := PrintEntityDetail(entityDetail)
expected := `Name: test
Description: my test entity
Tags: tag1,tag2
LastUpdated: 1970-01-01T07:30:01+07:30
Related Jobs:
- job1
- job2`
if out != expected {
t.Errorf("Expected output:\n%s \nActual:\n%s \n", expected, out)
}
}

func TestPrintStorage(t *testing.T) {
storageDetail := &core.UIServiceTypes_StorageDetail{
Spec: &specs.StorageSpec{
Id: "REDIS1",
Type: "redis",
Options: map[string]string{
"option1": "value1",
"option2": "value2",
},
},
LastUpdated: &timestamp.Timestamp{Seconds: 1},
}
out := PrintStorageDetail(storageDetail)
expected := `Id: REDIS1
Type: redis
Options:
option1: value1
option2: value2
LastUpdated: 1970-01-01T07:30:01+07:30`
if out != expected {
t.Errorf("Expected output:\n%s \nActual:\n%s \n", expected, out)
}
}
Loading

0 comments on commit 172a0eb

Please sign in to comment.