diff --git a/cmd/cli/app/project/role/role_grant.go b/cmd/cli/app/project/role/role_grant.go index dcb230922c..b6a64c7bc7 100644 --- a/cmd/cli/app/project/role/role_grant.go +++ b/cmd/cli/app/project/role/role_grant.go @@ -17,12 +17,17 @@ package role import ( "context" + "fmt" "os" + "strings" + "time" "github.com/spf13/cobra" "github.com/spf13/viper" "google.golang.org/grpc" + "github.com/stacklok/minder/cmd/cli/app" + "github.com/stacklok/minder/internal/util" "github.com/stacklok/minder/internal/util/cli" minderv1 "github.com/stacklok/minder/pkg/api/protobuf/go/minder/v1" ) @@ -43,6 +48,12 @@ func GrantCommand(ctx context.Context, cmd *cobra.Command, _ []string, conn *grp r := viper.GetString("role") project := viper.GetString("project") email := viper.GetString("email") + format := viper.GetString("output") + + // Ensure the output format is supported + if !app.IsOutputFormatSupported(format) { + return cli.MessageAndError(fmt.Sprintf("Output format %s not supported", format), fmt.Errorf("invalid argument")) + } // No longer print usage on returned error, since we've parsed our inputs // See https://github.com/spf13/cobra/issues/340#issuecomment-374617413 @@ -64,7 +75,7 @@ func GrantCommand(ctx context.Context, cmd *cobra.Command, _ []string, conn *grp successMsg = "Invite created successfully." } - ret, err := client.AssignRole(ctx, &minderv1.AssignRoleRequest{ + resp, err := client.AssignRole(ctx, &minderv1.AssignRoleRequest{ Context: &minderv1.Context{ Project: &project, }, @@ -74,12 +85,30 @@ func GrantCommand(ctx context.Context, cmd *cobra.Command, _ []string, conn *grp return cli.MessageAndError(failMsg, err) } - cmd.Println(successMsg) - - if ret.Invitation != nil && ret.Invitation.Code != "" { - cmd.Printf("\nThe invitee can accept it by running: \n\nminder auth invite accept %s\n", ret.Invitation.Code) - if ret.Invitation.InviteUrl != "" { - cmd.Printf("\nOr by visiting: %s\n", ret.Invitation.InviteUrl) + switch format { + case app.JSON: + out, err := util.GetJsonFromProto(resp) + if err != nil { + return cli.MessageAndError("Error getting json from proto", err) + } + cmd.Println(out) + case app.YAML: + out, err := util.GetYamlFromProto(resp) + if err != nil { + return cli.MessageAndError("Error getting yaml from proto", err) + } + cmd.Println(out) + case app.Table: + cmd.Println(successMsg) + if resp.Invitation != nil && resp.Invitation.Code != "" { + t := initializeTableForGrantListInvitations() + i := resp.Invitation + t.AddRow(i.Email, i.Role, i.SponsorDisplay, i.ExpiresAt.AsTime().Format(time.RFC3339)) + t.Render() + cmd.Printf("\nThe invitee can accept it by running: \n\nminder auth invite accept %s\n", resp.Invitation.Code) + if resp.Invitation.InviteUrl != "" { + cmd.Printf("\nOr by visiting: %s\n", resp.Invitation.InviteUrl) + } } } return nil @@ -91,6 +120,8 @@ func init() { grantCmd.Flags().StringP("sub", "s", "", "subject to grant access to") grantCmd.Flags().StringP("role", "r", "", "the role to grant") grantCmd.Flags().StringP("email", "e", "", "email to send invitation to") + grantCmd.Flags().StringP("output", "o", app.Table, + fmt.Sprintf("Output format (one of %s)", strings.Join(app.SupportedOutputFormats(), ","))) grantCmd.MarkFlagsOneRequired("sub", "email") grantCmd.MarkFlagsMutuallyExclusive("sub", "email") if err := grantCmd.MarkFlagRequired("role"); err != nil { diff --git a/cmd/cli/app/project/role/role_update.go b/cmd/cli/app/project/role/role_update.go index f3ec43293f..f906b6021a 100644 --- a/cmd/cli/app/project/role/role_update.go +++ b/cmd/cli/app/project/role/role_update.go @@ -18,11 +18,14 @@ package role import ( "context" "fmt" + "strings" "github.com/spf13/cobra" "github.com/spf13/viper" "google.golang.org/grpc" + "github.com/stacklok/minder/cmd/cli/app" + "github.com/stacklok/minder/internal/util" "github.com/stacklok/minder/internal/util/cli" minderv1 "github.com/stacklok/minder/pkg/api/protobuf/go/minder/v1" ) @@ -39,10 +42,16 @@ to a user (subject) on a particular project.`, func UpdateCommand(ctx context.Context, cmd *cobra.Command, _ []string, conn *grpc.ClientConn) error { client := minderv1.NewPermissionsServiceClient(conn) - r := viper.GetString("role") + role := viper.GetString("role") project := viper.GetString("project") sub := viper.GetString("sub") email := viper.GetString("email") + format := viper.GetString("output") + + // Ensure the output format is supported + if !app.IsOutputFormatSupported(format) { + return cli.MessageAndError(fmt.Sprintf("Output format %s not supported", format), fmt.Errorf("invalid argument")) + } // No longer print usage on returned error, since we've parsed our inputs // See https://github.com/spf13/cobra/issues/340#issuecomment-374617413 @@ -52,7 +61,7 @@ func UpdateCommand(ctx context.Context, cmd *cobra.Command, _ []string, conn *gr Context: &minderv1.Context{ Project: &project, }, - Roles: []string{r}, + Roles: []string{role}, Subject: sub, } failMsg := "Error updating role" @@ -63,28 +72,44 @@ func UpdateCommand(ctx context.Context, cmd *cobra.Command, _ []string, conn *gr successMsg = "Invite updated successfully." } - ret, err := client.UpdateRole(ctx, req) + resp, err := client.UpdateRole(ctx, req) if err != nil { return cli.MessageAndError(failMsg, err) } - cmd.Println(successMsg) - - // If it was an invitation, print the invite details - if len(ret.Invitations) != 0 { - for _, r := range ret.Invitations { - // TODO: Add a url to the invite - cmd.Printf("Updated an invite for %s to %s on %s\n\nThe invitee can accept it by running: \n\nminder auth invite accept %s\n", - r.Email, r.Role, r.Project, r.Code) + switch format { + case app.JSON: + out, err := util.GetJsonFromProto(resp) + if err != nil { + return cli.MessageAndError("Error getting json from proto", err) } - return nil - } - // Otherwise, print the role assignments if it was about updating a role - t := initializeTableForGrantListRoleAssignments() - for _, r := range ret.RoleAssignments { - t.AddRow(fmt.Sprintf("%s / %s", r.DisplayName, r.Subject), r.Role, *r.Project) + cmd.Println(out) + case app.YAML: + out, err := util.GetYamlFromProto(resp) + if err != nil { + return cli.MessageAndError("Error getting yaml from proto", err) + } + cmd.Println(out) + case app.Table: + cmd.Println(successMsg) + // If it was an invitation, print the invite details + if len(resp.Invitations) != 0 { + for _, r := range resp.Invitations { + cmd.Printf("Updated an invite for %s to %s on %s\n\nThe invitee can accept it by running: \n\nminder auth invite accept %s\n", + r.Email, r.Role, r.Project, r.Code) + if r.InviteUrl != "" { + cmd.Printf("\nOr by visiting: %s\n", r.InviteUrl) + } + } + return nil + } + // Otherwise, print the role assignments if it was about updating a role + t := initializeTableForGrantListRoleAssignments() + for _, r := range resp.RoleAssignments { + t.AddRow(fmt.Sprintf("%s / %s", r.DisplayName, r.Subject), r.Role, *r.Project) + } + t.Render() } - t.Render() return nil } @@ -94,6 +119,8 @@ func init() { updateCmd.Flags().StringP("role", "r", "", "the role to update it to") updateCmd.Flags().StringP("sub", "s", "", "subject to update role access for") updateCmd.Flags().StringP("email", "e", "", "email to send invitation to") + updateCmd.Flags().StringP("output", "o", app.Table, + fmt.Sprintf("Output format (one of %s)", strings.Join(app.SupportedOutputFormats(), ","))) updateCmd.MarkFlagsOneRequired("sub", "email") updateCmd.MarkFlagsMutuallyExclusive("sub", "email") }