diff --git a/cmd/kosli/get.go b/cmd/kosli/get.go index cb31a4ce1..a330c9c99 100644 --- a/cmd/kosli/get.go +++ b/cmd/kosli/get.go @@ -29,6 +29,7 @@ func newGetCmd(out io.Writer) *cobra.Command { newGetAttestationCmd(out), newGetRepoCmd(out), newGetServiceAccountCmd(out), + newGetDefaultOrgCmd(out), ) return cmd } diff --git a/cmd/kosli/getDefaultOrg.go b/cmd/kosli/getDefaultOrg.go new file mode 100644 index 000000000..e89f4e114 --- /dev/null +++ b/cmd/kosli/getDefaultOrg.go @@ -0,0 +1,95 @@ +package main + +import ( + "encoding/json" + "io" + "net/http" + "net/url" + + "github.com/kosli-dev/cli/internal/output" + "github.com/kosli-dev/cli/internal/requests" + "github.com/spf13/cobra" +) + +const getDefaultOrgShortDesc = `Get the default organization for the current user.` + +const getDefaultOrgLongDesc = getDefaultOrgShortDesc + ` +The default organization is the one selected by default in the Kosli Web UI when you log in.` + +const getDefaultOrgExample = ` +# get the default organization for the current user: +kosli get default-org \ + --api-token yourAPIToken +` + +type getDefaultOrgOptions struct { + output string +} + +// defaultOrg models the response of GET api/v2/user/default-org. +type defaultOrg struct { + DefaultOrgName string `json:"default_org_name"` +} + +func newGetDefaultOrgCmd(out io.Writer) *cobra.Command { + o := new(getDefaultOrgOptions) + cmd := &cobra.Command{ + Use: "default-org", + Short: getDefaultOrgShortDesc, + Long: getDefaultOrgLongDesc, + Example: getDefaultOrgExample, + Args: cobra.NoArgs, + PreRunE: func(cmd *cobra.Command, args []string) error { + if err := RequireGlobalFlags(global, []string{"ApiToken"}); err != nil { + return ErrorBeforePrintingUsage(cmd, err.Error()) + } + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + return o.run(out) + }, + } + + cmd.Flags().StringVarP(&o.output, "output", "o", "table", outputFlag) + + return cmd +} + +func (o *getDefaultOrgOptions) run(out io.Writer) error { + url, err := url.JoinPath(global.Host, "api/v2/user/default-org") + if err != nil { + return err + } + + reqParams := &requests.RequestParams{ + Method: http.MethodGet, + URL: url, + Token: global.ApiToken, + } + response, err := kosliClient.Do(reqParams) + if err != nil { + return err + } + + return output.FormattedPrint(response.Body, o.output, out, 0, + map[string]output.FormatOutputFunc{ + "table": printDefaultOrgAsTable, + "json": output.PrintJson, + }) +} + +// printDefaultOrgAsTable renders the default organization name. +func printDefaultOrgAsTable(raw string, out io.Writer, page int) error { + var org defaultOrg + if err := json.Unmarshal([]byte(raw), &org); err != nil { + return err + } + + name := org.DefaultOrgName + if name == "" { + name = "(none set)" + } + rows := []string{"Default organization:\t" + name} + tabFormattedPrint(out, []string{}, rows) + return nil +} diff --git a/cmd/kosli/getDefaultOrg_test.go b/cmd/kosli/getDefaultOrg_test.go new file mode 100644 index 000000000..f4ff2f720 --- /dev/null +++ b/cmd/kosli/getDefaultOrg_test.go @@ -0,0 +1,83 @@ +package main + +import ( + "bytes" + "fmt" + "testing" + + "github.com/maxcnunes/httpfake" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" +) + +func TestPrintDefaultOrgAsTable(t *testing.T) { + raw := `{"default_org_name":"test-org"}` + + var buf bytes.Buffer + err := printDefaultOrgAsTable(raw, &buf, 0) + require.NoError(t, err) + + out := buf.String() + for _, want := range []string{"Default organization:", "test-org"} { + require.Contains(t, out, want) + } +} + +func TestPrintDefaultOrgAsTableNoneSet(t *testing.T) { + raw := `{"default_org_name":""}` + + var buf bytes.Buffer + err := printDefaultOrgAsTable(raw, &buf, 0) + require.NoError(t, err) + require.Regexp(t, `Default organization:\s+\(none set\)`, buf.String()) +} + +type GetDefaultOrgCommandTestSuite struct { + suite.Suite + defaultKosliArguments string +} + +func (suite *GetDefaultOrgCommandTestSuite) SetupTest() { + global = &GlobalOpts{ + ApiToken: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6ImNkNzg4OTg5In0.e8i_lA_QrEhFncb05Xw6E_tkCHU9QfcY4OLTVUCHffY", + Host: "http://localhost:8001", + } + suite.defaultKosliArguments = fmt.Sprintf(" --host %s --api-token %s", global.Host, global.ApiToken) +} + +func (suite *GetDefaultOrgCommandTestSuite) TestGetDefaultOrgCmd() { + fake := httpfake.New() + defer fake.Close() + fake.NewHandler(). + Get("/api/v2/user/default-org"). + Reply(200). + BodyString(`{"default_org_name":"test-org"}`) + + args := fmt.Sprintf(" --host %s --api-token %s", fake.Server.URL, global.ApiToken) + tests := []cmdTestCase{ + { + wantError: false, + name: "get default-org prints the org name as a table", + cmd: "get default-org" + args, + goldenRegex: `Default organization:\s+test-org`, + }, + { + wantError: false, + name: "get default-org supports --output json", + cmd: "get default-org --output json" + args, + goldenRegex: `(?s)"default_org_name":\s*"test-org"`, + }, + { + wantError: true, + name: "get default-org fails when an argument is provided", + cmd: "get default-org extra-arg" + args, + golden: "Error: unknown command \"extra-arg\" for \"kosli get default-org\"\n", + }, + } + + runTestCmd(suite.T(), tests) +} + +func TestGetDefaultOrgCommandTestSuite(t *testing.T) { + suite.Run(t, new(GetDefaultOrgCommandTestSuite)) +} diff --git a/cmd/kosli/updateDefaultOrg.go b/cmd/kosli/updateDefaultOrg.go index eba1ab28f..7a26bd59a 100644 --- a/cmd/kosli/updateDefaultOrg.go +++ b/cmd/kosli/updateDefaultOrg.go @@ -12,7 +12,7 @@ import ( const updateDefaultOrgShortDesc = `Set the default organization for the current user.` const updateDefaultOrgLongDesc = updateDefaultOrgShortDesc + ` -The default organization is used by Kosli Web UI when logging in. +The default organization is the one selected by default in the Kosli Web UI when you log in. ` const updateDefaultOrgExample = `