From 5d4f3bf79a114a3dc51974725f92d0478c8e78cf Mon Sep 17 00:00:00 2001 From: Maximilian Date: Wed, 6 May 2026 15:49:54 +0200 Subject: [PATCH 01/12] add list organizations command Signed-off-by: Maximilian --- cli/cmd/list_organizations_test.go | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/cli/cmd/list_organizations_test.go b/cli/cmd/list_organizations_test.go index cdf1c71b..d7713d07 100644 --- a/cli/cmd/list_organizations_test.go +++ b/cli/cmd/list_organizations_test.go @@ -16,6 +16,7 @@ import ( "go.yaml.in/yaml/v2" "github.com/codesphere-cloud/cs-go/api" + //"github.com/codesphere-cloud/cs-go/api/openapi_client" "github.com/codesphere-cloud/cs-go/cli/cmd" ) @@ -24,6 +25,7 @@ var _ = Describe("Organization", func() { mockEnv *cmd.MockEnv mockClient *cmd.MockClient l cmd.ListOrgCmd + //organizationApiMock *openapi_client.MockOrganizationsAPI ) BeforeEach(func() { @@ -38,6 +40,8 @@ var _ = Describe("Organization", func() { }, ClientFactory: cmd.NewClient, // Default to real client, will be overridden in specific tests } + //organizationApiMock = openapi_client.NewMockOrganizationsAPI(GinkgoT()) + }) AfterEach(func() { @@ -128,11 +132,8 @@ var _ = Describe("Organization", func() { orgs, err := l.ListOrganizations(mockClient) - Expect(err).NotTo(HaveOccurred()) - Expect(orgs).To(Equal(expectedOrgs)) - // Restore Stdout - err = w.Close() + w.Close() var buf bytes.Buffer _, _ = io.Copy(&buf, r) os.Stdout = oldStdout @@ -161,13 +162,9 @@ var _ = Describe("Organization", func() { os.Stdout = w orgs, err := l.ListOrganizations(mockClient) - Expect(err).NotTo(HaveOccurred()) - Expect(orgs).To(Equal(expectedOrgs)) - - // Restore Stdout - err = w.Close() + w.Close() var buf bytes.Buffer _, _ = io.Copy(&buf, r) os.Stdout = oldStdout From 4e3f1a7040cd7915d56c52a5b05635cc24e9b3f0 Mon Sep 17 00:00:00 2001 From: Maximilian Date: Wed, 6 May 2026 16:01:41 +0200 Subject: [PATCH 02/12] feat(test): removed old code Signed-off-by: Maximilian --- cli/cmd/list_organizations_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cli/cmd/list_organizations_test.go b/cli/cmd/list_organizations_test.go index d7713d07..200e9b74 100644 --- a/cli/cmd/list_organizations_test.go +++ b/cli/cmd/list_organizations_test.go @@ -16,7 +16,6 @@ import ( "go.yaml.in/yaml/v2" "github.com/codesphere-cloud/cs-go/api" - //"github.com/codesphere-cloud/cs-go/api/openapi_client" "github.com/codesphere-cloud/cs-go/cli/cmd" ) @@ -25,7 +24,6 @@ var _ = Describe("Organization", func() { mockEnv *cmd.MockEnv mockClient *cmd.MockClient l cmd.ListOrgCmd - //organizationApiMock *openapi_client.MockOrganizationsAPI ) BeforeEach(func() { @@ -40,8 +38,6 @@ var _ = Describe("Organization", func() { }, ClientFactory: cmd.NewClient, // Default to real client, will be overridden in specific tests } - //organizationApiMock = openapi_client.NewMockOrganizationsAPI(GinkgoT()) - }) AfterEach(func() { From 5db3e4ca4aaab6e63da497ce8d1668c9e653e751 Mon Sep 17 00:00:00 2001 From: Maximilian Date: Thu, 7 May 2026 00:16:48 +0200 Subject: [PATCH 03/12] add missing err checks for stdout closing Signed-off-by: Maximilian --- cli/cmd/list_organizations_test.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/cli/cmd/list_organizations_test.go b/cli/cmd/list_organizations_test.go index 200e9b74..cdf1c71b 100644 --- a/cli/cmd/list_organizations_test.go +++ b/cli/cmd/list_organizations_test.go @@ -128,8 +128,11 @@ var _ = Describe("Organization", func() { orgs, err := l.ListOrganizations(mockClient) + Expect(err).NotTo(HaveOccurred()) + Expect(orgs).To(Equal(expectedOrgs)) + // Restore Stdout - w.Close() + err = w.Close() var buf bytes.Buffer _, _ = io.Copy(&buf, r) os.Stdout = oldStdout @@ -158,9 +161,13 @@ var _ = Describe("Organization", func() { os.Stdout = w orgs, err := l.ListOrganizations(mockClient) + Expect(err).NotTo(HaveOccurred()) + Expect(orgs).To(Equal(expectedOrgs)) + + // Restore Stdout - w.Close() + err = w.Close() var buf bytes.Buffer _, _ = io.Copy(&buf, r) os.Stdout = oldStdout From 99162d6e2fab59c77ebb555a4e52a1c63144b164 Mon Sep 17 00:00:00 2001 From: DerBurri <7892993+DerBurri@users.noreply.github.com> Date: Wed, 13 May 2026 12:11:01 +0000 Subject: [PATCH 04/12] chore(docs): Auto-update docs and licenses Signed-off-by: DerBurri <7892993+DerBurri@users.noreply.github.com> --- NOTICE | 36 ++++++++++++++++++------------------ pkg/tmpl/NOTICE | 36 ++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/NOTICE b/NOTICE index b8ff6df2..58474a56 100644 --- a/NOTICE +++ b/NOTICE @@ -119,15 +119,15 @@ License URL: https://github.com/go-git/gcfg/blob/3a3c6141e376/LICENSE ---------- Module: github.com/go-git/go-billy/v5 -Version: v5.8.0 +Version: v5.9.0 License: Apache-2.0 -License URL: https://github.com/go-git/go-billy/blob/v5.8.0/LICENSE +License URL: https://github.com/go-git/go-billy/blob/v5.9.0/LICENSE ---------- Module: github.com/go-git/go-git/v5 -Version: v5.18.0 +Version: v5.19.0 License: Apache-2.0 -License URL: https://github.com/go-git/go-git/blob/v5.18.0/LICENSE +License URL: https://github.com/go-git/go-git/blob/v5.19.0/LICENSE ---------- Module: github.com/go-logr/logr @@ -257,9 +257,9 @@ License URL: https://github.com/onsi/gomega/blob/v1.40.0/LICENSE ---------- Module: github.com/pjbgf/sha1cd -Version: v0.5.0 +Version: v0.6.0 License: Apache-2.0 -License URL: https://github.com/pjbgf/sha1cd/blob/v0.5.0/LICENSE +License URL: https://github.com/pjbgf/sha1cd/blob/v0.6.0/LICENSE ---------- Module: github.com/pmezard/go-difflib/difflib @@ -461,39 +461,39 @@ License URL: https://github.com/go-yaml/yaml/blob/v3.0.1/LICENSE ---------- Module: k8s.io/api -Version: v0.36.0 +Version: v0.36.1 License: Apache-2.0 -License URL: https://github.com/kubernetes/api/blob/v0.36.0/LICENSE +License URL: https://github.com/kubernetes/api/blob/v0.36.1/LICENSE ---------- Module: k8s.io/apimachinery/pkg -Version: v0.36.0 +Version: v0.36.1 License: Apache-2.0 -License URL: https://github.com/kubernetes/apimachinery/blob/v0.36.0/LICENSE +License URL: https://github.com/kubernetes/apimachinery/blob/v0.36.1/LICENSE ---------- Module: k8s.io/apimachinery/third_party/forked/golang/reflect -Version: v0.36.0 +Version: v0.36.1 License: BSD-3-Clause -License URL: https://github.com/kubernetes/apimachinery/blob/v0.36.0/third_party/forked/golang/LICENSE +License URL: https://github.com/kubernetes/apimachinery/blob/v0.36.1/third_party/forked/golang/LICENSE ---------- Module: k8s.io/cli-runtime/pkg/printers -Version: v0.36.0 +Version: v0.36.1 License: Apache-2.0 -License URL: https://github.com/kubernetes/cli-runtime/blob/v0.36.0/LICENSE +License URL: https://github.com/kubernetes/cli-runtime/blob/v0.36.1/LICENSE ---------- Module: k8s.io/client-go/third_party/forked/golang/template -Version: v0.36.0 +Version: v0.36.1 License: BSD-3-Clause -License URL: https://github.com/kubernetes/client-go/blob/v0.36.0/third_party/forked/golang/LICENSE +License URL: https://github.com/kubernetes/client-go/blob/v0.36.1/third_party/forked/golang/LICENSE ---------- Module: k8s.io/client-go/util/jsonpath -Version: v0.36.0 +Version: v0.36.1 License: Apache-2.0 -License URL: https://github.com/kubernetes/client-go/blob/v0.36.0/LICENSE +License URL: https://github.com/kubernetes/client-go/blob/v0.36.1/LICENSE ---------- Module: k8s.io/klog/v2 diff --git a/pkg/tmpl/NOTICE b/pkg/tmpl/NOTICE index b8ff6df2..58474a56 100644 --- a/pkg/tmpl/NOTICE +++ b/pkg/tmpl/NOTICE @@ -119,15 +119,15 @@ License URL: https://github.com/go-git/gcfg/blob/3a3c6141e376/LICENSE ---------- Module: github.com/go-git/go-billy/v5 -Version: v5.8.0 +Version: v5.9.0 License: Apache-2.0 -License URL: https://github.com/go-git/go-billy/blob/v5.8.0/LICENSE +License URL: https://github.com/go-git/go-billy/blob/v5.9.0/LICENSE ---------- Module: github.com/go-git/go-git/v5 -Version: v5.18.0 +Version: v5.19.0 License: Apache-2.0 -License URL: https://github.com/go-git/go-git/blob/v5.18.0/LICENSE +License URL: https://github.com/go-git/go-git/blob/v5.19.0/LICENSE ---------- Module: github.com/go-logr/logr @@ -257,9 +257,9 @@ License URL: https://github.com/onsi/gomega/blob/v1.40.0/LICENSE ---------- Module: github.com/pjbgf/sha1cd -Version: v0.5.0 +Version: v0.6.0 License: Apache-2.0 -License URL: https://github.com/pjbgf/sha1cd/blob/v0.5.0/LICENSE +License URL: https://github.com/pjbgf/sha1cd/blob/v0.6.0/LICENSE ---------- Module: github.com/pmezard/go-difflib/difflib @@ -461,39 +461,39 @@ License URL: https://github.com/go-yaml/yaml/blob/v3.0.1/LICENSE ---------- Module: k8s.io/api -Version: v0.36.0 +Version: v0.36.1 License: Apache-2.0 -License URL: https://github.com/kubernetes/api/blob/v0.36.0/LICENSE +License URL: https://github.com/kubernetes/api/blob/v0.36.1/LICENSE ---------- Module: k8s.io/apimachinery/pkg -Version: v0.36.0 +Version: v0.36.1 License: Apache-2.0 -License URL: https://github.com/kubernetes/apimachinery/blob/v0.36.0/LICENSE +License URL: https://github.com/kubernetes/apimachinery/blob/v0.36.1/LICENSE ---------- Module: k8s.io/apimachinery/third_party/forked/golang/reflect -Version: v0.36.0 +Version: v0.36.1 License: BSD-3-Clause -License URL: https://github.com/kubernetes/apimachinery/blob/v0.36.0/third_party/forked/golang/LICENSE +License URL: https://github.com/kubernetes/apimachinery/blob/v0.36.1/third_party/forked/golang/LICENSE ---------- Module: k8s.io/cli-runtime/pkg/printers -Version: v0.36.0 +Version: v0.36.1 License: Apache-2.0 -License URL: https://github.com/kubernetes/cli-runtime/blob/v0.36.0/LICENSE +License URL: https://github.com/kubernetes/cli-runtime/blob/v0.36.1/LICENSE ---------- Module: k8s.io/client-go/third_party/forked/golang/template -Version: v0.36.0 +Version: v0.36.1 License: BSD-3-Clause -License URL: https://github.com/kubernetes/client-go/blob/v0.36.0/third_party/forked/golang/LICENSE +License URL: https://github.com/kubernetes/client-go/blob/v0.36.1/third_party/forked/golang/LICENSE ---------- Module: k8s.io/client-go/util/jsonpath -Version: v0.36.0 +Version: v0.36.1 License: Apache-2.0 -License URL: https://github.com/kubernetes/client-go/blob/v0.36.0/LICENSE +License URL: https://github.com/kubernetes/client-go/blob/v0.36.1/LICENSE ---------- Module: k8s.io/klog/v2 From 1487f91ff0b08c3c1557a3710e9b23c266bd147c Mon Sep 17 00:00:00 2001 From: Maximilian Date: Wed, 13 May 2026 14:18:32 +0200 Subject: [PATCH 05/12] feat(api): Add organization filtering to ListTeams chore(mock): Update MockClient.ListTeams signature test(cli): Update ListTeams mock expectation in list_workspaces_test feat(api): Add ConvertOrgTeamToTeam helper for organization teams refactor(cli): Simplify ListTeamsCmd.RunE to use new ListTeams signature feat(cli): Update Client interface for ListTeams to include orgId feat(cli): Add --org flag and GlobalOptions.OrgId for organization context feat(pkg): Add GetOrgId to Environment for CS_ORG_ID feat(cli): Implement 'cs list org' command to list organizations Signed-off-by: Maximilian --- api/client.go | 5 --- api/organization.go | 10 ++++++ api/team.go | 17 +++++++-- api/types.go | 14 ++++++++ cli/cmd/client.go | 2 +- cli/cmd/list_organizations_test.go | 4 +-- cli/cmd/list_teams.go | 3 +- cli/cmd/list_workspaces.go | 2 +- cli/cmd/list_workspaces_test.go | 2 +- cli/cmd/mocks.go | 58 +++++++++++++++--------------- cli/cmd/root.go | 25 +++++++------ pkg/cs/env.go | 8 +++-- 12 files changed, 93 insertions(+), 57 deletions(-) create mode 100644 api/organization.go diff --git a/api/client.go b/api/client.go index c3697311..51d794ae 100644 --- a/api/client.go +++ b/api/client.go @@ -145,8 +145,3 @@ func (c *Client) ListBaseimages() ([]Baseimage, error) { baseimages, r, err := c.api.MetadataAPI.MetadataGetWorkspaceBaseImages(c.ctx).Execute() return baseimages, errors.FormatAPIError(r, err) } - -func (c *Client) ListOrganizations() ([]Organization, error) { - organizations, r, err := c.api.OrganizationsAPI.OrganizationsListOrganizations(c.ctx).Execute() - return organizations, errors.FormatAPIError(r, err) -} diff --git a/api/organization.go b/api/organization.go new file mode 100644 index 00000000..16426f06 --- /dev/null +++ b/api/organization.go @@ -0,0 +1,10 @@ +package api + +import ( + cserrors "github.com/codesphere-cloud/cs-go/api/errors" +) + +func (c *Client) ListOrganizations() ([]Organization, error) { + organizations, r, err := c.api.OrganizationsAPI.OrganizationsListOrganizations(c.ctx).Execute() + return organizations, cserrors.FormatAPIError(r, err) +} diff --git a/api/team.go b/api/team.go index 2f259ca6..0456d1aa 100644 --- a/api/team.go +++ b/api/team.go @@ -16,7 +16,7 @@ import ( // Returns [NotFound] if no plan with the given Id could be found // Returns [Duplicated] if no plan with the given Id could be found func (client *Client) TeamIdByName(name string) (Team, error) { - teams, err := client.ListTeams() + teams, err := client.ListTeams("") if err != nil { return Team{}, err } @@ -39,7 +39,20 @@ func (client *Client) TeamIdByName(name string) (Team, error) { return matchingTeams[0], nil } -func (c *Client) ListTeams() ([]Team, error) { +func (c *Client) ListTeams(orgId string) ([]Team, error) { + if orgId != "" { + teams, r, err := c.api.OrganizationsAPI.OrganizationsListOrgTeams(c.ctx, orgId).Execute() + if err != nil { + return nil, cserrors.FormatAPIError(r, err) + } + + res := make([]Team, len(teams)) + for i, t := range teams { + res[i] = ConvertOrgTeamToTeam(t, orgId) + } + return res, nil + } + teams, r, err := c.api.TeamsAPI.TeamsListTeams(c.ctx).Execute() return teams, cserrors.FormatAPIError(r, err) } diff --git a/api/types.go b/api/types.go index f49d55f0..3b425b9d 100644 --- a/api/types.go +++ b/api/types.go @@ -39,6 +39,20 @@ func ConvertToTeam(t *openapi.TeamsGetTeam200Response) *Team { } } +func ConvertOrgTeamToTeam(t openapi.OrganizationsListOrgTeams200ResponseInner, orgId string) Team { + return Team{ + Id: t.Id, + DefaultDataCenterId: t.DefaultDataCenterId, + Name: t.Name, + Description: *openapi.NewNullableString(t.Description), + AvatarId: *openapi.NewNullableString(t.AvatarId), + AvatarUrl: *openapi.NewNullableString(t.AvatarUrl), + IsFirst: t.IsFirst, + OrganizationId: &orgId, + Role: 0, // Default to admin role if not specified by org API + } +} + type Time interface { Sleep(time.Duration) Now() time.Time diff --git a/cli/cmd/client.go b/cli/cmd/client.go index 5600c888..472b868a 100644 --- a/cli/cmd/client.go +++ b/cli/cmd/client.go @@ -16,7 +16,7 @@ import ( ) type Client interface { - ListTeams() ([]api.Team, error) + ListTeams(orgId string) ([]api.Team, error) ListWorkspaces(teamId int) ([]api.Workspace, error) ListBaseimages() ([]api.Baseimage, error) ListOrganizations() ([]api.Organization, error) diff --git a/cli/cmd/list_organizations_test.go b/cli/cmd/list_organizations_test.go index cdf1c71b..c7b197c8 100644 --- a/cli/cmd/list_organizations_test.go +++ b/cli/cmd/list_organizations_test.go @@ -33,7 +33,7 @@ var _ = Describe("Organization", func() { Opts: &cmd.ListOptions{ GlobalOptions: &cmd.GlobalOptions{ Env: mockEnv, - OrgId: -1, // force using the env mock to get a org ID + OrgId: "", // force using the env mock to get a org ID }, }, ClientFactory: cmd.NewClient, // Default to real client, will be overridden in specific tests @@ -164,8 +164,6 @@ var _ = Describe("Organization", func() { Expect(err).NotTo(HaveOccurred()) Expect(orgs).To(Equal(expectedOrgs)) - - // Restore Stdout err = w.Close() var buf bytes.Buffer diff --git a/cli/cmd/list_teams.go b/cli/cmd/list_teams.go index e7e87d33..812a2840 100644 --- a/cli/cmd/list_teams.go +++ b/cli/cmd/list_teams.go @@ -40,11 +40,10 @@ func (l *ListTeamsCmd) RunE(_ *cobra.Command, args []string) (err error) { return fmt.Errorf("failed to create Codesphere client: %w", err) } - teams, err := client.ListTeams() + teams, err := client.ListTeams(l.opts.OrgId) if err != nil { return fmt.Errorf("failed to list teams: %w", err) } - switch l.opts.OutputFormat { case OutputFormatJSON: return io.PrintJSON(teams) diff --git a/cli/cmd/list_workspaces.go b/cli/cmd/list_workspaces.go index 001f99ad..0f83ed62 100644 --- a/cli/cmd/list_workspaces.go +++ b/cli/cmd/list_workspaces.go @@ -96,7 +96,7 @@ func (l *ListWorkspacesCmd) getTeamIds(client Client) (teams []int, err error) { return } var allTeams []api.Team - allTeams, err = client.ListTeams() + allTeams, err = client.ListTeams(l.Opts.OrgId) if err != nil { return } diff --git a/cli/cmd/list_workspaces_test.go b/cli/cmd/list_workspaces_test.go index b38d6eca..79570700 100644 --- a/cli/cmd/list_workspaces_test.go +++ b/cli/cmd/list_workspaces_test.go @@ -53,7 +53,7 @@ var _ = Describe("Workspace", func() { Context("when team ID is not set", func() { It("lists workspaces of all teams when no team ID is set", func() { - mockClient.EXPECT().ListTeams().Return([]api.Team{{Id: 0}, {Id: 1}}, nil) + mockClient.EXPECT().ListTeams("").Return([]api.Team{{Id: 0}, {Id: 1}}, nil) expectedWorkspaces := []api.Workspace{ {Id: 0, Name: "fakeForTeam0"}, diff --git a/cli/cmd/mocks.go b/cli/cmd/mocks.go index 4bec542a..fbb450ec 100644 --- a/cli/cmd/mocks.go +++ b/cli/cmd/mocks.go @@ -595,8 +595,8 @@ func (_c *MockClient_ListOrganizations_Call) RunAndReturn(run func() ([]api.Orga } // ListTeams provides a mock function for the type MockClient -func (_mock *MockClient) ListTeams() ([]api.Team, error) { - ret := _mock.Called() +func (_mock *MockClient) ListTeams(orgId string) ([]api.Team, error) { + ret := _mock.Called(orgId) if len(ret) == 0 { panic("no return value specified for ListTeams") @@ -604,18 +604,18 @@ func (_mock *MockClient) ListTeams() ([]api.Team, error) { var r0 []api.Team var r1 error - if returnFunc, ok := ret.Get(0).(func() ([]api.Team, error)); ok { - return returnFunc() + if returnFunc, ok := ret.Get(0).(func(string) ([]api.Team, error)); ok { + return returnFunc(orgId) } - if returnFunc, ok := ret.Get(0).(func() []api.Team); ok { - r0 = returnFunc() + if returnFunc, ok := ret.Get(0).(func(string) []api.Team); ok { + r0 = returnFunc(orgId) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]api.Team) } } - if returnFunc, ok := ret.Get(1).(func() error); ok { - r1 = returnFunc() + if returnFunc, ok := ret.Get(1).(func(string) error); ok { + r1 = returnFunc(orgId) } else { r1 = ret.Error(1) } @@ -628,13 +628,20 @@ type MockClient_ListTeams_Call struct { } // ListTeams is a helper method to define mock.On call -func (_e *MockClient_Expecter) ListTeams() *MockClient_ListTeams_Call { - return &MockClient_ListTeams_Call{Call: _e.mock.On("ListTeams")} +// - orgId string +func (_e *MockClient_Expecter) ListTeams(orgId interface{}) *MockClient_ListTeams_Call { + return &MockClient_ListTeams_Call{Call: _e.mock.On("ListTeams", orgId)} } -func (_c *MockClient_ListTeams_Call) Run(run func()) *MockClient_ListTeams_Call { +func (_c *MockClient_ListTeams_Call) Run(run func(orgId string)) *MockClient_ListTeams_Call { _c.Call.Run(func(args mock.Arguments) { - run() + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + run( + arg0, + ) }) return _c } @@ -644,7 +651,7 @@ func (_c *MockClient_ListTeams_Call) Return(vs []api.Team, err error) *MockClien return _c } -func (_c *MockClient_ListTeams_Call) RunAndReturn(run func() ([]api.Team, error)) *MockClient_ListTeams_Call { +func (_c *MockClient_ListTeams_Call) RunAndReturn(run func(orgId string) ([]api.Team, error)) *MockClient_ListTeams_Call { _c.Call.Return(run) return _c } @@ -1502,29 +1509,20 @@ func (_c *MockEnv_GetApiUrl_Call) RunAndReturn(run func() string) *MockEnv_GetAp } // GetOrgId provides a mock function for the type MockEnv -func (_mock *MockEnv) GetOrgId() (int, error) { +func (_mock *MockEnv) GetOrgId() string { ret := _mock.Called() if len(ret) == 0 { panic("no return value specified for GetOrgId") } - var r0 int - var r1 error - if returnFunc, ok := ret.Get(0).(func() (int, error)); ok { - return returnFunc() - } - if returnFunc, ok := ret.Get(0).(func() int); ok { + var r0 string + if returnFunc, ok := ret.Get(0).(func() string); ok { r0 = returnFunc() } else { - r0 = ret.Get(0).(int) - } - if returnFunc, ok := ret.Get(1).(func() error); ok { - r1 = returnFunc() - } else { - r1 = ret.Error(1) + r0 = ret.Get(0).(string) } - return r0, r1 + return r0 } // MockEnv_GetOrgId_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetOrgId' @@ -1544,12 +1542,12 @@ func (_c *MockEnv_GetOrgId_Call) Run(run func()) *MockEnv_GetOrgId_Call { return _c } -func (_c *MockEnv_GetOrgId_Call) Return(n int, err error) *MockEnv_GetOrgId_Call { - _c.Call.Return(n, err) +func (_c *MockEnv_GetOrgId_Call) Return(s string) *MockEnv_GetOrgId_Call { + _c.Call.Return(s) return _c } -func (_c *MockEnv_GetOrgId_Call) RunAndReturn(run func() (int, error)) *MockEnv_GetOrgId_Call { +func (_c *MockEnv_GetOrgId_Call) RunAndReturn(run func() string) *MockEnv_GetOrgId_Call { _c.Call.Return(run) return _c } diff --git a/cli/cmd/root.go b/cli/cmd/root.go index 08001ce3..097201a2 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -5,9 +5,11 @@ package cmd import ( "errors" + "fmt" "os" "github.com/codesphere-cloud/cs-go/pkg/cs" + "github.com/google/uuid" "github.com/spf13/cobra" ) @@ -15,7 +17,7 @@ type GlobalOptions struct { ApiUrl string TeamId int WorkspaceId int - OrgId int + OrgId string Env Env Verbose bool } @@ -24,7 +26,7 @@ type Env interface { GetApiToken() (string, error) GetTeamId() (int, error) GetWorkspaceId() (int, error) - GetOrgId() (int, error) + GetOrgId() string GetApiUrl() string } @@ -63,18 +65,20 @@ func (o GlobalOptions) GetWorkspaceId() (int, error) { return wsId, nil } -func (o GlobalOptions) GetOrgId() (int, error) { - if o.OrgId != -1 { +func (o GlobalOptions) GetOrgId() (string, error) { + if o.OrgId != "" { return o.OrgId, nil } - orgId, err := o.Env.GetOrgId() - if err != nil { - return -1, err + orgId := o.Env.GetOrgId() + if orgId == "" { + return "", errors.New("organization ID not set, use -O or CS_ORG_ID to set it") } - if orgId < 0 { - // Note: No global flag for org-id currently exists in GetRootCmd - return -1, errors.New("organization ID not set, use CS_ORG_ID to set it") + + _, err := uuid.Parse(orgId) + if err != nil { + return "", fmt.Errorf("invalid organization UUID format: %w", err) } + return orgId, nil } @@ -102,6 +106,7 @@ func GetRootCmd() *cobra.Command { rootCmd.PersistentFlags().IntVarP(&opts.TeamId, "team", "t", -1, "Team ID (relevant for some commands, can also be CS_TEAM_ID)") rootCmd.PersistentFlags().IntVarP(&opts.WorkspaceId, "workspace", "w", -1, "Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID)") rootCmd.PersistentFlags().BoolVarP(&opts.Verbose, "verbose", "v", false, "Verbose output") + rootCmd.PersistentFlags().StringVarP(&opts.OrgId, "org", "O", "", "Organization ID (relevant for some commands)") AddExecCmd(rootCmd, &opts) AddLogCmd(rootCmd, &opts) diff --git a/pkg/cs/env.go b/pkg/cs/env.go index 7d7c35a7..c413ed63 100644 --- a/pkg/cs/env.go +++ b/pkg/cs/env.go @@ -38,8 +38,12 @@ func (e *Environment) GetTeamId() (int, error) { return e.ReadNumericEnv("CS_TEAM_ID") } -func (e *Environment) GetOrgId() (int, error) { - return e.ReadNumericEnv("CS_ORG_ID") +func (e *Environment) GetOrgId() string { + orgId := os.Getenv("CS_ORG_ID") + if orgId != "" { + return orgId + } + return "" } func (e *Environment) ReadNumericEnv(env string) (int, error) { From 30f7dad609c1a4fd4f75bf4f0751c049e5534a1b Mon Sep 17 00:00:00 2001 From: DerBurri <7892993+DerBurri@users.noreply.github.com> Date: Wed, 13 May 2026 12:20:37 +0000 Subject: [PATCH 06/12] chore(docs): Auto-update docs and licenses Signed-off-by: DerBurri <7892993+DerBurri@users.noreply.github.com> --- NOTICE | 6 ++++++ api/organization.go | 3 +++ docs/README.md | 1 + docs/cs.md | 1 + docs/cs_create.md | 1 + docs/cs_create_workspace.md | 1 + docs/cs_curl.md | 1 + docs/cs_delete.md | 1 + docs/cs_delete_workspace.md | 1 + docs/cs_exec.md | 1 + docs/cs_generate.md | 1 + docs/cs_generate_docker.md | 1 + docs/cs_generate_images.md | 1 + docs/cs_generate_kubernetes.md | 1 + docs/cs_git.md | 1 + docs/cs_git_pull.md | 1 + docs/cs_licenses.md | 1 + docs/cs_list.md | 1 + docs/cs_list_baseimages.md | 1 + docs/cs_list_org.md | 1 + docs/cs_list_plans.md | 1 + docs/cs_list_teams.md | 1 + docs/cs_list_workspaces.md | 1 + docs/cs_log.md | 1 + docs/cs_monitor.md | 1 + docs/cs_open.md | 1 + docs/cs_open_workspace.md | 1 + docs/cs_scale.md | 1 + docs/cs_scale_workspace.md | 1 + docs/cs_set-env.md | 1 + docs/cs_start.md | 1 + docs/cs_start_pipeline.md | 1 + docs/cs_sync.md | 1 + docs/cs_sync_landscape.md | 1 + docs/cs_update.md | 1 + docs/cs_version.md | 1 + docs/cs_wake-up.md | 1 + pkg/tmpl/NOTICE | 6 ++++++ 38 files changed, 50 insertions(+) diff --git a/NOTICE b/NOTICE index 58474a56..9cbfcd66 100644 --- a/NOTICE +++ b/NOTICE @@ -159,6 +159,12 @@ Version: v1.2.0 License: BSD-3-Clause License URL: https://github.com/google/go-querystring/blob/v1.2.0/LICENSE +---------- +Module: github.com/google/uuid +Version: v1.6.0 +License: BSD-3-Clause +License URL: https://github.com/google/uuid/blob/v1.6.0/LICENSE + ---------- Module: github.com/hashicorp/go-cleanhttp Version: v0.5.2 diff --git a/api/organization.go b/api/organization.go index 16426f06..5d40b5f9 100644 --- a/api/organization.go +++ b/api/organization.go @@ -1,3 +1,6 @@ +// Copyright (c) Codesphere Inc. +// SPDX-License-Identifier: Apache-2.0 + package api import ( diff --git a/docs/README.md b/docs/README.md index 0b42bd66..646937af 100644 --- a/docs/README.md +++ b/docs/README.md @@ -11,6 +11,7 @@ Manage and debug resources deployed in Codesphere via command line. ``` -a, --api string URL of Codesphere API (can also be CS_API) -h, --help help for cs + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs.md b/docs/cs.md index 0b42bd66..646937af 100644 --- a/docs/cs.md +++ b/docs/cs.md @@ -11,6 +11,7 @@ Manage and debug resources deployed in Codesphere via command line. ``` -a, --api string URL of Codesphere API (can also be CS_API) -h, --help help for cs + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_create.md b/docs/cs_create.md index 38bf3595..8d99eb7d 100644 --- a/docs/cs_create.md +++ b/docs/cs_create.md @@ -16,6 +16,7 @@ Create codesphere resources like workspaces. ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_create_workspace.md b/docs/cs_create_workspace.md index d2565267..aa9f89c2 100644 --- a/docs/cs_create_workspace.md +++ b/docs/cs_create_workspace.md @@ -64,6 +64,7 @@ $ cs create workspace my-workspace -r https://github.com/my-org/my-private-proje ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_curl.md b/docs/cs_curl.md index 73bd0221..b79302cf 100644 --- a/docs/cs_curl.md +++ b/docs/cs_curl.md @@ -46,6 +46,7 @@ $ cs curl / -- -I ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_delete.md b/docs/cs_delete.md index f9770934..de17965f 100644 --- a/docs/cs_delete.md +++ b/docs/cs_delete.md @@ -16,6 +16,7 @@ Delete Codesphere resources, e.g. workspaces. ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_delete_workspace.md b/docs/cs_delete_workspace.md index 4f3deeed..f0719f6e 100644 --- a/docs/cs_delete_workspace.md +++ b/docs/cs_delete_workspace.md @@ -23,6 +23,7 @@ cs delete workspace [flags] ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_exec.md b/docs/cs_exec.md index 0505840a..47c79916 100644 --- a/docs/cs_exec.md +++ b/docs/cs_exec.md @@ -39,6 +39,7 @@ $ cs exec -e FOO=bar -- 'echo $FOO' ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_generate.md b/docs/cs_generate.md index c0528bd0..66a9ef96 100644 --- a/docs/cs_generate.md +++ b/docs/cs_generate.md @@ -23,6 +23,7 @@ on your local machine to run the artifact generation. ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_generate_docker.md b/docs/cs_generate_docker.md index 7c0373d6..2355f4fa 100644 --- a/docs/cs_generate_docker.md +++ b/docs/cs_generate_docker.md @@ -51,6 +51,7 @@ $ cs generate docker -w 1234 -i ci.prod.yml --branch string Branch of the repository to clone if the input file is not found (default "main") -f, --force Overwrite any files if existing -i, --input string CI profile to use as input for generation, relative to repository root (default "ci.yml") + -O, --org string Organization ID (relevant for some commands) -o, --output string Output path of the folder including generated artifacts, relative to repository root (default "export") --reporoot string root directory of the workspace repository to export. Will be used to clone the repository if it doesn't exist. (default "./workspace-repo") -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) diff --git a/docs/cs_generate_images.md b/docs/cs_generate_images.md index 2897bacb..2d80537a 100644 --- a/docs/cs_generate_images.md +++ b/docs/cs_generate_images.md @@ -38,6 +38,7 @@ $ cs generate images -r yourRegistry -p customImagePrefix --branch string Branch of the repository to clone if the input file is not found (default "main") -f, --force Overwrite any files if existing -i, --input string CI profile to use as input for generation, relative to repository root (default "ci.yml") + -O, --org string Organization ID (relevant for some commands) -o, --output string Output path of the folder including generated artifacts, relative to repository root (default "export") --reporoot string root directory of the workspace repository to export. Will be used to clone the repository if it doesn't exist. (default "./workspace-repo") -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) diff --git a/docs/cs_generate_kubernetes.md b/docs/cs_generate_kubernetes.md index b09337d2..73417665 100644 --- a/docs/cs_generate_kubernetes.md +++ b/docs/cs_generate_kubernetes.md @@ -57,6 +57,7 @@ $ cs generate kubernetes -w 1234 -i ci.prod.yml --branch string Branch of the repository to clone if the input file is not found (default "main") -f, --force Overwrite any files if existing -i, --input string CI profile to use as input for generation, relative to repository root (default "ci.yml") + -O, --org string Organization ID (relevant for some commands) -o, --output string Output path of the folder including generated artifacts, relative to repository root (default "export") --reporoot string root directory of the workspace repository to export. Will be used to clone the repository if it doesn't exist. (default "./workspace-repo") -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) diff --git a/docs/cs_git.md b/docs/cs_git.md index 57232110..d6c86e98 100644 --- a/docs/cs_git.md +++ b/docs/cs_git.md @@ -19,6 +19,7 @@ like pulling or switching to a specific branch. ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_git_pull.md b/docs/cs_git_pull.md index e72c9035..d4090080 100644 --- a/docs/cs_git_pull.md +++ b/docs/cs_git_pull.md @@ -34,6 +34,7 @@ $ cs git pull --remote origin --branch staging ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_licenses.md b/docs/cs_licenses.md index e08a52cf..5fb0665b 100644 --- a/docs/cs_licenses.md +++ b/docs/cs_licenses.md @@ -20,6 +20,7 @@ cs licenses [flags] ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_list.md b/docs/cs_list.md index 26c1fbae..a03116bb 100644 --- a/docs/cs_list.md +++ b/docs/cs_list.md @@ -24,6 +24,7 @@ $ cs list workspaces ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_list_baseimages.md b/docs/cs_list_baseimages.md index 481c1923..fb09f359 100644 --- a/docs/cs_list_baseimages.md +++ b/docs/cs_list_baseimages.md @@ -27,6 +27,7 @@ $ cs list baseimages ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -o, --output string Output format (table, json, yaml) (default "table") -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output diff --git a/docs/cs_list_org.md b/docs/cs_list_org.md index 8e0faf88..5aff0836 100644 --- a/docs/cs_list_org.md +++ b/docs/cs_list_org.md @@ -27,6 +27,7 @@ $ cs list org ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -o, --output string Output format (table, json, yaml) (default "table") -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output diff --git a/docs/cs_list_plans.md b/docs/cs_list_plans.md index ae417914..0d6531f1 100644 --- a/docs/cs_list_plans.md +++ b/docs/cs_list_plans.md @@ -22,6 +22,7 @@ cs list plans [flags] ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -o, --output string Output format (table, json, yaml) (default "table") -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output diff --git a/docs/cs_list_teams.md b/docs/cs_list_teams.md index 22a716fc..183f4da6 100644 --- a/docs/cs_list_teams.md +++ b/docs/cs_list_teams.md @@ -27,6 +27,7 @@ $ cs list teams ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -o, --output string Output format (table, json, yaml) (default "table") -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output diff --git a/docs/cs_list_workspaces.md b/docs/cs_list_workspaces.md index 27ac0e64..37400bde 100644 --- a/docs/cs_list_workspaces.md +++ b/docs/cs_list_workspaces.md @@ -27,6 +27,7 @@ $ cs list workspaces -t ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -o, --output string Output format (table, json, yaml) (default "table") -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output diff --git a/docs/cs_log.md b/docs/cs_log.md index 723a0f9d..aee74d46 100644 --- a/docs/cs_log.md +++ b/docs/cs_log.md @@ -43,6 +43,7 @@ $ cs log -w 637128 -r workspace-213d7a8c-48b4-42e2-8f70-c905ab04abb5-58d657cdc5- ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_monitor.md b/docs/cs_monitor.md index 7eb96e1f..20cde957 100644 --- a/docs/cs_monitor.md +++ b/docs/cs_monitor.md @@ -54,6 +54,7 @@ $ cs monitor --forward --ca-cert-file ca.crt -- ./my-app --healthcheck https://l ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_open.md b/docs/cs_open.md index 5eb75540..71ff57d1 100644 --- a/docs/cs_open.md +++ b/docs/cs_open.md @@ -20,6 +20,7 @@ cs open [flags] ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_open_workspace.md b/docs/cs_open_workspace.md index d870d33d..f497fe95 100644 --- a/docs/cs_open_workspace.md +++ b/docs/cs_open_workspace.md @@ -30,6 +30,7 @@ $ cs open workspace ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_scale.md b/docs/cs_scale.md index 115570ea..4c9f6ed3 100644 --- a/docs/cs_scale.md +++ b/docs/cs_scale.md @@ -16,6 +16,7 @@ Scale Codesphere resources, like landscape services of a workspace. ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_scale_workspace.md b/docs/cs_scale_workspace.md index 6e464edc..bc7cc349 100644 --- a/docs/cs_scale_workspace.md +++ b/docs/cs_scale_workspace.md @@ -34,6 +34,7 @@ $ cs scale workspace --service api=0 ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_set-env.md b/docs/cs_set-env.md index f8ee408b..82d53467 100644 --- a/docs/cs_set-env.md +++ b/docs/cs_set-env.md @@ -31,6 +31,7 @@ $ cs set-env --workspace --env-var foo=bar --env-var hello=world ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_start.md b/docs/cs_start.md index e1c88e37..925556a0 100644 --- a/docs/cs_start.md +++ b/docs/cs_start.md @@ -16,6 +16,7 @@ Start pipeline of a workspace using the pipeline subcommand ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_start_pipeline.md b/docs/cs_start_pipeline.md index 454f620e..56651a5c 100644 --- a/docs/cs_start_pipeline.md +++ b/docs/cs_start_pipeline.md @@ -52,6 +52,7 @@ $ cs start pipeline -t 5m prepare ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_sync.md b/docs/cs_sync.md index 87745fb1..94161123 100644 --- a/docs/cs_sync.md +++ b/docs/cs_sync.md @@ -16,6 +16,7 @@ Synchronize Codesphere resources, like infrastructure required to run services. ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_sync_landscape.md b/docs/cs_sync_landscape.md index 6875dd00..c48e6c5c 100644 --- a/docs/cs_sync_landscape.md +++ b/docs/cs_sync_landscape.md @@ -21,6 +21,7 @@ cs sync landscape [flags] ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_update.md b/docs/cs_update.md index 73ce7946..ba62d1b9 100644 --- a/docs/cs_update.md +++ b/docs/cs_update.md @@ -20,6 +20,7 @@ cs update [flags] ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_version.md b/docs/cs_version.md index c54be562..5a4a39f3 100644 --- a/docs/cs_version.md +++ b/docs/cs_version.md @@ -20,6 +20,7 @@ cs version [flags] ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/docs/cs_wake-up.md b/docs/cs_wake-up.md index 05d0ea0e..275e3f02 100644 --- a/docs/cs_wake-up.md +++ b/docs/cs_wake-up.md @@ -42,6 +42,7 @@ $ cs wake-up -w 1234 --sync-landscape --profile prod ``` -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) -v, --verbose Verbose output -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) diff --git a/pkg/tmpl/NOTICE b/pkg/tmpl/NOTICE index 58474a56..9cbfcd66 100644 --- a/pkg/tmpl/NOTICE +++ b/pkg/tmpl/NOTICE @@ -159,6 +159,12 @@ Version: v1.2.0 License: BSD-3-Clause License URL: https://github.com/google/go-querystring/blob/v1.2.0/LICENSE +---------- +Module: github.com/google/uuid +Version: v1.6.0 +License: BSD-3-Clause +License URL: https://github.com/google/uuid/blob/v1.6.0/LICENSE + ---------- Module: github.com/hashicorp/go-cleanhttp Version: v0.5.2 From d8ee5a4d24457e08a540a873a9fc936b73c7a9ef Mon Sep 17 00:00:00 2001 From: Maximilian Date: Wed, 13 May 2026 22:01:32 +0200 Subject: [PATCH 07/12] feat(cli): added team add and delete opton with org context Signed-off-by: Maximilian --- api/team.go | 11 +-- api/types.go | 4 +- cli/cmd/client.go | 2 + cli/cmd/mocks.go | 131 ++++++++++++++++++++++++++++++++++ cli/cmd/root.go | 6 +- cli/cmd/team.go | 37 ++++++++++ cli/cmd/team_add_member.go | 29 ++++++++ cli/cmd/team_create.go | 59 +++++++++++++++ cli/cmd/team_remove.go | 57 +++++++++++++++ cli/cmd/team_remove_member.go | 30 ++++++++ 10 files changed, 356 insertions(+), 10 deletions(-) create mode 100644 cli/cmd/team.go create mode 100644 cli/cmd/team_add_member.go create mode 100644 cli/cmd/team_create.go create mode 100644 cli/cmd/team_remove.go create mode 100644 cli/cmd/team_remove_member.go diff --git a/api/team.go b/api/team.go index 0456d1aa..eab81cc7 100644 --- a/api/team.go +++ b/api/team.go @@ -48,7 +48,7 @@ func (c *Client) ListTeams(orgId string) ([]Team, error) { res := make([]Team, len(teams)) for i, t := range teams { - res[i] = ConvertOrgTeamToTeam(t, orgId) + res[i] = *ConvertOrgTeamToTeam(t, orgId) } return res, nil } @@ -62,17 +62,18 @@ func (c *Client) GetTeam(teamId int) (*Team, error) { return ConvertToTeam(team), cserrors.FormatAPIError(r, err) } -func (c *Client) CreateTeam(name string, dc int) (*Team, error) { +func (c *Client) CreateTeam(orgId string, name string, dc int) (*Team, error) { team, r, err := c.api.TeamsAPI.TeamsCreateTeam(c.ctx). TeamsCreateTeamRequest(openapi_client.TeamsCreateTeamRequest{ - Name: name, - Dc: dc, + Name: name, + Dc: dc, + OrganizationId: &orgId, }). Execute() return ConvertToTeam(team), cserrors.FormatAPIError(r, err) } -func (c *Client) DeleteTeam(teamId int) error { +func (c *Client) DeleteTeam(orgId string, teamId int) error { r, err := c.api.TeamsAPI.TeamsDeleteTeam(c.ctx, float32(teamId)).Execute() return cserrors.FormatAPIError(r, err) } diff --git a/api/types.go b/api/types.go index 3b425b9d..b6be6d7b 100644 --- a/api/types.go +++ b/api/types.go @@ -39,8 +39,8 @@ func ConvertToTeam(t *openapi.TeamsGetTeam200Response) *Team { } } -func ConvertOrgTeamToTeam(t openapi.OrganizationsListOrgTeams200ResponseInner, orgId string) Team { - return Team{ +func ConvertOrgTeamToTeam(t openapi.OrganizationsListOrgTeams200ResponseInner, orgId string) *Team { + return &Team{ Id: t.Id, DefaultDataCenterId: t.DefaultDataCenterId, Name: t.Name, diff --git a/cli/cmd/client.go b/cli/cmd/client.go index 472b868a..116b1487 100644 --- a/cli/cmd/client.go +++ b/cli/cmd/client.go @@ -34,6 +34,8 @@ type Client interface { GetPipelineState(wsId int, stage string) ([]api.PipelineStatus, error) GitPull(wsId int, remote string, branch string) error DeployLandscape(wsId int, profile string) error + CreateTeam(orgId string, name string, dcId int) (*api.Team, error) + DeleteTeam(orgId string, teamId int) error } // CommandExecutor abstracts command execution for testing diff --git a/cli/cmd/mocks.go b/cli/cmd/mocks.go index fbb450ec..fd7eff3f 100644 --- a/cli/cmd/mocks.go +++ b/cli/cmd/mocks.go @@ -39,6 +39,137 @@ func (_m *MockClient) EXPECT() *MockClient_Expecter { return &MockClient_Expecter{mock: &_m.Mock} } +// CreateTeam provides a mock function for the type MockClient +func (_mock *MockClient) CreateTeam(orgId string, name string, dcId int) (*api.Team, error) { + ret := _mock.Called(orgId, name, dcId) + + if len(ret) == 0 { + panic("no return value specified for CreateTeam") + } + + var r0 *api.Team + var r1 error + if returnFunc, ok := ret.Get(0).(func(string, string, int) (*api.Team, error)); ok { + return returnFunc(orgId, name, dcId) + } + if returnFunc, ok := ret.Get(0).(func(string, string, int) *api.Team); ok { + r0 = returnFunc(orgId, name, dcId) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*api.Team) + } + } + if returnFunc, ok := ret.Get(1).(func(string, string, int) error); ok { + r1 = returnFunc(orgId, name, dcId) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// MockClient_CreateTeam_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateTeam' +type MockClient_CreateTeam_Call struct { + *mock.Call +} + +// CreateTeam is a helper method to define mock.On call +// - orgId string +// - name string +// - dcId int +func (_e *MockClient_Expecter) CreateTeam(orgId interface{}, name interface{}, dcId interface{}) *MockClient_CreateTeam_Call { + return &MockClient_CreateTeam_Call{Call: _e.mock.On("CreateTeam", orgId, name, dcId)} +} + +func (_c *MockClient_CreateTeam_Call) Run(run func(orgId string, name string, dcId int)) *MockClient_CreateTeam_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 int + if args[2] != nil { + arg2 = args[2].(int) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *MockClient_CreateTeam_Call) Return(v *api.Team, err error) *MockClient_CreateTeam_Call { + _c.Call.Return(v, err) + return _c +} + +func (_c *MockClient_CreateTeam_Call) RunAndReturn(run func(orgId string, name string, dcId int) (*api.Team, error)) *MockClient_CreateTeam_Call { + _c.Call.Return(run) + return _c +} + +// DeleteTeam provides a mock function for the type MockClient +func (_mock *MockClient) DeleteTeam(orgId string, teamId int) error { + ret := _mock.Called(orgId, teamId) + + if len(ret) == 0 { + panic("no return value specified for DeleteTeam") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(string, int) error); ok { + r0 = returnFunc(orgId, teamId) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// MockClient_DeleteTeam_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteTeam' +type MockClient_DeleteTeam_Call struct { + *mock.Call +} + +// DeleteTeam is a helper method to define mock.On call +// - orgId string +// - teamId int +func (_e *MockClient_Expecter) DeleteTeam(orgId interface{}, teamId interface{}) *MockClient_DeleteTeam_Call { + return &MockClient_DeleteTeam_Call{Call: _e.mock.On("DeleteTeam", orgId, teamId)} +} + +func (_c *MockClient_DeleteTeam_Call) Run(run func(orgId string, teamId int)) *MockClient_DeleteTeam_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 int + if args[1] != nil { + arg1 = args[1].(int) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *MockClient_DeleteTeam_Call) Return(err error) *MockClient_DeleteTeam_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockClient_DeleteTeam_Call) RunAndReturn(run func(orgId string, teamId int) error) *MockClient_DeleteTeam_Call { + _c.Call.Return(run) + return _c +} + // DeleteWorkspace provides a mock function for the type MockClient func (_mock *MockClient) DeleteWorkspace(wsId int) error { ret := _mock.Called(wsId) diff --git a/cli/cmd/root.go b/cli/cmd/root.go index 097201a2..5e90c887 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -70,8 +70,8 @@ func (o GlobalOptions) GetOrgId() (string, error) { return o.OrgId, nil } orgId := o.Env.GetOrgId() - if orgId == "" { - return "", errors.New("organization ID not set, use -O or CS_ORG_ID to set it") + if o.OrgId == "" { + return o.OrgId, nil } _, err := uuid.Parse(orgId) @@ -127,7 +127,7 @@ func GetRootCmd() *cobra.Command { AddWakeUpCmd(rootCmd, &opts) AddCurlCmd(rootCmd, &opts) AddScaleCmd(rootCmd, &opts) - + AddTeamManageCmd(rootCmd, &opts) return rootCmd } diff --git a/cli/cmd/team.go b/cli/cmd/team.go new file mode 100644 index 00000000..822a53b6 --- /dev/null +++ b/cli/cmd/team.go @@ -0,0 +1,37 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +type TeamManageCmd struct { + cmd *cobra.Command +} + +func AddTeamManageCmd(rootCmd *cobra.Command, opts *GlobalOptions) { + t := TeamManageCmd{ + cmd: &cobra.Command{ + Use: "team", + Short: "Manage Team", + Long: `Manage Team Resources like Members or Roles in Teams`, + }, + } + + AddCmd(rootCmd, t.cmd) + AddMemberCmd(t.cmd, opts) + AddCreateTeamCmd(t.cmd, opts) + AddRemoveTeamCmd(t.cmd, opts) +} + +func AddMemberCmd(t *cobra.Command, opts *GlobalOptions) { + + memberCmd := &cobra.Command{ + Use: "member", + Short: "Manage team members", + } + + AddAddTeamMemberCmd(memberCmd, opts) + AddRemoveTeamMemberCmd(memberCmd, opts) + + t.AddCommand(memberCmd) +} diff --git a/cli/cmd/team_add_member.go b/cli/cmd/team_add_member.go new file mode 100644 index 00000000..82f5b776 --- /dev/null +++ b/cli/cmd/team_add_member.go @@ -0,0 +1,29 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +type AddTeamMemberCmd struct { + cmd *cobra.Command + Opts CreateWorkspaceOpts +} + +func AddAddTeamMemberCmd(team *cobra.Command, opts *GlobalOptions) { + t := AddTeamMemberCmd{ + cmd: &cobra.Command{ + Use: "add", + Short: "Add team member", + Long: `Add team member to a team`, + }, + Opts: CreateWorkspaceOpts{ + GlobalOptions: opts, + }, + } + t.cmd.RunE = t.RunE + AddCmd(team, t.cmd) +} + +func (c *AddTeamMemberCmd) RunE(_ *cobra.Command, args []string) error { + return nil +} diff --git a/cli/cmd/team_create.go b/cli/cmd/team_create.go new file mode 100644 index 00000000..d7b07f33 --- /dev/null +++ b/cli/cmd/team_create.go @@ -0,0 +1,59 @@ +package cmd + +import ( + "errors" + "fmt" + "github.com/spf13/cobra" +) + +type CreateTeamCmd struct { + cmd *cobra.Command + Opts CreateTeamOpts +} + +type CreateTeamOpts struct { + *GlobalOptions + name string + dcId int + orgId string +} + +func AddCreateTeamCmd(team *cobra.Command, opts *GlobalOptions) { + t := CreateTeamCmd{ + cmd: &cobra.Command{ + Use: "create", + Short: "Create team", + Long: `Create a team in Codesphere or an Organization`, + }, + Opts: CreateTeamOpts{ + GlobalOptions: opts, + }, + } + t.cmd.RunE = t.RunE + t.cmd.Flags().StringVarP(&t.Opts.name, "name", "n", "", "Team name") + t.cmd.Flags().IntVarP(&t.Opts.dcId, "dc-id", "d", 0, "Data center ID") + AddCmd(team, t.cmd) +} + +func (c *CreateTeamCmd) RunE(_ *cobra.Command, args []string) error { + client, err := NewClient(*c.Opts.GlobalOptions) + if err != nil { + return fmt.Errorf("failed to create Codesphere client: %w", err) + } + + orgId, err := c.Opts.GetOrgId() + if err != nil { + return errors.New("organization ID not set, use -O or CS_ORG_ID to set it") + } + + teamName := c.Opts.name + dcId := c.Opts.dcId + + createdTeam, err := client.CreateTeam(orgId, teamName, dcId) + if err != nil { + return fmt.Errorf("failed to create team: %w", err) + } + + fmt.Printf("Team created: %+v in Organization: %+v\n", createdTeam.Id, orgId) + return nil +} diff --git a/cli/cmd/team_remove.go b/cli/cmd/team_remove.go new file mode 100644 index 00000000..3a69e2ba --- /dev/null +++ b/cli/cmd/team_remove.go @@ -0,0 +1,57 @@ +package cmd + +import ( + "errors" + "github.com/spf13/cobra" +) + +type RemoveTeamCmd struct { + cmd *cobra.Command + Opts RemoveTeamOpts +} + +type RemoveTeamOpts struct { + *GlobalOptions + name string +} + +func AddRemoveTeamCmd(team *cobra.Command, opts *GlobalOptions) { + t := RemoveTeamCmd{ + cmd: &cobra.Command{ + Use: "remove", + Short: "Remove team", + Long: `Remove a team from Codesphere or an Organization`, + }, + Opts: RemoveTeamOpts{ + GlobalOptions: opts, + }, + } + t.cmd.RunE = t.RunE + t.cmd.Flags().StringVarP(&t.Opts.name, "name", "n", "", "Team name") + + AddCmd(team, t.cmd) +} + +func (c *RemoveTeamCmd) RunE(_ *cobra.Command, args []string) error { + // TODO: Implement team removal logic + client, err := NewClient(*c.Opts.GlobalOptions) + if err != nil { + return err + } + + orgId, err := c.Opts.GetOrgId() + if err != nil { + return err + } + + teamId, err := c.Opts.GetTeamId() + if err != nil { + return errors.New("team ID not set, use -T or CS_TEAM_ID to set it") + } + + // + + client.DeleteTeam(orgId, teamId) + return nil + +} diff --git a/cli/cmd/team_remove_member.go b/cli/cmd/team_remove_member.go new file mode 100644 index 00000000..34232db4 --- /dev/null +++ b/cli/cmd/team_remove_member.go @@ -0,0 +1,30 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +type RemoveTeamMemberCmd struct { + cmd *cobra.Command + Opts CreateWorkspaceOpts +} + +func AddRemoveTeamMemberCmd(team *cobra.Command, opts *GlobalOptions) { + res := RemoveTeamMemberCmd{ + cmd: &cobra.Command{ + Use: "remove", + Short: "Remove team member", + Long: `Remove team member from a team`, + }, + Opts: CreateWorkspaceOpts{ + GlobalOptions: opts, + }, + } + res.cmd.RunE = res.RunE + AddCmd(team, res.cmd) +} + +func (c *RemoveTeamMemberCmd) RunE(_ *cobra.Command, args []string) error { + // TODO: Implement team member removal logic + return nil +} From 935df9737942f9220bb67603c199fdb6f7c87747 Mon Sep 17 00:00:00 2001 From: DerBurri <7892993+DerBurri@users.noreply.github.com> Date: Wed, 13 May 2026 20:03:52 +0000 Subject: [PATCH 08/12] chore(docs): Auto-update docs and licenses Signed-off-by: DerBurri <7892993+DerBurri@users.noreply.github.com> --- cli/cmd/team.go | 3 +++ cli/cmd/team_add_member.go | 3 +++ cli/cmd/team_create.go | 3 +++ cli/cmd/team_remove.go | 3 +++ cli/cmd/team_remove_member.go | 3 +++ docs/README.md | 1 + docs/cs.md | 1 + docs/cs_team.md | 31 +++++++++++++++++++++++++++++++ docs/cs_team_create.md | 34 ++++++++++++++++++++++++++++++++++ docs/cs_team_member.md | 26 ++++++++++++++++++++++++++ docs/cs_team_member_add.md | 32 ++++++++++++++++++++++++++++++++ docs/cs_team_member_remove.md | 32 ++++++++++++++++++++++++++++++++ docs/cs_team_remove.md | 33 +++++++++++++++++++++++++++++++++ 13 files changed, 205 insertions(+) create mode 100644 docs/cs_team.md create mode 100644 docs/cs_team_create.md create mode 100644 docs/cs_team_member.md create mode 100644 docs/cs_team_member_add.md create mode 100644 docs/cs_team_member_remove.md create mode 100644 docs/cs_team_remove.md diff --git a/cli/cmd/team.go b/cli/cmd/team.go index 822a53b6..d6d0c951 100644 --- a/cli/cmd/team.go +++ b/cli/cmd/team.go @@ -1,3 +1,6 @@ +// Copyright (c) Codesphere Inc. +// SPDX-License-Identifier: Apache-2.0 + package cmd import ( diff --git a/cli/cmd/team_add_member.go b/cli/cmd/team_add_member.go index 82f5b776..9dd56d0b 100644 --- a/cli/cmd/team_add_member.go +++ b/cli/cmd/team_add_member.go @@ -1,3 +1,6 @@ +// Copyright (c) Codesphere Inc. +// SPDX-License-Identifier: Apache-2.0 + package cmd import ( diff --git a/cli/cmd/team_create.go b/cli/cmd/team_create.go index d7b07f33..ae4178f5 100644 --- a/cli/cmd/team_create.go +++ b/cli/cmd/team_create.go @@ -1,3 +1,6 @@ +// Copyright (c) Codesphere Inc. +// SPDX-License-Identifier: Apache-2.0 + package cmd import ( diff --git a/cli/cmd/team_remove.go b/cli/cmd/team_remove.go index 3a69e2ba..4f10716b 100644 --- a/cli/cmd/team_remove.go +++ b/cli/cmd/team_remove.go @@ -1,3 +1,6 @@ +// Copyright (c) Codesphere Inc. +// SPDX-License-Identifier: Apache-2.0 + package cmd import ( diff --git a/cli/cmd/team_remove_member.go b/cli/cmd/team_remove_member.go index 34232db4..fe9202ae 100644 --- a/cli/cmd/team_remove_member.go +++ b/cli/cmd/team_remove_member.go @@ -1,3 +1,6 @@ +// Copyright (c) Codesphere Inc. +// SPDX-License-Identifier: Apache-2.0 + package cmd import ( diff --git a/docs/README.md b/docs/README.md index 646937af..c40e374a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -34,6 +34,7 @@ Manage and debug resources deployed in Codesphere via command line. * [cs set-env](cs_set-env.md) - Set environment variables * [cs start](cs_start.md) - Start workspace pipeline * [cs sync](cs_sync.md) - Sync Codesphere resources +* [cs team](cs_team.md) - Manage Team * [cs update](cs_update.md) - Update Codesphere CLI * [cs version](cs_version.md) - Print version * [cs wake-up](cs_wake-up.md) - Wake up an on-demand workspace diff --git a/docs/cs.md b/docs/cs.md index 646937af..c40e374a 100644 --- a/docs/cs.md +++ b/docs/cs.md @@ -34,6 +34,7 @@ Manage and debug resources deployed in Codesphere via command line. * [cs set-env](cs_set-env.md) - Set environment variables * [cs start](cs_start.md) - Start workspace pipeline * [cs sync](cs_sync.md) - Sync Codesphere resources +* [cs team](cs_team.md) - Manage Team * [cs update](cs_update.md) - Update Codesphere CLI * [cs version](cs_version.md) - Print version * [cs wake-up](cs_wake-up.md) - Wake up an on-demand workspace diff --git a/docs/cs_team.md b/docs/cs_team.md new file mode 100644 index 00000000..a4bfa1ac --- /dev/null +++ b/docs/cs_team.md @@ -0,0 +1,31 @@ +## cs team + +Manage Team + +### Synopsis + +Manage Team Resources like Members or Roles in Teams + +### Options + +``` + -h, --help help for team +``` + +### Options inherited from parent commands + +``` + -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) + -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) + -v, --verbose Verbose output + -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) +``` + +### SEE ALSO + +* [cs](cs.md) - The Codesphere CLI +* [cs team create](cs_team_create.md) - Create team +* [cs team member](cs_team_member.md) - Manage team members +* [cs team remove](cs_team_remove.md) - Remove team + diff --git a/docs/cs_team_create.md b/docs/cs_team_create.md new file mode 100644 index 00000000..9d36906d --- /dev/null +++ b/docs/cs_team_create.md @@ -0,0 +1,34 @@ +## cs team create + +Create team + +### Synopsis + +Create a team in Codesphere or an Organization + +``` +cs team create [flags] +``` + +### Options + +``` + -d, --dc-id int Data center ID + -h, --help help for create + -n, --name string Team name +``` + +### Options inherited from parent commands + +``` + -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) + -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) + -v, --verbose Verbose output + -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) +``` + +### SEE ALSO + +* [cs team](cs_team.md) - Manage Team + diff --git a/docs/cs_team_member.md b/docs/cs_team_member.md new file mode 100644 index 00000000..a5960a22 --- /dev/null +++ b/docs/cs_team_member.md @@ -0,0 +1,26 @@ +## cs team member + +Manage team members + +### Options + +``` + -h, --help help for member +``` + +### Options inherited from parent commands + +``` + -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) + -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) + -v, --verbose Verbose output + -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) +``` + +### SEE ALSO + +* [cs team](cs_team.md) - Manage Team +* [cs team member add](cs_team_member_add.md) - Add team member +* [cs team member remove](cs_team_member_remove.md) - Remove team member + diff --git a/docs/cs_team_member_add.md b/docs/cs_team_member_add.md new file mode 100644 index 00000000..0ffcf6bc --- /dev/null +++ b/docs/cs_team_member_add.md @@ -0,0 +1,32 @@ +## cs team member add + +Add team member + +### Synopsis + +Add team member to a team + +``` +cs team member add [flags] +``` + +### Options + +``` + -h, --help help for add +``` + +### Options inherited from parent commands + +``` + -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) + -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) + -v, --verbose Verbose output + -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) +``` + +### SEE ALSO + +* [cs team member](cs_team_member.md) - Manage team members + diff --git a/docs/cs_team_member_remove.md b/docs/cs_team_member_remove.md new file mode 100644 index 00000000..eedf67bb --- /dev/null +++ b/docs/cs_team_member_remove.md @@ -0,0 +1,32 @@ +## cs team member remove + +Remove team member + +### Synopsis + +Remove team member from a team + +``` +cs team member remove [flags] +``` + +### Options + +``` + -h, --help help for remove +``` + +### Options inherited from parent commands + +``` + -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) + -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) + -v, --verbose Verbose output + -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) +``` + +### SEE ALSO + +* [cs team member](cs_team_member.md) - Manage team members + diff --git a/docs/cs_team_remove.md b/docs/cs_team_remove.md new file mode 100644 index 00000000..11131b82 --- /dev/null +++ b/docs/cs_team_remove.md @@ -0,0 +1,33 @@ +## cs team remove + +Remove team + +### Synopsis + +Remove a team from Codesphere or an Organization + +``` +cs team remove [flags] +``` + +### Options + +``` + -h, --help help for remove + -n, --name string Team name +``` + +### Options inherited from parent commands + +``` + -a, --api string URL of Codesphere API (can also be CS_API) + -O, --org string Organization ID (relevant for some commands) + -t, --team int Team ID (relevant for some commands, can also be CS_TEAM_ID) (default -1) + -v, --verbose Verbose output + -w, --workspace int Workspace ID (relevant for some commands, can also be CS_WORKSPACE_ID) (default -1) +``` + +### SEE ALSO + +* [cs team](cs_team.md) - Manage Team + From f9fb7e3aa25b15326de21469796ff6e72f9ab42f Mon Sep 17 00:00:00 2001 From: Maximilian Date: Wed, 13 May 2026 22:10:48 +0200 Subject: [PATCH 09/12] chore(lint): removed unused orgId field in createTeamOpts --- cli/cmd/team_create.go | 5 ++--- cli/cmd/team_remove.go | 5 ++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/cli/cmd/team_create.go b/cli/cmd/team_create.go index ae4178f5..b5d2ad27 100644 --- a/cli/cmd/team_create.go +++ b/cli/cmd/team_create.go @@ -16,9 +16,8 @@ type CreateTeamCmd struct { type CreateTeamOpts struct { *GlobalOptions - name string - dcId int - orgId string + name string + dcId int } func AddCreateTeamCmd(team *cobra.Command, opts *GlobalOptions) { diff --git a/cli/cmd/team_remove.go b/cli/cmd/team_remove.go index 4f10716b..41dd2e4b 100644 --- a/cli/cmd/team_remove.go +++ b/cli/cmd/team_remove.go @@ -54,7 +54,10 @@ func (c *RemoveTeamCmd) RunE(_ *cobra.Command, args []string) error { // - client.DeleteTeam(orgId, teamId) + err = client.DeleteTeam(orgId, teamId) + if err != nil { + return err + } return nil } From 80e97ca2b02aa231d05ebd92288b3570ec728cea Mon Sep 17 00:00:00 2001 From: Maximilian Date: Wed, 20 May 2026 14:18:31 +0200 Subject: [PATCH 10/12] add logic seperation for teams and org teams --- api/team.go | 31 +++++++++++++++++++++++++++++-- cli/cmd/root.go | 13 +++++++------ cli/cmd/team_create.go | 38 +++++++++++++++++++++++++------------- 3 files changed, 61 insertions(+), 21 deletions(-) diff --git a/api/team.go b/api/team.go index eab81cc7..f94624df 100644 --- a/api/team.go +++ b/api/team.go @@ -59,10 +59,34 @@ func (c *Client) ListTeams(orgId string) ([]Team, error) { func (c *Client) GetTeam(teamId int) (*Team, error) { team, r, err := c.api.TeamsAPI.TeamsGetTeam(c.ctx, float32(teamId)).Execute() - return ConvertToTeam(team), cserrors.FormatAPIError(r, err) + if err != nil { + return nil, cserrors.FormatAPIError(r, err) + } + return ConvertToTeam(team), nil } func (c *Client) CreateTeam(orgId string, name string, dc int) (*Team, error) { + if orgId == "" { + return c.createTeam(name, dc) + } + return c.createOrgTeam(orgId, name, dc) + +} + +func (c *Client) createTeam(name string, dc int) (*Team, error) { + team, r, err := c.api.TeamsAPI.TeamsCreateTeam(c.ctx). + TeamsCreateTeamRequest(openapi_client.TeamsCreateTeamRequest{ + Name: name, + Dc: dc, + }). + Execute() + if err != nil { + return nil, cserrors.FormatAPIError(r, err) + } + return ConvertToTeam(team), nil +} + +func (c *Client) createOrgTeam(orgId string, name string, dc int) (*Team, error) { team, r, err := c.api.TeamsAPI.TeamsCreateTeam(c.ctx). TeamsCreateTeamRequest(openapi_client.TeamsCreateTeamRequest{ Name: name, @@ -70,7 +94,10 @@ func (c *Client) CreateTeam(orgId string, name string, dc int) (*Team, error) { OrganizationId: &orgId, }). Execute() - return ConvertToTeam(team), cserrors.FormatAPIError(r, err) + if err != nil { + return nil, cserrors.FormatAPIError(r, err) + } + return ConvertToTeam(team), nil } func (c *Client) DeleteTeam(orgId string, teamId int) error { diff --git a/cli/cmd/root.go b/cli/cmd/root.go index 5e90c887..d224a1cd 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -66,17 +66,18 @@ func (o GlobalOptions) GetWorkspaceId() (int, error) { } func (o GlobalOptions) GetOrgId() (string, error) { - if o.OrgId != "" { - return o.OrgId, nil + orgId := o.OrgId + if orgId == "" { + orgId = o.Env.GetOrgId() } - orgId := o.Env.GetOrgId() - if o.OrgId == "" { - return o.OrgId, nil + + if orgId == "" { + return "", nil } _, err := uuid.Parse(orgId) if err != nil { - return "", fmt.Errorf("invalid organization UUID format: %w", err) + return "", fmt.Errorf("invalid organization ID format: %w", err) } return orgId, nil diff --git a/cli/cmd/team_create.go b/cli/cmd/team_create.go index b5d2ad27..870fe8b4 100644 --- a/cli/cmd/team_create.go +++ b/cli/cmd/team_create.go @@ -6,18 +6,20 @@ package cmd import ( "errors" "fmt" + "github.com/codesphere-cloud/cs-go/api" "github.com/spf13/cobra" ) type CreateTeamCmd struct { - cmd *cobra.Command - Opts CreateTeamOpts + cmd *cobra.Command + Opts CreateTeamOpts + ClientFactory func(GlobalOptions) (Client, error) } type CreateTeamOpts struct { *GlobalOptions - name string - dcId int + Name string + DcId int } func AddCreateTeamCmd(team *cobra.Command, opts *GlobalOptions) { @@ -30,32 +32,42 @@ func AddCreateTeamCmd(team *cobra.Command, opts *GlobalOptions) { Opts: CreateTeamOpts{ GlobalOptions: opts, }, + ClientFactory: NewClient, } t.cmd.RunE = t.RunE - t.cmd.Flags().StringVarP(&t.Opts.name, "name", "n", "", "Team name") - t.cmd.Flags().IntVarP(&t.Opts.dcId, "dc-id", "d", 0, "Data center ID") + t.cmd.Flags().StringVarP(&t.Opts.Name, "name", "n", "", "Team name") + t.cmd.Flags().IntVarP(&t.Opts.DcId, "dc-id", "d", 0, "Data center ID") AddCmd(team, t.cmd) } func (c *CreateTeamCmd) RunE(_ *cobra.Command, args []string) error { - client, err := NewClient(*c.Opts.GlobalOptions) + client, err := c.ClientFactory(*c.Opts.GlobalOptions) if err != nil { return fmt.Errorf("failed to create Codesphere client: %w", err) } orgId, err := c.Opts.GetOrgId() if err != nil { - return errors.New("organization ID not set, use -O or CS_ORG_ID to set it") + return errors.Join(err, errors.New("failed to get organization ID")) } - teamName := c.Opts.name - dcId := c.Opts.dcId - - createdTeam, err := client.CreateTeam(orgId, teamName, dcId) + createdTeam, err := c.CreateTeam(client, orgId, c.Opts.Name, c.Opts.DcId) if err != nil { - return fmt.Errorf("failed to create team: %w", err) + return err } fmt.Printf("Team created: %+v in Organization: %+v\n", createdTeam.Id, orgId) return nil } + +func (c *CreateTeamCmd) CreateTeam(client Client, orgId string, teamName string, dcId int) (*api.Team, error) { + if teamName == "" { + return nil, errors.New("team name cannot be empty") + } + + createdTeam, err := client.CreateTeam(orgId, teamName, dcId) + if err != nil { + return nil, fmt.Errorf("failed to create team: %w", err) + } + return createdTeam, nil +} From c32befcfffc9b99b63864f969618a90869f97224 Mon Sep 17 00:00:00 2001 From: Maximilian Date: Wed, 20 May 2026 14:19:02 +0200 Subject: [PATCH 11/12] add unit tests for team creation --- cli/cmd/team_test.go | 142 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 cli/cmd/team_test.go diff --git a/cli/cmd/team_test.go b/cli/cmd/team_test.go new file mode 100644 index 00000000..cf6e05a9 --- /dev/null +++ b/cli/cmd/team_test.go @@ -0,0 +1,142 @@ +package cmd_test + +import ( + "fmt" + + "github.com/codesphere-cloud/cs-go/api" + "github.com/codesphere-cloud/cs-go/cli/cmd" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("CreateTeam", func() { + var ( + mockEnv *cmd.MockEnv + mockClient *cmd.MockClient + c *cmd.CreateTeamCmd + teamId int + orgId string + teamName string + dcId int + ) + + BeforeEach(func() { + mockClient = cmd.NewMockClient(GinkgoT()) + mockEnv = cmd.NewMockEnv(GinkgoT()) + teamId = 42 + orgId = "d90e5f82-445e-4397-a90e-74d55cd4be3c" + teamName = "test-team" + dcId = 1 // Default data center ID for testing + c = &cmd.CreateTeamCmd{ + Opts: cmd.CreateTeamOpts{ + GlobalOptions: &cmd.GlobalOptions{ + Env: mockEnv, + TeamId: teamId, + // OrgId is intentionally left empty here, will be set in BeforeEach for specific contexts + }, + Name: teamName, + DcId: dcId, + }, + ClientFactory: func(opts cmd.GlobalOptions) (cmd.Client, error) { + return mockClient, nil + }, + } + // Mock common environment calls needed for client creation + }) + + AfterEach(func() { + mockEnv.AssertExpectations(GinkgoT()) + mockClient.AssertExpectations(GinkgoT()) + }) + + Context("Validation", func() { + It("should fail if the team name is empty", func() { + team, err := c.CreateTeam(mockClient, orgId, "", dcId) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(Equal("team name cannot be empty")) + Expect(team).To(BeNil()) + }) + }) + + Context("RunE execution flow", func() { + It("should successfully create a team when organization ID is provided via environment", func() { + c.Opts.GlobalOptions.OrgId = "" // Ensure flag is empty + mockEnv.EXPECT().GetOrgId().Return(orgId).Once() + + expectedTeam := api.Team{ + Id: teamId, + Name: teamName, + OrganizationId: &orgId, + DefaultDataCenterId: dcId, + } + mockClient.EXPECT().CreateTeam(orgId, teamName, dcId).Return(&expectedTeam, nil).Once() + + err := c.RunE(nil, []string{}) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when creating a team with an organization ID", func() { + BeforeEach(func() { + c.Opts.GlobalOptions.OrgId = orgId // Set OrgId via GlobalOptions (flag equivalent) + }) + + It("should successfully create the team and return the correct object", func() { + expectedTeam := api.Team{ + Id: teamId, + Name: teamName, + OrganizationId: &orgId, + DefaultDataCenterId: dcId, + } + // Expect CreateTeam API call with the provided orgId + mockClient.EXPECT().CreateTeam(orgId, teamName, dcId).Return(&expectedTeam, nil).Once() + + team, err := c.CreateTeam(mockClient, orgId, teamName, dcId) + Expect(err).ToNot(HaveOccurred()) + Expect(team.Name).To(Equal(teamName)) + Expect(*team.OrganizationId).To(Equal(orgId)) + }) + It("should fail to create with no permission in this orgId", func() { + // Change the return values to (nil, error) to simulate an API failure + mockClient.EXPECT().CreateTeam(orgId, teamName, dcId).Return(nil, fmt.Errorf("permission denied")).Once() + + team, err := c.CreateTeam(mockClient, orgId, teamName, dcId) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to create team: permission denied")) + Expect(team).To(BeNil()) + }) + }) + + Context("when creating a team without an organization ID", func() { + BeforeEach(func() { + c.Opts.GlobalOptions.OrgId = "" // Ensure OrgId is empty from flag + }) + + It("should create the team without orgID ", func() { + expectedTeam := api.Team{ + Id: teamId, + Name: teamName, + DefaultDataCenterId: dcId, + } + mockClient.EXPECT().CreateTeam("", teamName, dcId).Return(&expectedTeam, nil).Once() + mockEnv.EXPECT().GetOrgId().Return("").Once() + + team, err := c.CreateTeam(mockClient, mockEnv.GetOrgId(), teamName, dcId) + Expect(err).ToNot(HaveOccurred()) + Expect(team.Name).To(Equal(teamName)) + }) + }) + + Context("when an invalid organization ID format is provided via flag", func() { + BeforeEach(func() { + c.Opts.GlobalOptions.OrgId = "invalid-uuid-format" // Set an invalid UUID in GlobalOptions + }) + + It("should return an error due to invalid organization ID format", func() { + // The error should occur before the API call to CreateTeam. + err := c.RunE(nil, []string{}) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("invalid organization ID format:")) + }) + }) +}) From 825f61a2bba1482b57bcc43b85cc89023f1f8963 Mon Sep 17 00:00:00 2001 From: DerBurri <7892993+DerBurri@users.noreply.github.com> Date: Wed, 20 May 2026 12:20:58 +0000 Subject: [PATCH 12/12] chore(docs): Auto-update docs and licenses Signed-off-by: DerBurri <7892993+DerBurri@users.noreply.github.com> --- cli/cmd/team_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cli/cmd/team_test.go b/cli/cmd/team_test.go index cf6e05a9..fed429c4 100644 --- a/cli/cmd/team_test.go +++ b/cli/cmd/team_test.go @@ -1,3 +1,6 @@ +// Copyright (c) Codesphere Inc. +// SPDX-License-Identifier: Apache-2.0 + package cmd_test import (