diff --git a/Dockerfile b/Dockerfile index bedb4262097879c2f2429853929755dd84e52b70..b3cd263df3bfaf8e3073a3165daa340abd5e5722 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # NOTE: USING THIS IMAGE UNTIL registry1 credentials are added to IL2 runners # Build the manager binary -FROM registry.il2.dso.mil/platform-one/devops/pipeline-templates/valkyrie/golang-builder-1.6:1.0 as builder +FROM registry.il2.dso.mil/platform-one/devops/pipeline-templates/pipeline-job/golang-builder-1.6:1.0 as builder WORKDIR /workspace # Copy the Go Modules manifests diff --git a/apis/gitlab/v1alpha1/group_types.go b/apis/gitlab/v1alpha1/group_types.go index 7700f96f32432d7b74183e2b18cfb05ec5e416ad..6b62c8a51dabe65fe122ebdcbf37c3e7adf39f89 100644 --- a/apis/gitlab/v1alpha1/group_types.go +++ b/apis/gitlab/v1alpha1/group_types.go @@ -22,6 +22,10 @@ import ( // GroupSpec defines the desired state of Group type GroupSpec struct { + // FullPath is the gitlab path for this Project + // +kubebuiler:validation:required + FullPath string `json:"path"` + // Name is the name of the Group and will be used as part of the URL in Gitlab // +kubebuilder:validation:required Name string `json:"name"` @@ -34,6 +38,10 @@ type GroupSpec struct { // information for logging into the GitlabCredentialsName string `json:"gitlabCredentialsName"` + // GroupSpecs are for the GitLab Subgroups managed by this Group. + // +kubebuilder:validation:Optional + SubGroups []GroupSpec `json:"subGroups:omitempty"` + // ProjectSpecs are for the GitLab projects managed by this Group. It's expected that Projects // will be managed at the group level rather than be adjusted themselves. // +kubebuilder:validation:Optional @@ -42,7 +50,6 @@ type GroupSpec struct { // GroupStatus defines the observed state of Group type GroupStatus struct { - GitlabID *int64 `json:"gitlabId"` CreatedTime metav1.Time `json:"createdTime"` LastUpdatedTime metav1.Time `json:"lastUpdatedTime"` State string `json:"state"` diff --git a/apis/gitlab/v1alpha1/group_types_test.go b/apis/gitlab/v1alpha1/group_types_test.go index bf3d636c9f28893f3d15427ba5ae66363981d675..af9ea676579d012f9b49401e32bd8607694e87f3 100644 --- a/apis/gitlab/v1alpha1/group_types_test.go +++ b/apis/gitlab/v1alpha1/group_types_test.go @@ -79,9 +79,7 @@ func initVarsGroup() testVarsGroup { Description: "testDescription2", } - id1 := int64(1) testVars.testObjectStatus1 = GroupStatus{ - GitlabID: &id1, CreatedTime: metav1.Time{ Time: time.Now(), }, @@ -90,9 +88,7 @@ func initVarsGroup() testVarsGroup { }, } - id2 := int64(2) testVars.testObjectStatus2 = GroupStatus{ - GitlabID: &id2, CreatedTime: metav1.Time{ Time: time.Now(), }, diff --git a/apis/gitlab/v1alpha1/project_types.go b/apis/gitlab/v1alpha1/project_types.go index af6abe31335252eb95f96f8a7624d4462de959ef..a13d4b85b69f655abc81440fd25fdc967c11dd53 100644 --- a/apis/gitlab/v1alpha1/project_types.go +++ b/apis/gitlab/v1alpha1/project_types.go @@ -24,15 +24,15 @@ import ( type ProjectSpec struct { // GroupID is the id of the GitLab Group id that owns this project // +kubebuilder:validation:required - GroupID int64 `json:"groupId"` + GroupID int `json:"groupId"` // Name is the name of this Project // +kubebuilder:validation:required Name string `json:"name"` - // Path is the gitlab path for this Project + // FullPath is the gitlab path for this Project // +kubebuiler:validation:required - Path string `json:"path"` + FullPath string `json:"path"` // ImpactLevel is the RMF Impact Level for this Project // +kubebuilder:validation:Enum=2;4;5;6 diff --git a/apis/gitlab/v1alpha1/zz_generated.deepcopy.go b/apis/gitlab/v1alpha1/zz_generated.deepcopy.go index fc6171901ba1cac9cf66fc07143a7e43254e7878..0b97a5607f1a60eabf4b78070237bfd50fb00979 100644 --- a/apis/gitlab/v1alpha1/zz_generated.deepcopy.go +++ b/apis/gitlab/v1alpha1/zz_generated.deepcopy.go @@ -177,6 +177,13 @@ func (in *GroupList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GroupSpec) DeepCopyInto(out *GroupSpec) { *out = *in + if in.SubGroups != nil { + in, out := &in.SubGroups, &out.SubGroups + *out = make([]GroupSpec, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } if in.ProjectSpecs != nil { in, out := &in.ProjectSpecs, &out.ProjectSpecs *out = make([]ProjectSpec, len(*in)) @@ -199,11 +206,6 @@ func (in *GroupSpec) DeepCopy() *GroupSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GroupStatus) DeepCopyInto(out *GroupStatus) { *out = *in - if in.GitlabID != nil { - in, out := &in.GitlabID, &out.GitlabID - *out = new(int64) - **out = **in - } in.CreatedTime.DeepCopyInto(&out.CreatedTime) in.LastUpdatedTime.DeepCopyInto(&out.LastUpdatedTime) } diff --git a/clients/gitlab/client.go b/clients/gitlab/client.go index 21374d626fd749ced042da8c2ca7c82210b380fd..9d76e9bdaabc96647e5e6bb24b1dca904d38098d 100644 --- a/clients/gitlab/client.go +++ b/clients/gitlab/client.go @@ -45,8 +45,31 @@ import ( const itemsPerPage = 50 -// Client - -type Client struct { +type Client interface { + GetUser(userID int) (*gogitlab.User, int, error) + GetUsers(search *string) ([]*gogitlab.User, error) + GetUserByUsername(username *string) (*gogitlab.User, int, error) + AddUser(createUserOptions *gogitlab.CreateUserOptions) (*gogitlab.User, int, error) + UpdateUser(userID int, modifyUserOptions *gogitlab.ModifyUserOptions) (*gogitlab.User, int, error) + DeleteUser(userID int, waitInterval int, waitCount int) (int, error) + DeleteUserByUsername(username string, waitInterval int, waitCount int) (int, error) + GetGroup(groupID int) (*gogitlab.Group, int, error) + GetGroupByFullPath(fullPath *string) (*gogitlab.Group, int, error) + GetGroups(search *string) ([]*gogitlab.Group, error) + AddGroup(createGroupOptions gogitlab.CreateGroupOptions) (*gogitlab.Group, int, error) + AddGroupMember(groupID *int, userID *int, accessLevel gogitlab.AccessLevelValue) (*gogitlab.GroupMember, int, error) + UpdateGroup(groupID int, updateGroupOptions *gogitlab.UpdateGroupOptions) (*gogitlab.Group, int, error) + DeleteGroup(groupID int, waitInterval int, waitCount int) (int, error) + GetProject(projectID int) (*gogitlab.Project, int, error) + GetProjectByFullPath(fullPath *string) (*gogitlab.Project, int, error) + GetProjects(search *string) ([]*gogitlab.Project, error) + AddProject(createProjectOptions gogitlab.CreateProjectOptions) (*gogitlab.Project, int, error) + UpdateProject(projectID int, editProjectOptions gogitlab.EditProjectOptions) (*gogitlab.Project, int, error) + DeleteProject(projectID int, waitInterval int, waitCount int) (int, error) +} + +// ClientImpl - +type ClientImpl struct { client *gogitlab.Client token string apiURL string @@ -63,28 +86,29 @@ func processComplete(logPrefix string, statusCode int) { } // NewClient - create new gitlab api client -func NewClient(apiURL string, token string, httpClient *http.Client) Client { +func NewClient(apiURL string, token string, httpClient *http.Client) (ClientImpl, error) { // apiUrl https://code.il2.dso.mil/api/v4 // token gitlab user access token // httpClient optional injection of http client object to be used by gitlab api var gitlabClient *gogitlab.Client + var err error if httpClient == nil { - gitlabClient, _ = gogitlab.NewClient(token, gogitlab.WithBaseURL(apiURL)) + gitlabClient, err = gogitlab.NewClient(token, gogitlab.WithBaseURL(apiURL)) } else { - gitlabClient, _ = gogitlab.NewClient(token, gogitlab.WithBaseURL(apiURL), gogitlab.WithHTTPClient(httpClient)) + gitlabClient, err = gogitlab.NewClient(token, gogitlab.WithBaseURL(apiURL), gogitlab.WithHTTPClient(httpClient)) } - rlog.Debug("Created new Client instance") - return Client{ + rlog.Debug("Created new ClientImpl instance") + return ClientImpl{ client: gitlabClient, token: token, apiURL: apiURL, - } + }, err } // GetUser - -func (r Client) GetUser(userID int) (*gogitlab.User, int, error) { +func (r ClientImpl) GetUser(userID int) (*gogitlab.User, int, error) { logPrefix := "GetUser" getCustomeAttributes := true @@ -104,7 +128,7 @@ func (r Client) GetUser(userID int) (*gogitlab.User, int, error) { } // GetUsers - -func (r Client) GetUsers(search *string) ([]*gogitlab.User, error) { +func (r ClientImpl) GetUsers(search *string) ([]*gogitlab.User, error) { logPrefix := "GetUsers" getCustomeAttributes := true @@ -150,7 +174,7 @@ func (r Client) GetUsers(search *string) ([]*gogitlab.User, error) { } // GetUserByUsername - -func (r Client) GetUserByUsername(username *string) (*gogitlab.User, int, error) { +func (r ClientImpl) GetUserByUsername(username *string) (*gogitlab.User, int, error) { logPrefix := "GetUserByUsername" getCustomeAttributes := true var opts = gogitlab.ListUsersOptions{ @@ -176,7 +200,7 @@ func (r Client) GetUserByUsername(username *string) (*gogitlab.User, int, error) } // AddUser - -func (r Client) AddUser(createUserOptions *gogitlab.CreateUserOptions) (*gogitlab.User, int, error) { +func (r ClientImpl) AddUser(createUserOptions *gogitlab.CreateUserOptions) (*gogitlab.User, int, error) { logPrefix := "AddUser" var opts = gogitlab.CreateUserOptions{ Username: createUserOptions.Username, @@ -197,7 +221,7 @@ func (r Client) AddUser(createUserOptions *gogitlab.CreateUserOptions) (*gogitla } // UpdateUser - Update existing user. Only allow update of specific values -func (r Client) UpdateUser(userID int, modifyUserOptions *gogitlab.ModifyUserOptions) (*gogitlab.User, int, error) { +func (r ClientImpl) UpdateUser(userID int, modifyUserOptions *gogitlab.ModifyUserOptions) (*gogitlab.User, int, error) { logPrefix := "UpdateUser" var opts = gogitlab.ModifyUserOptions{ @@ -217,7 +241,7 @@ func (r Client) UpdateUser(userID int, modifyUserOptions *gogitlab.ModifyUserOpt } // DeleteUser - -func (r Client) DeleteUser(userID int, waitInterval int, waitCount int) (int, error) { +func (r ClientImpl) DeleteUser(userID int, waitInterval int, waitCount int) (int, error) { // waiting will be skilled if waitCount is 0 // setting wait will use a loop to wait until resource has completed deletion logPrefix := "DeleteUser" @@ -264,7 +288,7 @@ func (r Client) DeleteUser(userID int, waitInterval int, waitCount int) (int, er } // DeleteUserByUsername - convenience method -func (r Client) DeleteUserByUsername(username string, waitInterval int, waitCount int) (int, error) { +func (r ClientImpl) DeleteUserByUsername(username string, waitInterval int, waitCount int) (int, error) { // waiting will be skilled if waitCount is 0 // setting wait will use a loop to wait until resource has completed deletion logPrefix := "DeleteUserByUsername" @@ -284,7 +308,7 @@ func (r Client) DeleteUserByUsername(username string, waitInterval int, waitCoun return statusCode, nil } - statusCode, err := r.DeleteUser(users[0].ID, waitInterval, waitCount) + statusCode, err := r.DeleteUser(users[0].ID, 0, 0) if err != nil { processError(logPrefix, err) @@ -296,7 +320,7 @@ func (r Client) DeleteUserByUsername(username string, waitInterval int, waitCoun } // GetGroup - -func (r Client) GetGroup(groupID int) (*gogitlab.Group, int, error) { +func (r ClientImpl) GetGroup(groupID int) (*gogitlab.Group, int, error) { logPrefix := "GetGroup" group, res, err := r.client.Groups.GetGroup(groupID) @@ -311,7 +335,7 @@ func (r Client) GetGroup(groupID int) (*gogitlab.Group, int, error) { } // GetGroupByFullPath - -func (r Client) GetGroupByFullPath(fullPath *string) (*gogitlab.Group, int, error) { +func (r ClientImpl) GetGroupByFullPath(fullPath *string) (*gogitlab.Group, int, error) { // slow. get all groups and check for exact match to fullPath logPrefix := "GetGroupByFullPath" @@ -364,7 +388,7 @@ func (r Client) GetGroupByFullPath(fullPath *string) (*gogitlab.Group, int, erro } // GetGroups - -func (r Client) GetGroups(search *string) ([]*gogitlab.Group, error) { +func (r ClientImpl) GetGroups(search *string) ([]*gogitlab.Group, error) { logPrefix := "GetGroups" listOptions := gogitlab.ListOptions{ @@ -411,7 +435,7 @@ func (r Client) GetGroups(search *string) ([]*gogitlab.Group, error) { } // AddGroup - -func (r Client) AddGroup(createGroupOptions gogitlab.CreateGroupOptions) (*gogitlab.Group, int, error) { +func (r ClientImpl) AddGroup(createGroupOptions gogitlab.CreateGroupOptions) (*gogitlab.Group, int, error) { // https://stackoverflow.com/questions/65081356/how-do-you-create-a-project-in-a-specific-group-via-gitlab-api // SubGroup will be created if a parentID is supplied logPrefix := "AddGroup" @@ -438,7 +462,7 @@ func (r Client) AddGroup(createGroupOptions gogitlab.CreateGroupOptions) (*gogit } // AddGroupMember - -func (r Client) AddGroupMember(groupID *int, userID *int, accessLevel gogitlab.AccessLevelValue) (*gogitlab.GroupMember, int, error) { +func (r ClientImpl) AddGroupMember(groupID *int, userID *int, accessLevel gogitlab.AccessLevelValue) (*gogitlab.GroupMember, int, error) { logPrefix := "AddGroupMember" var opts = gogitlab.AddGroupMemberOptions{ @@ -457,7 +481,7 @@ func (r Client) AddGroupMember(groupID *int, userID *int, accessLevel gogitlab.A } // UpdateGroup - -func (r Client) UpdateGroup(groupID int, updateGroupOptions *gogitlab.UpdateGroupOptions) (*gogitlab.Group, int, error) { +func (r ClientImpl) UpdateGroup(groupID int, updateGroupOptions *gogitlab.UpdateGroupOptions) (*gogitlab.Group, int, error) { logPrefix := "UpdateGroup" group, res, err := r.client.Groups.UpdateGroup(groupID, updateGroupOptions) @@ -472,7 +496,7 @@ func (r Client) UpdateGroup(groupID int, updateGroupOptions *gogitlab.UpdateGrou } // DeleteGroup - -func (r Client) DeleteGroup(groupID int, waitInterval int, waitCount int) (int, error) { +func (r ClientImpl) DeleteGroup(groupID int, waitInterval int, waitCount int) (int, error) { // waiting will be skilled if waitCount is 0 // setting wait will use a loop to wait until resource has completed deletion logPrefix := "DeleteGroup" @@ -513,7 +537,7 @@ func (r Client) DeleteGroup(groupID int, waitInterval int, waitCount int) (int, } // GetProject - -func (r Client) GetProject(projectID int) (*gogitlab.Project, int, error) { +func (r ClientImpl) GetProject(projectID int) (*gogitlab.Project, int, error) { logPrefix := "GetProject" opts := gogitlab.GetProjectOptions{} @@ -529,7 +553,7 @@ func (r Client) GetProject(projectID int) (*gogitlab.Project, int, error) { } // GetProjectByFullPath - -func (r Client) GetProjectByFullPath(fullPath *string) (*gogitlab.Project, int, error) { +func (r ClientImpl) GetProjectByFullPath(fullPath *string) (*gogitlab.Project, int, error) { // slow. get all groups and check for exact match to fullPath logPrefix := "GetProjectByFullPath" @@ -585,7 +609,7 @@ func (r Client) GetProjectByFullPath(fullPath *string) (*gogitlab.Project, int, } // GetProjects - -func (r Client) GetProjects(search *string) ([]*gogitlab.Project, error) { +func (r ClientImpl) GetProjects(search *string) ([]*gogitlab.Project, error) { logPrefix := "GetProjects" listOptions := gogitlab.ListOptions{ @@ -629,7 +653,7 @@ func (r Client) GetProjects(search *string) ([]*gogitlab.Project, error) { } // AddProject - -func (r Client) AddProject(createProjectOptions gogitlab.CreateProjectOptions) (*gogitlab.Project, int, error) { +func (r ClientImpl) AddProject(createProjectOptions gogitlab.CreateProjectOptions) (*gogitlab.Project, int, error) { logPrefix := "AddProject" // force visibility to private var visibility = gogitlab.PrivateVisibility @@ -656,7 +680,7 @@ func (r Client) AddProject(createProjectOptions gogitlab.CreateProjectOptions) ( } // UpdateProject - -func (r Client) UpdateProject(projectID int, editProjectOptions gogitlab.EditProjectOptions) (*gogitlab.Project, int, error) { +func (r ClientImpl) UpdateProject(projectID int, editProjectOptions gogitlab.EditProjectOptions) (*gogitlab.Project, int, error) { logPrefix := "UpdateProject" // copy customizable settings from argument, hard code other options as desired var opts = gogitlab.EditProjectOptions{ @@ -677,7 +701,7 @@ func (r Client) UpdateProject(projectID int, editProjectOptions gogitlab.EditPro } // DeleteProject - -func (r Client) DeleteProject(projectID int, waitInterval int, waitCount int) (int, error) { +func (r ClientImpl) DeleteProject(projectID int, waitInterval int, waitCount int) (int, error) { logPrefix := "DeleteProject" // waiting will be skipped if waitCount is 0 // setting wait will use a loop to wait until resource has completed deletion diff --git a/clients/gitlab/client_test.go b/clients/gitlab/client_test.go index ecde48da07c463d85689c67e398980c2197c1d65..2e2f11e0457620824825e419f2b6605e23eeee4f 100644 --- a/clients/gitlab/client_test.go +++ b/clients/gitlab/client_test.go @@ -27,19 +27,19 @@ func TestNewClient(t *testing.T) { wantBaseURL string }{ { - name: "New Client", + name: "New ClientImpl", args: args{testURL, testToken, nil}, wantBaseURL: testWantURL, }, { - name: "New Client with httpClient injection", + name: "New ClientImpl with httpClient injection", args: args{testURL, testToken, testHTTPClient}, wantBaseURL: testWantURL, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := NewClient(tt.args.apiURL, tt.args.token, tt.args.httpClient) + got, _ := NewClient(tt.args.apiURL, tt.args.token, tt.args.httpClient) t.Logf("baseUrl %s", got.client.BaseURL()) if got.client.BaseURL().String() != tt.wantBaseURL { t.Errorf("NewClient() = %v, want %v", got.client.BaseURL().String(), tt.wantBaseURL) @@ -67,7 +67,7 @@ func TestClient_GetUser(t *testing.T) { // test objects testAPIUrl := "https://test/api/v4/" testToken := "token" - // create a gitlab Client object, inject http client to allow for mocking using httpmock + // create a gitlab ClientImpl object, inject http client to allow for mocking using httpmock testGitlabClient, _ := gogitlab.NewClient(testToken, gogitlab.WithBaseURL(testAPIUrl), gogitlab.WithHTTPClient(testHTTPClient)) type fields struct { @@ -95,7 +95,7 @@ func TestClient_GetUser(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Client{ + r := ClientImpl{ client: tt.fields.client, token: tt.fields.token, apiURL: tt.fields.apiURL, @@ -103,14 +103,14 @@ func TestClient_GetUser(t *testing.T) { user, statusCode, err := r.GetUser(tt.args.userID) if (err != nil) != tt.wantErr { - t.Errorf("Client.GetUsers() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ClientImpl.GetUsers() error = %v, wantErr %v", err, tt.wantErr) return } t.Logf("user id %d, username %s statusCode: %d", user.ID, user.Username, statusCode) if !reflect.DeepEqual(user, tt.want) { - t.Errorf("Client.GetUsers() = %v, want %v", user, tt.want) + t.Errorf("ClientImpl.GetUsers() = %v, want %v", user, tt.want) } }) } @@ -184,7 +184,7 @@ func TestClient_GetUserByUsername(t *testing.T) { ) } - r := Client{ + r := ClientImpl{ client: tt.fields.client, token: tt.fields.token, apiURL: tt.fields.apiURL, @@ -233,7 +233,7 @@ func TestClient_GetUsers(t *testing.T) { testEmptySearch := "EMPTY" testAPIUrl := "https://test/api/v4/" testToken := "token" - // create a gitlab Client object, inject http client to allow for mocking using httpmock + // create a gitlab ClientImpl object, inject http client to allow for mocking using httpmock testGitlabClient, _ := gogitlab.NewClient(testToken, gogitlab.WithBaseURL(testAPIUrl), gogitlab.WithHTTPClient(testHTTPClient)) type fields struct { @@ -275,7 +275,7 @@ func TestClient_GetUsers(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Client{ + r := ClientImpl{ client: tt.fields.client, token: tt.fields.token, apiURL: tt.fields.apiURL, @@ -283,14 +283,14 @@ func TestClient_GetUsers(t *testing.T) { got, err := r.GetUsers(tt.args.search) if (err != nil) != tt.wantErr { - t.Errorf("Client.GetUsers() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ClientImpl.GetUsers() error = %v, wantErr %v", err, tt.wantErr) return } for _, user := range got { t.Logf("user id %d, username %s", user.ID, user.Username) } if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Client.GetUsers() = %v, want %v", got, tt.want) + t.Errorf("ClientImpl.GetUsers() = %v, want %v", got, tt.want) } }) } @@ -315,7 +315,7 @@ func TestClient_AddUser(t *testing.T) { // test objects testAPIUrl := "https://test/api/v4/" testToken := "token" - // create a gitlab Client object, inject http client to allow for mocking using httpmock + // create a gitlab ClientImpl object, inject http client to allow for mocking using httpmock testGitlabClient, _ := gogitlab.NewClient(testToken, gogitlab.WithBaseURL(testAPIUrl), gogitlab.WithHTTPClient(testHTTPClient)) type fields struct { @@ -344,21 +344,21 @@ func TestClient_AddUser(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Client{ + r := ClientImpl{ client: tt.fields.client, token: tt.fields.token, apiURL: tt.fields.apiURL, } got, _, err := r.AddUser(tt.args.createUserOptions) if (err != nil) != tt.wantErr { - t.Errorf("Client.AddUser() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ClientImpl.AddUser() error = %v, wantErr %v", err, tt.wantErr) return } if got.ID != tt.want.ID { - t.Errorf("Client.AddUser() got = %d, want %d", got.ID, tt.want.ID) + t.Errorf("ClientImpl.AddUser() got = %d, want %d", got.ID, tt.want.ID) return } - t.Logf("Client.AddUser() got = %d, want %d", got.ID, tt.want.ID) + t.Logf("ClientImpl.AddUser() got = %d, want %d", got.ID, tt.want.ID) }) } } @@ -379,7 +379,7 @@ func TestClient_UpdateUser(t *testing.T) { // test objects testAPIUrl := "https://test/api/v4/" testToken := "token" - // create a gitlab Client object, inject http client to allow for mocking using httpmock + // create a gitlab ClientImpl object, inject http client to allow for mocking using httpmock testGitlabClient, _ := gogitlab.NewClient(testToken, gogitlab.WithBaseURL(testAPIUrl), gogitlab.WithHTTPClient(testHTTPClient)) updatedName := "Updated Name" @@ -410,21 +410,21 @@ func TestClient_UpdateUser(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Client{ + r := ClientImpl{ client: tt.fields.client, token: tt.fields.token, apiURL: tt.fields.apiURL, } got, _, err := r.UpdateUser(tt.args.user.ID, &tt.args.modifyUserOptions) if (err != nil) != tt.wantErr { - t.Errorf("Client.UpdateUser() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ClientImpl.UpdateUser() error = %v, wantErr %v", err, tt.wantErr) return } if got.ID != tt.want.ID { - t.Errorf("Client.UpdateUser() got = %d, want %d", got.ID, tt.want.ID) + t.Errorf("ClientImpl.UpdateUser() got = %d, want %d", got.ID, tt.want.ID) return } - t.Logf("Client.UpdateUser() got = %d, want %d", got.ID, tt.want.ID) + t.Logf("ClientImpl.UpdateUser() got = %d, want %d", got.ID, tt.want.ID) }) } } @@ -463,7 +463,7 @@ func TestClient_DeleteUser(t *testing.T) { // test objects testAPIUrl := "https://test/api/v4/" testToken := "token" - // create a gitlab Client object, inject http client to allow for mocking using httpmock + // create a gitlab ClientImpl object, inject http client to allow for mocking using httpmock testGitlabClient, _ := gogitlab.NewClient(testToken, gogitlab.WithBaseURL(testAPIUrl), gogitlab.WithHTTPClient(testHTTPClient)) type fields struct { @@ -500,21 +500,21 @@ func TestClient_DeleteUser(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Client{ + r := ClientImpl{ client: tt.fields.client, token: tt.fields.token, apiURL: tt.fields.apiURL, } got, err := r.DeleteUser(tt.args.userID, tt.args.waitInterval, tt.args.waitCount) if (err != nil) != tt.wantErr { - t.Errorf("Client.DeleteUser() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ClientImpl.DeleteUser() error = %v, wantErr %v", err, tt.wantErr) return } if got != tt.want { - t.Errorf("Client.DeleteUser() = %v, want %v", got, tt.want) + t.Errorf("ClientImpl.DeleteUser() = %v, want %v", got, tt.want) return } - t.Logf("Client.DeleteUser() statusCode = %d ", got) + t.Logf("ClientImpl.DeleteUser() statusCode = %d ", got) }) } } @@ -542,7 +542,7 @@ func TestClient_DeleteUserByUsername(t *testing.T) { testUsername := "testusername" testAPIUrl := "https://test/api/v4/" testToken := "token" - // create a gitlab Client object, inject http client to allow for mocking using httpmock + // create a gitlab ClientImpl object, inject http client to allow for mocking using httpmock testGitlabClient, _ := gogitlab.NewClient(testToken, gogitlab.WithBaseURL(testAPIUrl), gogitlab.WithHTTPClient(testHTTPClient)) type fields struct { @@ -595,21 +595,21 @@ func TestClient_DeleteUserByUsername(t *testing.T) { ) } t.Run(tt.name, func(t *testing.T) { - r := Client{ + r := ClientImpl{ client: tt.fields.client, token: tt.fields.token, apiURL: tt.fields.apiURL, } got, err := r.DeleteUserByUsername(tt.args.username, 1000, 10) if (err != nil) != tt.wantErr { - t.Errorf("Client.DeleteUserByUsername() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ClientImpl.DeleteUserByUsername() error = %v, wantErr %v", err, tt.wantErr) return } if got != tt.want { - t.Errorf("Client.DeleteUserByUsername() = %v, want %v", got, tt.want) + t.Errorf("ClientImpl.DeleteUserByUsername() = %v, want %v", got, tt.want) return } - t.Logf("Client.DeleteUserByUsername() statusCode = %d ", got) + t.Logf("ClientImpl.DeleteUserByUsername() statusCode = %d ", got) }) } } @@ -632,7 +632,7 @@ func TestClient_GetGroup(t *testing.T) { // test objects testAPIUrl := "https://test/api/v4/" testToken := "token" - // create a gitlab Client object, inject http client to allow for mocking using httpmock + // create a gitlab ClientImpl object, inject http client to allow for mocking using httpmock testGitlabClient, _ := gogitlab.NewClient(testToken, gogitlab.WithBaseURL(testAPIUrl), gogitlab.WithHTTPClient(testHTTPClient)) type fields struct { @@ -661,7 +661,7 @@ func TestClient_GetGroup(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Client{ + r := ClientImpl{ client: tt.fields.client, token: tt.fields.token, apiURL: tt.fields.apiURL, @@ -669,14 +669,14 @@ func TestClient_GetGroup(t *testing.T) { group, statusCode, err := r.GetGroup(tt.args.userID) if (err != nil) != tt.wantErr { - t.Errorf("Client.GetGroup() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ClientImpl.GetGroup() error = %v, wantErr %v", err, tt.wantErr) return } t.Logf("user id %d, username %s statusCode: %d", group.ID, group.FullName, statusCode) if !reflect.DeepEqual(group, tt.want) { - t.Errorf("Client.GetUsers() = %v, want %v", group, tt.want) + t.Errorf("ClientImpl.GetUsers() = %v, want %v", group, tt.want) } }) } @@ -736,7 +736,7 @@ func TestClient_GetGroupByFullPath(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Client{ + r := ClientImpl{ client: tt.fields.client, token: tt.fields.token, apiURL: tt.fields.apiURL, @@ -778,7 +778,7 @@ func TestClient_GetGroups(t *testing.T) { search := "searchstring" testAPIUrl := "https://test/api/v4/" testToken := "token" - // create a gitlab Client object, inject http client to allow for mocking using httpmock + // create a gitlab ClientImpl object, inject http client to allow for mocking using httpmock testGitlabClient, _ := gogitlab.NewClient(testToken, gogitlab.WithBaseURL(testAPIUrl), gogitlab.WithHTTPClient(testHTTPClient)) type fields struct { @@ -813,7 +813,7 @@ func TestClient_GetGroups(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Client{ + r := ClientImpl{ client: tt.fields.client, token: tt.fields.token, apiURL: tt.fields.apiURL, @@ -821,14 +821,14 @@ func TestClient_GetGroups(t *testing.T) { got, err := r.GetGroups(tt.args.search) if (err != nil) != tt.wantErr { - t.Errorf("Client.GetGroups() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ClientImpl.GetGroups() error = %v, wantErr %v", err, tt.wantErr) return } for _, group := range got { t.Logf("user id %d, groupname %s", group.ID, group.Name) } if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Client.GetGroups() = %v, want %v", got, tt.want) + t.Errorf("ClientImpl.GetGroups() = %v, want %v", got, tt.want) } }) } @@ -852,7 +852,7 @@ func TestClient_AddGroup(t *testing.T) { // test objects testAPIUrl := "https://test/api/v4/" testToken := "token" - // create a gitlab Client object, inject http client to allow for mocking using httpmock + // create a gitlab ClientImpl object, inject http client to allow for mocking using httpmock testGitlabClient, _ := gogitlab.NewClient(testToken, gogitlab.WithBaseURL(testAPIUrl), gogitlab.WithHTTPClient(testHTTPClient)) type fields struct { @@ -881,21 +881,21 @@ func TestClient_AddGroup(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Client{ + r := ClientImpl{ client: tt.fields.client, token: tt.fields.token, apiURL: tt.fields.apiURL, } got, _, err := r.AddGroup(tt.args.createGroupOptions) if (err != nil) != tt.wantErr { - t.Errorf("Client.AddGroup() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ClientImpl.AddGroup() error = %v, wantErr %v", err, tt.wantErr) return } if got.ID != tt.want.ID { - t.Errorf("Client.AddGroup() got = %d, want %d", got.ID, tt.want.ID) + t.Errorf("ClientImpl.AddGroup() got = %d, want %d", got.ID, tt.want.ID) return } - t.Logf("Client.AddGroup() got = %d %s, want %d %s", got.ID, got.Name, tt.want.ID, tt.want.Name) + t.Logf("ClientImpl.AddGroup() got = %d %s, want %d %s", got.ID, got.Name, tt.want.ID, tt.want.Name) }) } } @@ -954,7 +954,7 @@ func TestClient_AddGroupMember(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Client{ + r := ClientImpl{ client: tt.fields.client, token: tt.fields.token, apiURL: tt.fields.apiURL, @@ -1024,7 +1024,7 @@ func TestClient_UpdateGroup(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Client{ + r := ClientImpl{ client: tt.fields.client, token: tt.fields.token, apiURL: tt.fields.apiURL, @@ -1073,7 +1073,7 @@ func TestClient_DeleteGroup(t *testing.T) { testGroupID := 1 testAPIUrl := "https://test/api/v4/" testToken := "token" - // create a gitlab Client object, inject http client to allow for mocking using httpmock + // create a gitlab ClientImpl object, inject http client to allow for mocking using httpmock testGitlabClient, _ := gogitlab.NewClient(testToken, gogitlab.WithBaseURL(testAPIUrl), gogitlab.WithHTTPClient(testHTTPClient)) type fields struct { @@ -1110,21 +1110,21 @@ func TestClient_DeleteGroup(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Client{ + r := ClientImpl{ client: tt.fields.client, token: tt.fields.token, apiURL: tt.fields.apiURL, } got, err := r.DeleteGroup(tt.args.groupID, tt.args.waitInterval, tt.args.waitCount) if (err != nil) != tt.wantErr { - t.Errorf("Client.DeleteGroup() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ClientImpl.DeleteGroup() error = %v, wantErr %v", err, tt.wantErr) return } if got != tt.want { - t.Errorf("Client.ç() = %v, want %v", got, tt.want) + t.Errorf("ClientImpl.ç() = %v, want %v", got, tt.want) return } - t.Logf("Client.DeleteGroup() statusCode = %d ", got) + t.Logf("ClientImpl.DeleteGroup() statusCode = %d ", got) }) } } @@ -1149,7 +1149,7 @@ func TestClient_GetProject(t *testing.T) { // test objects testAPIUrl := "https://test/api/v4/" testToken := "token" - // create a gitlab Client object, inject http client to allow for mocking using httpmock + // create a gitlab ClientImpl object, inject http client to allow for mocking using httpmock testGitlabClient, _ := gogitlab.NewClient(testToken, gogitlab.WithBaseURL(testAPIUrl), gogitlab.WithHTTPClient(testHTTPClient)) type fields struct { @@ -1177,18 +1177,18 @@ func TestClient_GetProject(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Client{ + r := ClientImpl{ client: tt.fields.client, token: tt.fields.token, apiURL: tt.fields.apiURL, } got, _, err := r.GetProject(tt.args.projectID) if (err != nil) != tt.wantErr { - t.Errorf("Client.GetProject() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ClientImpl.GetProject() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Client.GetProject() = %v, want %v", got, tt.want) + t.Errorf("ClientImpl.GetProject() = %v, want %v", got, tt.want) } }) } @@ -1214,7 +1214,7 @@ func TestClient_GetProjects(t *testing.T) { // test objects testAPIUrl := "https://test/api/v4/" testToken := "token" - // create a gitlab Client object, inject http client to allow for mocking using httpmock + // create a gitlab ClientImpl object, inject http client to allow for mocking using httpmock testGitlabClient, _ := gogitlab.NewClient(testToken, gogitlab.WithBaseURL(testAPIUrl), gogitlab.WithHTTPClient(testHTTPClient)) // test objects @@ -1251,18 +1251,18 @@ func TestClient_GetProjects(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Client{ + r := ClientImpl{ client: tt.fields.client, token: tt.fields.token, apiURL: tt.fields.apiURL, } got, err := r.GetProjects(tt.args.search) if (err != nil) != tt.wantErr { - t.Errorf("Client.GetProjects() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ClientImpl.GetProjects() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Client.GetProjects() = %v, want %v", got, tt.want) + t.Errorf("ClientImpl.GetProjects() = %v, want %v", got, tt.want) } }) } @@ -1320,7 +1320,7 @@ func TestClient_GetProjectByFullPath(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Client{ + r := ClientImpl{ client: tt.fields.client, token: tt.fields.token, apiURL: tt.fields.apiURL, @@ -1361,7 +1361,7 @@ func TestClient_AddProject(t *testing.T) { // test objects testAPIUrl := "https://test/api/v4/" testToken := "token" - // create a gitlab Client object, inject http client to allow for mocking using httpmock + // create a gitlab ClientImpl object, inject http client to allow for mocking using httpmock testGitlabClient, _ := gogitlab.NewClient(testToken, gogitlab.WithBaseURL(testAPIUrl), gogitlab.WithHTTPClient(testHTTPClient)) type fields struct { @@ -1391,21 +1391,21 @@ func TestClient_AddProject(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Client{ + r := ClientImpl{ client: tt.fields.client, token: tt.fields.token, apiURL: tt.fields.apiURL, } got, got1, err := r.AddProject(*tt.args.createProjectOptions) if (err != nil) != tt.wantErr { - t.Errorf("Client.AddProject() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ClientImpl.AddProject() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Client.AddProject() got = %v, want %v", got, tt.want) + t.Errorf("ClientImpl.AddProject() got = %v, want %v", got, tt.want) } if got1 != tt.want1 { - t.Errorf("Client.AddProject() got1 = %v, want %v", got1, tt.want1) + t.Errorf("ClientImpl.AddProject() got1 = %v, want %v", got1, tt.want1) } }) } @@ -1463,7 +1463,7 @@ func TestClient_UpdateProject(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Client{ + r := ClientImpl{ client: tt.fields.client, token: tt.fields.token, apiURL: tt.fields.apiURL, @@ -1549,7 +1549,7 @@ func TestClient_DeleteProject(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Client{ + r := ClientImpl{ client: tt.fields.client, token: tt.fields.token, apiURL: tt.fields.apiURL, diff --git a/controllers/gitlab/gitlab_client.go b/controllers/gitlab/gitlab_client.go deleted file mode 100644 index 9db79bf5e8cd1ba4fa4fee4e99ec5c33053146cc..0000000000000000000000000000000000000000 --- a/controllers/gitlab/gitlab_client.go +++ /dev/null @@ -1,61 +0,0 @@ -package gitlab - -import gitlab "github.com/xanzy/go-gitlab" - -// Client is a facade for go-gitlab -type Client interface { - NewClient(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) - ListGroups(opt *gitlab.ListGroupsOptions, options ...gitlab.RequestOptionFunc) ([]*gitlab.Group, *gitlab.Response, error) - ListGroupsByName(name string) ([]*gitlab.Group, *gitlab.Response, error) - CreateGroup(name string, description string) (*gitlab.Group, *gitlab.Response, error) - UpdateGroup(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error) - GetGroup(groupID int64) (*gitlab.Group, *gitlab.Response, error) -} - -// ClientImpl is the Default implementation for the facade. -type ClientImpl struct { - client *gitlab.Client -} - -// NewClient is a facade for the go-gitlab client NewClient call -func (c ClientImpl) NewClient(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) { - client, err := gitlab.NewClient(token, options...) - c.client = client - return client, err -} - -// ListGroups is a facade for the go-gitlab client.Groups.ListGroups call. -func (c ClientImpl) ListGroups(opt *gitlab.ListGroupsOptions, options ...gitlab.RequestOptionFunc) ([]*gitlab.Group, *gitlab.Response, error) { - return c.client.Groups.ListGroups(opt, options...) -} - -// ListGroupsByName is a facade for the go-gitlab client.Groups.ListGroups call, with the group name as a search option. -func (c ClientImpl) ListGroupsByName(name string) ([]*gitlab.Group, *gitlab.Response, error) { - return c.client.Groups.ListGroups( - &gitlab.ListGroupsOptions{ - Search: &name, - }) -} - -// CreateGroup is a facade for the go-gitlab client.Groups.CreateGroup -func (c ClientImpl) CreateGroup(name string, description string) (*gitlab.Group, *gitlab.Response, error) { - opt := gitlab.CreateGroupOptions{ - Name: &name, - Description: &description, - } - return c.client.Groups.CreateGroup(&opt) -} - -// UpdateGroup is a facade for the go-gitlab client.Groups.UpdateGroup -func (c ClientImpl) UpdateGroup(id string, name string, descrption string) (*gitlab.Group, *gitlab.Response, error) { - opt := gitlab.UpdateGroupOptions{ - Name: &name, - Description: &descrption, - } - return c.client.Groups.UpdateGroup(id, &opt) -} - -// GetGroup is a facade for go-gitlab client.Groups.GetGroup -func (c ClientImpl) GetGroup(groupID int64) (*gitlab.Group, *gitlab.Response, error) { - return c.client.Groups.GetGroup(groupID) -} diff --git a/controllers/gitlab/group_controller.go b/controllers/gitlab/group_controller.go index 7cdb5a61dc5b537d1a8b3f26bc2357d0c8dcf8b2..441d1fefef9afd7790ca903450b0e25af4d20521 100644 --- a/controllers/gitlab/group_controller.go +++ b/controllers/gitlab/group_controller.go @@ -27,8 +27,10 @@ import ( "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + "strconv" "time" gitlabv1alpha1 "valkyrie.dso.mil/valkyrie-api/apis/gitlab/v1alpha1" + gitlabClient "valkyrie.dso.mil/valkyrie-api/clients/gitlab" ) // Errors @@ -63,7 +65,7 @@ type GroupReconciler struct { client.Client Log logr.Logger Scheme *runtime.Scheme - gitlabClient Client + gitlabClient gitlabClient.Client } //+kubebuilder:rbac:groups=gitlab.valkyrie.dso.mil,resources=groups,verbs=get;list;watch;create;update;patch;delete @@ -126,14 +128,19 @@ func (r *GroupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl var accessToken = string(secret.Data[gitlabCredentials.Spec.AccessTokenKey]) var err error - if _, err = r.gitlabClient.NewClient(accessToken, gitlab.WithBaseURL(gitlabCredentials.Spec.URL)); err != nil { - log.Error(err, errorUnableToCreateGitlabClient, "username", gitlabCredentials.Spec.Username, "url", gitlabCredentials.Spec.URL) - return ctrl.Result{Requeue: true}, err + + // We check for a nil client here so we can inject a mock for testing. + + if r.gitlabClient == nil { + if r.gitlabClient, err = gitlabClient.NewClient(accessToken, gitlabCredentials.Spec.URL, nil); err != nil { + log.Error(err, errorUnableToCreateGitlabClient, "username", gitlabCredentials.Spec.Username, "url", gitlabCredentials.Spec.URL) + return ctrl.Result{Requeue: true}, err + } } // See if the Group Exists var gitlabGroup *gitlab.Group - found, _, gitlabGroup, err := r.groupExists(group) + found, gitlabGroup, err := r.groupExists(group) if err != nil { log.Error(err, errorWhileSearchingGroups, "status") return ctrl.Result{Requeue: true}, err @@ -165,13 +172,12 @@ func (r *GroupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl return ctrl.Result{}, nil } -func (r *GroupReconciler) groupExists(group *gitlabv1alpha1.Group) (bool, *gitlab.Response, *gitlab.Group, error) { +func (r *GroupReconciler) groupExists(group *gitlabv1alpha1.Group) (bool, *gitlab.Group, error) { var grouplist []*gitlab.Group - var response *gitlab.Response var err error - if grouplist, response, err = r.gitlabClient.ListGroupsByName(group.Spec.Name); err != nil { - return false, response, nil, err + if grouplist, err = r.gitlabClient.GetGroups(&group.Spec.Name); err != nil { + return false, nil, err } // TODO: (jvb) For work beyond the MVP we'll need to handle pagination. May be superceeded by adam's client work. @@ -179,14 +185,17 @@ func (r *GroupReconciler) groupExists(group *gitlabv1alpha1.Group) (bool, *gitla for _, groupInList := range grouplist { found = group.Spec.Name == groupInList.Name if found { - return found, response, groupInList, nil + return found, groupInList, nil } } - return found, response, nil, nil + return found, nil, nil } -func (r *GroupReconciler) createGroup(group *gitlabv1alpha1.Group) (*gitlab.Group, *gitlab.Response, error) { - gitlabGroup, response, err := r.gitlabClient.CreateGroup(group.Spec.Name, group.Spec.Description) +func (r *GroupReconciler) createGroup(group *gitlabv1alpha1.Group) (*gitlab.Group, int, error) { + gitlabGroup, statusCode, err := r.gitlabClient.AddGroup(gitlab.CreateGroupOptions{ + Name: &group.Spec.Name, + Description: &group.Spec.Description, + }) if err == nil { group.Status.CreatedTime = metav1.Time{ @@ -197,11 +206,17 @@ func (r *GroupReconciler) createGroup(group *gitlabv1alpha1.Group) (*gitlab.Grou group.Status.State = GroupCreated } - return gitlabGroup, response, err + return gitlabGroup, statusCode, err } -func (r *GroupReconciler) updateGroup(group *gitlabv1alpha1.Group) (*gitlab.Group, *gitlab.Response, error) { - gitlabGroup, response, err := r.gitlabClient.UpdateGroup(group.ObjectMeta.Annotations["ID"], group.Spec.Name, group.Spec.Description) +func (r *GroupReconciler) updateGroup(group *gitlabv1alpha1.Group) (*gitlab.Group, int, error) { + id, _ := strconv.Atoi(group.ObjectMeta.Annotations["ID"]) + gitlabGroup, statusCode, err := r.gitlabClient.UpdateGroup(id, + &gitlab.UpdateGroupOptions{ + Name: &group.Spec.Name, + Description: &group.Spec.Description, + }, + ) if err == nil { group.Status.State = GroupOK @@ -210,7 +225,7 @@ func (r *GroupReconciler) updateGroup(group *gitlabv1alpha1.Group) (*gitlab.Grou } } - return gitlabGroup, response, err + return gitlabGroup, statusCode, err } func (r *GroupReconciler) processProjects(ctx context.Context, group *gitlabv1alpha1.Group, specs []gitlabv1alpha1.ProjectSpec) error { @@ -269,7 +284,7 @@ func (r *GroupReconciler) createProject(ctx context.Context, group *gitlabv1alph }, Spec: gitlabv1alpha1.ProjectSpec{ Name: spec.Name, - Path: spec.Path, + FullPath: spec.FullPath, ImpactLevel: spec.ImpactLevel, StorageTypes: spec.StorageTypes, VirtualService: spec.VirtualService, @@ -279,10 +294,10 @@ func (r *GroupReconciler) createProject(ctx context.Context, group *gitlabv1alph }) } -func (r *GroupReconciler) updateProject(ctx context.Context, groupID int64, spec gitlabv1alpha1.ProjectSpec, project *gitlabv1alpha1.Project) (*gitlabv1alpha1.Project, error) { +func (r *GroupReconciler) updateProject(ctx context.Context, groupID int, spec gitlabv1alpha1.ProjectSpec, project *gitlabv1alpha1.Project) (*gitlabv1alpha1.Project, error) { project.Spec.GroupID = groupID project.Spec.Name = spec.Name - project.Spec.Path = spec.Path + project.Spec.FullPath = spec.FullPath project.Spec.ImpactLevel = spec.ImpactLevel project.Spec.StorageTypes = spec.StorageTypes project.Spec.VirtualService = spec.VirtualService @@ -293,8 +308,6 @@ func (r *GroupReconciler) updateProject(ctx context.Context, groupID int64, spec func (r *GroupReconciler) updateStatus(ctx context.Context, id int, group *gitlabv1alpha1.Group) error { if id != 0 { - id64 := int64(id) - group.Status.GitlabID = &id64 group.Status.LastUpdatedTime = metav1.Time{ Time: time.Now(), } @@ -305,9 +318,6 @@ func (r *GroupReconciler) updateStatus(ctx context.Context, id int, group *gitla // SetupWithManager sets up the controller with the Manager. func (r *GroupReconciler) SetupWithManager(mgr ctrl.Manager) error { - // Setup a default GitlabClient implementation - r.gitlabClient = &ClientImpl{} - return ctrl.NewControllerManagedBy(mgr). For(&gitlabv1alpha1.Group{}). Owns(&gitlabv1alpha1.Project{}). diff --git a/controllers/gitlab/group_controller_test.go b/controllers/gitlab/group_controller_test.go index 84fdeb7355305ef6c57996654fa125495530bdb4..4f86fcebb1b1e0eccb2289c0009d4a471b9d3f14 100755 --- a/controllers/gitlab/group_controller_test.go +++ b/controllers/gitlab/group_controller_test.go @@ -8,7 +8,6 @@ import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "net/http" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" gitlabv1alpha1 "valkyrie.dso.mil/valkyrie-api/apis/gitlab/v1alpha1" @@ -166,94 +165,6 @@ var _ = Describe("Reconcile", func() { }) }) -var _ = Describe("Reconcile", func() { - builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{}) - scheme, _ := builder.Build() - When("logging in to GitLab", func() { - Context("can't create client", func() { - loggerMock := &MockLogger{ - WithValuesKeysAndValues: nil, - WithValuesCalled: false, - WithNameValue: "", - WithNameCalled: false, - } - contextMock := context.TODO() - clientMock := MockClient{statusWriter: &MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { - return nil - }}} - requestMock := ctrl.Request{} - sut := GroupReconciler{ - Client: &clientMock, - Log: loggerMock, - Scheme: scheme, - } - requestMock.NamespacedName = types.NamespacedName{ - Namespace: "default", - Name: "testGroup", - } - gitlabCred := gitlabv1alpha1.GitlabCredentials{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{}, - Spec: gitlabv1alpha1.GitlabCredentialsSpec{ - URL: "https://example.com", - Username: "ausername", - AccessToken: v1.SecretReference{ - Name: "asecret", - Namespace: "default", - }, - }, - Status: gitlabv1alpha1.GitlabCredentialsStatus{}, - } - group := gitlabv1alpha1.Group{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{}, - Spec: gitlabv1alpha1.GroupSpec{ - Name: "agroup", - GitlabCredentialsName: "gitlab-credentials", - ProjectSpecs: nil, - }, - Status: gitlabv1alpha1.GroupStatus{}, - } - secretNamespacedName := types.NamespacedName{ - Namespace: gitlabCred.Spec.AccessToken.Namespace, - Name: gitlabCred.Spec.AccessToken.Name, - } - stringData := map[string]string{"accessToken": "password"} - secret := v1.Secret{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{}, - StringData: stringData, - Type: "opaque", - } - clientMock.expectedObjects = make(map[client.ObjectKey]client.Object) - clientMock.expectedObjects[requestMock.NamespacedName] = &group - clientMock.expectedObjects[types.NamespacedName{ - Namespace: "default", - Name: group.Spec.GitlabCredentialsName, - }] = &gitlabCred - clientMock.expectedObjects[secretNamespacedName] = &secret - sut.gitlabClient = &MockGitlabClient{ - newClientFunction: func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) { - return nil, &MockError{ - message: "mocked error", - } - }, - } - result, err := sut.Reconcile(contextMock, requestMock) - It("Should log the failure", func() { - Expect(loggerMock.logLevelCalled).To(Equal("Error")) - Expect(loggerMock.loggedMessage).To(Equal(errorUnableToCreateGitlabClient)) - }) - It("Should return an error", func() { - Expect(err).ToNot(BeNil()) - }) - It("should requeue the group", func() { - Expect(result).To(Equal(ctrl.Result{Requeue: true})) - }) - }) - }) -}) - var _ = Describe("Reconcile", func() { builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{}) scheme, _ := builder.Build() @@ -323,33 +234,10 @@ var _ = Describe("Reconcile", func() { newClientFunction: func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) { return &gitlab.Client{}, nil }, - listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) { - return nil, &gitlab.Response{ - Response: &http.Response{ - Status: "", - StatusCode: 0, - Proto: "", - ProtoMajor: 0, - ProtoMinor: 0, - Header: nil, - Body: nil, - ContentLength: 0, - TransferEncoding: nil, - Close: false, - Uncompressed: false, - Trailer: nil, - Request: nil, - TLS: nil, - }, - TotalItems: 0, - TotalPages: 0, - ItemsPerPage: 0, - CurrentPage: 0, - NextPage: 0, - PreviousPage: 0, - }, &MockError{ - message: "Error", - } + getGroupsFunction: func(name *string) ([]*gitlab.Group, int, error) { + return nil, 500, &MockError{ + message: "Error", + } }, } result, err := sut.Reconcile(contextMock, requestMock) @@ -435,7 +323,7 @@ var _ = Describe("Reconcile", func() { newClientFunction: func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) { return &gitlab.Client{}, nil }, - listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) { + getGroupsFunction: func(name *string) ([]*gitlab.Group, int, error) { groups := []*gitlab.Group{&gitlab.Group{ ID: 0, Name: "", @@ -472,33 +360,10 @@ var _ = Describe("Reconcile", func() { MarkedForDeletionOn: nil, CreatedAt: nil, }} - return groups, &gitlab.Response{ - Response: &http.Response{ - Status: "", - StatusCode: 0, - Proto: "", - ProtoMajor: 0, - ProtoMinor: 0, - Header: nil, - Body: nil, - ContentLength: 0, - TransferEncoding: nil, - Close: false, - Uncompressed: false, - Trailer: nil, - Request: nil, - TLS: nil, - }, - TotalItems: 0, - TotalPages: 0, - ItemsPerPage: 0, - CurrentPage: 0, - NextPage: 0, - PreviousPage: 0, - }, nil + return groups, 200, nil }, - createGroupFunction: func(name string, description string) (*gitlab.Group, *gitlab.Response, error) { - return nil, &gitlab.Response{}, &MockError{ + addGroupFunction: func(options gitlab.CreateGroupOptions) (*gitlab.Group, int, error) { + return nil, 500, &MockError{ message: "Error", } }, @@ -586,35 +451,12 @@ var _ = Describe("Reconcile", func() { newClientFunction: func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) { return &gitlab.Client{}, nil }, - listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) { + getGroupsFunction: func(name *string) ([]*gitlab.Group, int, error) { groups := []*gitlab.Group{{Name: "agroup"}} - return groups, &gitlab.Response{ - Response: &http.Response{ - Status: "", - StatusCode: 0, - Proto: "", - ProtoMajor: 0, - ProtoMinor: 0, - Header: nil, - Body: nil, - ContentLength: 0, - TransferEncoding: nil, - Close: false, - Uncompressed: false, - Trailer: nil, - Request: nil, - TLS: nil, - }, - TotalItems: 0, - TotalPages: 0, - ItemsPerPage: 0, - CurrentPage: 0, - NextPage: 0, - PreviousPage: 0, - }, nil + return groups, 200, nil }, - updateGroupFunction: func(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error) { - return nil, &gitlab.Response{}, &MockError{ + updateGroupFunction: func(id int, options *gitlab.UpdateGroupOptions) (*gitlab.Group, int, error) { + return nil, 500, &MockError{ message: "Error", } }, @@ -706,35 +548,12 @@ var _ = Describe("Reconcile", func() { newClientFunction: func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) { return &gitlab.Client{}, nil }, - listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) { + getGroupsFunction: func(name *string) ([]*gitlab.Group, int, error) { groups := []*gitlab.Group{{Name: "agroup"}} - return groups, &gitlab.Response{ - Response: &http.Response{ - Status: "", - StatusCode: 0, - Proto: "", - ProtoMajor: 0, - ProtoMinor: 0, - Header: nil, - Body: nil, - ContentLength: 0, - TransferEncoding: nil, - Close: false, - Uncompressed: false, - Trailer: nil, - Request: nil, - TLS: nil, - }, - TotalItems: 0, - TotalPages: 0, - ItemsPerPage: 0, - CurrentPage: 0, - NextPage: 0, - PreviousPage: 0, - }, nil + return groups, 200, nil }, - updateGroupFunction: func(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error) { - return &gitlab.Group{Name: "agroup"}, &gitlab.Response{}, nil + updateGroupFunction: func(id int, options *gitlab.UpdateGroupOptions) (*gitlab.Group, int, error) { + return &gitlab.Group{Name: "agroup"}, 200, nil }, } result, err := sut.Reconcile(contextMock, requestMock) @@ -827,35 +646,12 @@ var _ = Describe("Reconcile", func() { newClientFunction: func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) { return &gitlab.Client{}, nil }, - listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) { + getGroupsFunction: func(name *string) ([]*gitlab.Group, int, error) { groups := []*gitlab.Group{{Name: "agroup"}} - return groups, &gitlab.Response{ - Response: &http.Response{ - Status: "", - StatusCode: 0, - Proto: "", - ProtoMajor: 0, - ProtoMinor: 0, - Header: nil, - Body: nil, - ContentLength: 0, - TransferEncoding: nil, - Close: false, - Uncompressed: false, - Trailer: nil, - Request: nil, - TLS: nil, - }, - TotalItems: 0, - TotalPages: 0, - ItemsPerPage: 0, - CurrentPage: 0, - NextPage: 0, - PreviousPage: 0, - }, nil + return groups, 200, nil }, - updateGroupFunction: func(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error) { - return &gitlab.Group{Name: "agroup"}, &gitlab.Response{}, nil + updateGroupFunction: func(id int, options *gitlab.UpdateGroupOptions) (*gitlab.Group, int, error) { + return &gitlab.Group{Name: "agroup"}, 200, nil }, } result, err := sut.Reconcile(contextMock, requestMock) @@ -876,20 +672,17 @@ var _ = Describe("groupExists", func() { When("the gitlab client fails", func() { sut := GroupReconciler{ gitlabClient: &MockGitlabClient{ - listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) { - return nil, &gitlab.Response{}, &MockError{ + getGroupsFunction: func(name *string) ([]*gitlab.Group, int, error) { + return nil, 500, &MockError{ message: "mockedError", } }, }, } - found, response, groups, err := sut.groupExists(&gitlabv1alpha1.Group{Spec: gitlabv1alpha1.GroupSpec{Name: "An error"}}) + found, groups, err := sut.groupExists(&gitlabv1alpha1.Group{Spec: gitlabv1alpha1.GroupSpec{Name: "An error"}}) It("should return that it didn't find the group", func() { Expect(found).To(Equal(false)) }) - It("should return the gitlab response", func() { - Expect(response).ToNot(BeNil()) - }) It("should return a nil group", func() { Expect(groups).To(BeNil()) }) @@ -902,19 +695,16 @@ var _ = Describe("groupExists", func() { returnGroups := []*gitlab.Group{group} sut := GroupReconciler{ gitlabClient: &MockGitlabClient{ - listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) { - return returnGroups, &gitlab.Response{}, nil + getGroupsFunction: func(name *string) ([]*gitlab.Group, int, error) { + return returnGroups, 500, nil }, }, } - found, response, returnedGroup, err := sut.groupExists(&gitlabv1alpha1.Group{Spec: gitlabv1alpha1.GroupSpec{Name: "A group"}}) + found, returnedGroup, err := sut.groupExists(&gitlabv1alpha1.Group{Spec: gitlabv1alpha1.GroupSpec{Name: "A group"}}) It("should return that it found the group", func() { Expect(found).To(Equal(true)) }) - It("should return the gitlab response", func() { - Expect(response).ToNot(BeNil()) - }) It("should return list with the group", func() { Expect(returnedGroup).To(Equal(group)) }) @@ -925,19 +715,16 @@ var _ = Describe("groupExists", func() { When("the group is not in the list", func() { sut := GroupReconciler{ gitlabClient: &MockGitlabClient{ - listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) { - return nil, &gitlab.Response{}, nil + getGroupsFunction: func(name *string) ([]*gitlab.Group, int, error) { + return nil, 404, nil }, }, } - found, response, groups, err := sut.groupExists(&gitlabv1alpha1.Group{Spec: gitlabv1alpha1.GroupSpec{Name: "A group"}}) + found, groups, err := sut.groupExists(&gitlabv1alpha1.Group{Spec: gitlabv1alpha1.GroupSpec{Name: "A group"}}) It("should return that it did not find the group", func() { Expect(found).To(Equal(false)) }) - It("should return the gitlab response", func() { - Expect(response).ToNot(BeNil()) - }) It("should return nil for the group list", func() { Expect(groups).To(BeNil()) }) @@ -949,23 +736,16 @@ var _ = Describe("groupExists", func() { var _ = Describe("createGroup", func() { expectedGroup := &gitlab.Group{ID: 1, Name: "A test group"} - expectedResponse := &gitlab.Response{ - Response: &http.Response{}, - TotalItems: 1, - TotalPages: 1, - ItemsPerPage: 10, - CurrentPage: 1, - NextPage: 0, - PreviousPage: 0, - } + expectedResponse := 200 + sut := GroupReconciler{ gitlabClient: &MockGitlabClient{ - createGroupFunction: func(name string, description string) (*gitlab.Group, *gitlab.Response, error) { + addGroupFunction: func(options gitlab.CreateGroupOptions) (*gitlab.Group, int, error) { return expectedGroup, expectedResponse, nil }, }, } - group, response, err := sut.createGroup( + group, statusCode, err := sut.createGroup( &gitlabv1alpha1.Group{ ObjectMeta: ctrl.ObjectMeta{Annotations: make(map[string]string)}, Spec: gitlabv1alpha1.GroupSpec{Name: "a group"}, @@ -973,8 +753,8 @@ var _ = Describe("createGroup", func() { It("should return the gitlab group created", func() { Expect(group).To(Equal(expectedGroup)) }) - It("should return the gitlab response", func() { - Expect(response).To(Equal(expectedResponse)) + It("should return the gitlab statusCode", func() { + Expect(statusCode).To(Equal(expectedResponse)) }) It("should return the error created by the call, or nil", func() { Expect(err).To(BeNil()) @@ -983,22 +763,14 @@ var _ = Describe("createGroup", func() { var _ = Describe("updateGroup", func() { expectedGroup := &gitlab.Group{ID: 2, Name: "A test group"} - expectedResponse := &gitlab.Response{ - Response: &http.Response{}, - TotalItems: 1, - TotalPages: 1, - ItemsPerPage: 10, - CurrentPage: 1, - NextPage: 0, - PreviousPage: 0, - } + expectedStatusCode := 200 sut := GroupReconciler{ gitlabClient: &MockGitlabClient{ - updateGroupFunction: func(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error) { - return expectedGroup, expectedResponse, nil + updateGroupFunction: func(id int, options *gitlab.UpdateGroupOptions) (*gitlab.Group, int, error) { + return expectedGroup, expectedStatusCode, nil }, - listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) { - return []*gitlab.Group{{Name: "a group"}}, &gitlab.Response{}, nil + getGroupsFunction: func(name *string) ([]*gitlab.Group, int, error) { + return []*gitlab.Group{{Name: "a group"}}, 200, nil }, }, } @@ -1007,7 +779,6 @@ var _ = Describe("updateGroup", func() { ObjectMeta: ctrl.ObjectMeta{Annotations: make(map[string]string)}, Spec: gitlabv1alpha1.GroupSpec{Name: "a group"}, Status: gitlabv1alpha1.GroupStatus{ - GitlabID: nil, CreatedTime: metav1.Time{}, LastUpdatedTime: metav1.Time{}, State: "", @@ -1016,8 +787,8 @@ var _ = Describe("updateGroup", func() { It("should return the gitlab group created", func() { Expect(group).To(Equal(expectedGroup)) }) - It("should return the gitlab response", func() { - Expect(response).To(Equal(expectedResponse)) + It("should return the gitlab status code", func() { + Expect(response).To(Equal(expectedStatusCode)) }) It("should return the error created by the call, or nil", func() { Expect(err).To(BeNil()) @@ -1045,9 +816,6 @@ var _ = Describe("SetupWithManager", func() { Log: &loggerMock, builder: builder, }) - It("should setup the default gitlab client", func() { - Expect(sut.gitlabClient).To(BeAssignableToTypeOf(&ClientImpl{})) - }) It("should return no error", func() { Expect(err).To(BeNil()) }) @@ -1072,16 +840,12 @@ var _ = Describe("updateStatus", func() { Scheme: scheme, } group := gitlabv1alpha1.Group{Status: gitlabv1alpha1.GroupStatus{ - GitlabID: nil, CreatedTime: metav1.Time{}, LastUpdatedTime: metav1.Time{}, State: "", }} sut.updateStatus(&MockContext{}, 1, &group) - It("should update the gitlab id", func() { - Expect(*group.Status.GitlabID).To(Equal(int64(1))) - }) It("should update the last updated time", func() { Expect(group.Status.LastUpdatedTime.Time).To(Not(BeNil())) }) @@ -1091,7 +855,7 @@ var _ = Describe("updateStatus", func() { var _ = Describe("updateProject", func() { spec := gitlabv1alpha1.ProjectSpec{ Name: "a project", - Path: "https://example.com.path", + FullPath: "https://example.com.path", ImpactLevel: "2", StorageTypes: nil, VirtualService: "default", @@ -1126,11 +890,11 @@ var _ = Describe("updateProject", func() { returnedProject, err := sut.updateProject(context.TODO(), 1, spec, &project) It("should update the project from the project specification", func() { - Expect(project.Spec.GroupID).To(Equal(int64(1))) + Expect(project.Spec.GroupID).To(Equal(1)) Expect(project.Spec.Name).To(Equal(spec.Name)) Expect(project.Spec.ServicePort).To(Equal(spec.ServicePort)) Expect(project.Spec.Language).To(Equal(spec.Language)) - Expect(project.Spec.Path).To(Equal(spec.Path)) + Expect(project.Spec.FullPath).To(Equal(spec.FullPath)) Expect(project.Spec.VirtualService).To(Equal(spec.VirtualService)) Expect(project.Spec.StorageTypes).To(Equal(spec.StorageTypes)) Expect(project.Spec.ImpactLevel).To(Equal(spec.ImpactLevel)) diff --git a/controllers/gitlab/mocks_test.go b/controllers/gitlab/mocks_test.go index 358bf605e70956ab9e91246212b5b764aeabed60..d0edb5837a0b7fac64db168ef9c11bfb03c909c5 100755 --- a/controllers/gitlab/mocks_test.go +++ b/controllers/gitlab/mocks_test.go @@ -413,43 +413,99 @@ func (m *MockError) Error() string { } type MockGitlabClient struct { - newClientFunction func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) - listGroupsFunction func(opt *gitlab.ListGroupsOptions, options ...gitlab.RequestOptionFunc) ([]*gitlab.Group, *gitlab.Response, error) - listGroupsByNameFunction func(name string) ([]*gitlab.Group, *gitlab.Response, error) - createGroupFunction func(name string, description string) (*gitlab.Group, *gitlab.Response, error) - updateGroupFunction func(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error) - getGroupFunction func(groupID int64) (*gitlab.Group, *gitlab.Response, error) - expectedGroups map[int64]*gitlab.Group + newClientFunction func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) + getGroupsFunction func(name *string) ([]*gitlab.Group, int, error) + addGroupFunction func(options gitlab.CreateGroupOptions) (*gitlab.Group, int, error) + updateGroupFunction func(id int, options *gitlab.UpdateGroupOptions) (*gitlab.Group, int, error) + getGroupFunction func(groupID int) (*gitlab.Group, int, error) + expectedGroups map[int]*gitlab.Group } -func (m *MockGitlabClient) GetGroup(groupID int64) (*gitlab.Group, *gitlab.Response, error) { - if m.getGroupFunction != nil { - return m.getGroupFunction(groupID) - } +func (m *MockGitlabClient) GetUser(userID int) (*gitlab.User, int, error) { + panic("implement me") +} - if m.expectedGroups == nil { - m.expectedGroups = make(map[int64]*gitlab.Group) - } +func (m *MockGitlabClient) GetUsers(search *string) ([]*gitlab.User, error) { + panic("implement me") +} + +func (m *MockGitlabClient) GetUserByUsername(username *string) (*gitlab.User, int, error) { + panic("implement me") +} + +func (m *MockGitlabClient) AddUser(createUserOptions *gitlab.CreateUserOptions) (*gitlab.User, int, error) { + panic("implement me") +} + +func (m *MockGitlabClient) UpdateUser(userID int, modifyUserOptions *gitlab.ModifyUserOptions) (*gitlab.User, int, error) { + panic("implement me") +} + +func (m *MockGitlabClient) DeleteUser(userID int, waitInterval int, waitCount int) (int, error) { + panic("implement me") +} + +func (m *MockGitlabClient) DeleteUserByUsername(username string, waitInterval int, waitCount int) (int, error) { + panic("implement me") +} + +func (m *MockGitlabClient) GetGroupByFullPath(fullPath *string) (*gitlab.Group, int, error) { + panic("implement me") +} - return m.expectedGroups[groupID], nil, nil +func (m *MockGitlabClient) GetGroups(search *string) ([]*gitlab.Group, error) { + groups, _, err := m.getGroupsFunction(search) + return groups, err } -func (m *MockGitlabClient) CreateGroup(name string, description string) (*gitlab.Group, *gitlab.Response, error) { - return m.createGroupFunction(name, description) +func (m *MockGitlabClient) AddGroupMember(groupID *int, userID *int, accessLevel gitlab.AccessLevelValue) (*gitlab.GroupMember, int, error) { + panic("implement me") +} + +func (m *MockGitlabClient) DeleteGroup(groupID int, waitInterval int, waitCount int) (int, error) { + panic("implement me") +} + +func (m *MockGitlabClient) GetProject(projectID int) (*gitlab.Project, int, error) { + panic("implement me") } -func (m *MockGitlabClient) UpdateGroup(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error) { - return m.updateGroupFunction(id, name, description) +func (m *MockGitlabClient) GetProjectByFullPath(fullPath *string) (*gitlab.Project, int, error) { + panic("implement me") +} + +func (m *MockGitlabClient) GetProjects(search *string) ([]*gitlab.Project, error) { + panic("implement me") +} + +func (m *MockGitlabClient) AddProject(createProjectOptions gitlab.CreateProjectOptions) (*gitlab.Project, int, error) { + panic("implement me") } -func (m *MockGitlabClient) ListGroupsByName(name string) ([]*gitlab.Group, *gitlab.Response, error) { - return m.listGroupsByNameFunction(name) +func (m *MockGitlabClient) UpdateProject(projectID int, editProjectOptions gitlab.EditProjectOptions) (*gitlab.Project, int, error) { + panic("implement me") +} + +func (m *MockGitlabClient) DeleteProject(projectID int, waitInterval int, waitCount int) (int, error) { + panic("implement me") +} + +func (m *MockGitlabClient) GetGroup(groupID int) (*gitlab.Group, int, error) { + if m.getGroupFunction != nil { + return m.getGroupFunction(groupID) + } + + if m.expectedGroups == nil { + m.expectedGroups = make(map[int]*gitlab.Group) + } + + return m.expectedGroups[groupID], 0, nil } -func (m *MockGitlabClient) NewClient(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) { - return m.newClientFunction(token, options...) +func (m *MockGitlabClient) AddGroup(options gitlab.CreateGroupOptions) (*gitlab.Group, int, error) { + return m.addGroupFunction(options) } -func (m *MockGitlabClient) ListGroups(opt *gitlab.ListGroupsOptions, options ...gitlab.RequestOptionFunc) ([]*gitlab.Group, *gitlab.Response, error) { - return m.listGroupsFunction(opt, options...) +func (m *MockGitlabClient) UpdateGroup(id int, options *gitlab.UpdateGroupOptions) (*gitlab.Group, int, error) { + return m.updateGroupFunction(id, options) } diff --git a/controllers/gitlab/project_controller.go b/controllers/gitlab/project_controller.go index d67ea4c26f9ab9be87299b2d03ef98553e2f6a37..e44dfda2f70bb0912f08ecbe3344616997e9875a 100644 --- a/controllers/gitlab/project_controller.go +++ b/controllers/gitlab/project_controller.go @@ -24,6 +24,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" gitlabv1alpha1 "valkyrie.dso.mil/valkyrie-api/apis/gitlab/v1alpha1" + gitlabClient "valkyrie.dso.mil/valkyrie-api/clients/gitlab" ) // ProjectReconciler reconciles a Project object @@ -31,7 +32,7 @@ type ProjectReconciler struct { client.Client Log logr.Logger Scheme *runtime.Scheme - gitlabClient Client + gitlabClient gitlabClient.Client } //+kubebuilder:rbac:groups=gitlab.valkyrie.dso.mil,resources=projects,verbs=get;list;watch;create;update;patch;delete @@ -55,6 +56,8 @@ func (r *ProjectReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct _ = r.Log.WithValues("project", req.NamespacedName) var err error + // TODO Setup the gitlab client + var project *gitlabv1alpha1.Project if project, err = r.getProject(ctx, req); err != nil { @@ -82,8 +85,6 @@ func (r *ProjectReconciler) updateStatus(ctx context.Context, project *gitlabv1a // SetupWithManager sets up the controller with the Manager. func (r *ProjectReconciler) SetupWithManager(mgr ctrl.Manager) error { - r.gitlabClient = ClientImpl{} - return ctrl.NewControllerManagedBy(mgr). For(&gitlabv1alpha1.Project{}). Owns(&gitlabv1alpha1.Pipeline{}). @@ -101,9 +102,9 @@ func (r *ProjectReconciler) getProject(ctx context.Context, request ctrl.Request return &project, nil } -func (r *ProjectReconciler) getGroup(groupID int64) (*gitlab.Group, error) { +func (r *ProjectReconciler) getGroup(groupID int) (*gitlab.Group, error) { var group *gitlab.Group - var response *gitlab.Response + var response int var err error if group, response, err = r.gitlabClient.GetGroup(groupID); err != nil { diff --git a/controllers/gitlab/project_controller_test.go b/controllers/gitlab/project_controller_test.go index 975132961bdc73719c2c4dbf5e68ca265873d57d..be724c9a6608251e035757c34889570ab0589d96 100644 --- a/controllers/gitlab/project_controller_test.go +++ b/controllers/gitlab/project_controller_test.go @@ -45,7 +45,7 @@ func getControllerWithMocksInGreenTestState() (ProjectReconciler, *MockManager, }, Spec: gitlabv1alpha1.ProjectSpec{ Name: "TestProject", - Path: "https://example.com/TestProject", + FullPath: "https://example.com/TestProject", ImpactLevel: "2", StorageTypes: nil, VirtualService: "default", @@ -87,9 +87,6 @@ var _ = Describe("SetupWithManager", func() { err := sut.SetupWithManager(mgr) - It("should setup the default gitlab client", func() { - Expect(sut.gitlabClient).To(BeAssignableToTypeOf(ClientImpl{})) - }) It("should return no error", func() { Expect(err).To(BeNil()) }) @@ -151,8 +148,8 @@ var _ = Describe("reconcile", func() { }) Context("getGroup returns an error", func() { failingGitlabClient := MockGitlabClient{ - getGroupFunction: func(groupID int64) (*gitlab.Group, *gitlab.Response, error) { - return nil, &gitlab.Response{}, &MockError{ + getGroupFunction: func(groupID int) (*gitlab.Group, int, error) { + return nil, 500, &MockError{ message: "failure in getGroup", } }, @@ -236,7 +233,7 @@ var _ = Describe("getProject", func() { var _ = Describe("getGroup", func() { Context("green state", func() { - var fakeGroupID = int64(1) + var fakeGroupID = 1 sut, _, _, _ := getControllerWithMocksInGreenTestState() group, err := sut.getGroup(fakeGroupID) It("should return a group, and no error.", func() { @@ -245,10 +242,10 @@ var _ = Describe("getGroup", func() { }) }) Context("gitlab client returns error", func() { - var fakeGroupID = int64(1) + var fakeGroupID = 1 failingGitlabClient := MockGitlabClient{ - getGroupFunction: func(groupID int64) (*gitlab.Group, *gitlab.Response, error) { - return nil, &gitlab.Response{}, &MockError{ + getGroupFunction: func(groupID int) (*gitlab.Group, int, error) { + return nil, 500, &MockError{ message: "failure in getGroup", } }, diff --git a/custom/p1/project.go b/custom/p1/project.go index c4c6064fbfad5f98a7160b46621ab7c1955ff4f8..b4b6a68e4c6588455eea8762a605ac9bba8131db 100644 --- a/custom/p1/project.go +++ b/custom/p1/project.go @@ -28,7 +28,7 @@ func CreateProject(projectCredentials ProjectCredentials, projectSpec apigitlab. logPrefix := "CreateProject" logStart(logPrefix, projectSpec) - client := gitlab.NewClient(projectCredentials.ServerURL, projectCredentials.ServerToken, httpClient) + client, _ := gitlab.NewClient(projectCredentials.ServerURL, projectCredentials.ServerToken, httpClient) // confirm parent group by ID group, statusCode, err := client.GetGroup(int(projectSpec.GroupID)) @@ -78,7 +78,7 @@ func DeleteProject(projectCredentials ProjectCredentials, projectSpec apigitlab. logPrefix := "DeleteProject" logStart(logPrefix, projectSpec) - client := gitlab.NewClient(projectCredentials.ServerURL, projectCredentials.ServerToken, httpClient) + client, _ := gitlab.NewClient(projectCredentials.ServerURL, projectCredentials.ServerToken, httpClient) group, _, err := client.GetGroup(int(projectSpec.GroupID)) if err != nil { return fmt.Errorf(fmt.Sprintf("Faild to find group with ID %d", int(projectSpec.GroupID))) @@ -109,7 +109,7 @@ func UpdateProject(projectCredentials ProjectCredentials, projectSpec apigitlab. logPrefix := "UpdateProject" logStart(logPrefix, projectSpec) - client := gitlab.NewClient(projectCredentials.ServerURL, projectCredentials.ServerToken, httpClient) + client, _ := gitlab.NewClient(projectCredentials.ServerURL, projectCredentials.ServerToken, httpClient) // Identify parent Group for project group, _, err := client.GetGroup(int(projectSpec.GroupID)) diff --git a/integration-tests/custom/p1/p1_main_test.go b/integration-tests/custom/p1/p1_main_test.go index de480b8cdc2b1350a8b415681cd8028b525e0c4b..06993ed8eeddedcfd3b59c28226c5144326299fd 100644 --- a/integration-tests/custom/p1/p1_main_test.go +++ b/integration-tests/custom/p1/p1_main_test.go @@ -117,6 +117,6 @@ func getClient() (gitlab.Client, error) { if !ok { return gitlab.Client{}, errors.New("env variable GITLAB_API_TOKEN undefinded") } - var client = gitlab.NewClient(gitlabAPIURL, gitlabAPIToken, nil) + var client, _ = gitlab.NewClient(gitlabAPIURL, gitlabAPIToken, nil) return client, nil } diff --git a/integration-tests/gitlab/api/gitlab_api_adhoc_test.go b/integration-tests/gitlab/api/gitlab_api_adhoc_test.go index 4e50afd3e36d9daca1f9dfb9e1c7297156c77242..cc08a2ddbc08e0ad45affc37943bae77d7c33954 100644 --- a/integration-tests/gitlab/api/gitlab_api_adhoc_test.go +++ b/integration-tests/gitlab/api/gitlab_api_adhoc_test.go @@ -3,39 +3,40 @@ package integration import ( + "testing" "errors" "os" "testing" gitlab "valkyrie.dso.mil/valkyrie-api/clients/gitlab" ) -// getClient_AdHoc - -func getClient_AdHoc() (gitlab.Client, error) { +// getClient_AdHoc - +func getClient_AdHoc() (gitlab.ClientImpl, error) { gitlabAPIURL, ok := os.LookupEnv("GITLAB_API_URL") if !ok { - return gitlab.Client{}, errors.New("env variable GITLAB_API_URL undefinded") + return gitlab.ClientImpl{}, errors.New("env variable GITLAB_API_URL undefinded") } gitlabAPIToken, ok := os.LookupEnv("GITLAB_API_TOKEN") if !ok { - return gitlab.Client{}, errors.New("env variable GITLAB_API_TOKEN undefinded") + return gitlab.ClientImpl{}, errors.New("env variable GITLAB_API_TOKEN undefinded") } - var client = gitlab.NewClient(gitlabAPIURL, gitlabAPIToken, nil) + var client, _ = gitlab.NewClient(gitlabAPIURL, gitlabAPIToken,nil) return client, nil } func TestClient_AdHoc_getUsers_All(t *testing.T) { t.Run("test", func(t *testing.T) { c, err := getClient_AdHoc() if err != nil { - t.Errorf("Client.GetUsers() error = %v", err) + t.Errorf("ClientImpl.GetUsers() error = %v", err) return } got, err := c.GetUsers(nil) if err != nil { - t.Errorf("Client.GetUsers() error = %v", err) + t.Errorf("ClientImpl.GetUsers() error = %v", err) return } t.Logf("GetUsers %d", len(got)) - for x := 0; x < len(got); x++ { + for x:=0;x