diff --git a/README.md b/README.md index 7d96782227bdb84dcb71fb4a8781a87d9672746e..858419f321ff90b50acfc7bb3d75c410c7cc8371 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ ## Valkyrie Automated CICD Provisioning Tool +## Bump ### Golang Frameworks - kubebuilder - https://book.kubebuilder.io/introduction.html diff --git a/apis/customer/v1alpha1/customer_types.go b/apis/customer/v1alpha1/customer_types.go index fd7950c2612995ed3afde079f51a2cb4cd19afa1..9fc3eecb99b010c6b20d405c6eedc2074a1cd8f7 100644 --- a/apis/customer/v1alpha1/customer_types.go +++ b/apis/customer/v1alpha1/customer_types.go @@ -18,7 +18,6 @@ package v1alpha1 import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "valkyrie.dso.mil/valkyrie-api/apis/gitlab/v1alpha1" ) // CustomerSpec defines the desired state of Customer @@ -26,9 +25,6 @@ type CustomerSpec struct { // Organization is the organizational information for this customer based upon the organization record in AutoBot Organization OrganizationSpec `json:"Organization,omitempty"` - // Group is the Gitlab Group that belongs to this Customer - Group v1alpha1.GroupSpec `json:"Group,omitempty"` - // test dummy - do not remove Dummy string `json:"dummy,omitempty"` } diff --git a/apis/customer/v1alpha1/zz_generated.deepcopy.go b/apis/customer/v1alpha1/zz_generated.deepcopy.go index e938b89ce014b7159ba64af19de4df5820be28b0..368bc294c5675eb2236438fc5eeb77019a8fa2cc 100644 --- a/apis/customer/v1alpha1/zz_generated.deepcopy.go +++ b/apis/customer/v1alpha1/zz_generated.deepcopy.go @@ -207,7 +207,7 @@ func (in *Customer) DeepCopyInto(out *Customer) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) + out.Spec = in.Spec out.Status = in.Status } @@ -265,7 +265,6 @@ func (in *CustomerList) DeepCopyObject() runtime.Object { func (in *CustomerSpec) DeepCopyInto(out *CustomerSpec) { *out = *in out.Organization = in.Organization - in.Group.DeepCopyInto(&out.Group) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomerSpec. diff --git a/apis/gitlab/v1alpha1/group_types.go b/apis/gitlab/v1alpha1/group_types.go index 6b62c8a51dabe65fe122ebdcbf37c3e7adf39f89..242a7eb900b97cedbee006172314d38f43909a87 100644 --- a/apis/gitlab/v1alpha1/group_types.go +++ b/apis/gitlab/v1alpha1/group_types.go @@ -23,7 +23,7 @@ import ( // GroupSpec defines the desired state of Group type GroupSpec struct { // FullPath is the gitlab path for this Project - // +kubebuiler:validation:required + // +kubebuilder:validation:required FullPath string `json:"path"` // Name is the name of the Group and will be used as part of the URL in Gitlab @@ -31,21 +31,17 @@ type GroupSpec struct { Name string `json:"name"` // Description is the Gitlab Description for the group - // +kubebuilder:validation:Optional + // +kubebuilder:validation:optional Description string `json:"description"` // GitlabCredentialsName is the name of the object in this namespace that contains authentication // 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 - ProjectSpecs []ProjectSpec `json:"projects:omitempty"` + // +kubebuilder:validation:Required + ProjectSpecs []ProjectSpec `json:"projects,omitempty"` } // GroupStatus defines the observed state of Group diff --git a/apis/gitlab/v1alpha1/project_types.go b/apis/gitlab/v1alpha1/project_types.go index a13d4b85b69f655abc81440fd25fdc967c11dd53..6d710dc355beb372d78e705a9c17e22f518e1584 100644 --- a/apis/gitlab/v1alpha1/project_types.go +++ b/apis/gitlab/v1alpha1/project_types.go @@ -31,17 +31,17 @@ type ProjectSpec struct { Name string `json:"name"` // FullPath is the gitlab path for this Project - // +kubebuiler:validation:required + // +kubebuilder:validation:required FullPath string `json:"path"` // ImpactLevel is the RMF Impact Level for this Project // +kubebuilder:validation:Enum=2;4;5;6 - // +kubebuiler:validation:required + // +kubebuilder:validation:required ImpactLevel string `json:"impactLevel"` // StorageTypes is the storage types that will be added to the Project - // +kubebuiler:validation:optional - StorageTypes []string `json:"storageTypes:omitempty"` + // +kubebuilder:validation:optional + StorageTypes []string `json:"storageTypes,omitempty"` // VirtualService is the type of virtual service that will be created for this Project // +kubebuilder:default="Default" @@ -51,7 +51,7 @@ type ProjectSpec struct { ServicePort int32 `json:"servicePort,omitempty"` // Language is the programming language of the Project for this application. - // +kubebuiler:validation:required + // +kubebuilder:validation:required Language string `json:"language"` //TODO: Consider a custom type / annotation } diff --git a/apis/gitlab/v1alpha1/zz_generated.deepcopy.go b/apis/gitlab/v1alpha1/zz_generated.deepcopy.go index 0b97a5607f1a60eabf4b78070237bfd50fb00979..b9e8572ebdfa671ec90396db7fb9f8fee0381159 100644 --- a/apis/gitlab/v1alpha1/zz_generated.deepcopy.go +++ b/apis/gitlab/v1alpha1/zz_generated.deepcopy.go @@ -177,13 +177,6 @@ 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)) diff --git a/clients/gitlab/client.go b/clients/gitlab/client.go index 9d76e9bdaabc96647e5e6bb24b1dca904d38098d..62cc74b6a1203b7e1b3da57363167d37fe38fc1c 100644 --- a/clients/gitlab/client.go +++ b/clients/gitlab/client.go @@ -45,6 +45,7 @@ import ( const itemsPerPage = 50 +// Client - type Client interface { GetUser(userID int) (*gogitlab.User, int, error) GetUsers(search *string) ([]*gogitlab.User, error) @@ -289,7 +290,7 @@ func (r ClientImpl) DeleteUser(userID int, waitInterval int, waitCount int) (int // DeleteUserByUsername - convenience method func (r ClientImpl) DeleteUserByUsername(username string, waitInterval int, waitCount int) (int, error) { - // waiting will be skilled if waitCount is 0 + // waiting will be skipped if waitCount is 0 // setting wait will use a loop to wait until resource has completed deletion logPrefix := "DeleteUserByUsername" @@ -308,6 +309,7 @@ func (r ClientImpl) DeleteUserByUsername(username string, waitInterval int, wait return statusCode, nil } + // the user return array should never have more than one entry statusCode, err := r.DeleteUser(users[0].ID, 0, 0) if err != nil { @@ -497,7 +499,7 @@ func (r ClientImpl) UpdateGroup(groupID int, updateGroupOptions *gogitlab.Update // DeleteGroup - func (r ClientImpl) DeleteGroup(groupID int, waitInterval int, waitCount int) (int, error) { - // waiting will be skilled if waitCount is 0 + // waiting will be skipped if waitCount is 0 // setting wait will use a loop to wait until resource has completed deletion logPrefix := "DeleteGroup" diff --git a/clients/gitlab/client_test.go b/clients/gitlab/client_test.go index 2e2f11e0457620824825e419f2b6605e23eeee4f..5466fb44ff54de18a4dc37530d142f46803edb00 100644 --- a/clients/gitlab/client_test.go +++ b/clients/gitlab/client_test.go @@ -534,7 +534,7 @@ func TestClient_DeleteUserByUsername(t *testing.T) { httpmock.RegisterResponder("DELETE", `=~^https://test/api/v4/users.*`, func(req *http.Request) (*http.Response, error) { - return httpmock.NewJsonResponse(201, testUser) + return httpmock.NewJsonResponse(http.StatusAccepted, testUser) }, ) @@ -564,7 +564,7 @@ func TestClient_DeleteUserByUsername(t *testing.T) { name: "DeleteUserByUsername Success", fields: fields{client: testGitlabClient, token: testToken, apiURL: testAPIUrl}, args: args{username: testUsername}, - want: http.StatusOK, + want: http.StatusAccepted, wantErr: false, }, { @@ -1121,7 +1121,7 @@ func TestClient_DeleteGroup(t *testing.T) { return } if got != tt.want { - t.Errorf("ClientImpl.รง() = %v, want %v", got, tt.want) + t.Errorf("ClientImpl.DeleteGroup() = %v, want %v", got, tt.want) return } t.Logf("ClientImpl.DeleteGroup() statusCode = %d ", got) diff --git a/config/crd/bases/customer.valkyrie.dso.mil_customers.yaml b/config/crd/bases/customer.valkyrie.dso.mil_customers.yaml index 39573fc416b4d06e926c9c3dc124a05dec8580b9..952f1c1fa6dd553de306b4d7c0f4dceba9544811 100644 --- a/config/crd/bases/customer.valkyrie.dso.mil_customers.yaml +++ b/config/crd/bases/customer.valkyrie.dso.mil_customers.yaml @@ -36,82 +36,6 @@ spec: spec: description: CustomerSpec defines the desired state of Customer properties: - Group: - description: Group is the Gitlab Group that belongs to this Customer - properties: - description: - description: Description is the Gitlab Description for the group - type: string - gitlabCredentialsName: - description: GitlabCredentialsName is the name of the object in - this namespace that contains authentication information for - logging into the - type: string - name: - description: Name is the name of the Group and will be used as - part of the URL in Gitlab - type: string - projects:omitempty: - description: 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. - items: - description: ProjectSpec defines the desired state of Project - properties: - groupId: - description: GroupID is the id of the GitLab Group id that - owns this project - format: int64 - type: integer - impactLevel: - description: ImpactLevel is the RMF Impact Level for this - Project - enum: - - 2 - - 4 - - 5 - - 6 - type: string - language: - description: Language is the programming language of the - Project for this application. - type: string - name: - description: Name is the name of this Project - type: string - path: - description: Path is the gitlab path for this Project - type: string - servicePort: - description: ServicePort is the port for the virtual service - for the application served by this Project - format: int32 - type: integer - storageTypes:omitempty: - description: StorageTypes is the storage types that will - be added to the Project - items: - type: string - type: array - virtualService: - default: Default - description: VirtualService is the type of virtual service - that will be created for this Project - type: string - required: - - groupId - - impactLevel - - language - - name - - path - - storageTypes:omitempty - - virtualService - type: object - type: array - required: - - gitlabCredentialsName - - name - type: object Organization: description: Organization is the organizational information for this customer based upon the organization record in AutoBot diff --git a/config/crd/bases/gitlab.valkyrie.dso.mil_groups.yaml b/config/crd/bases/gitlab.valkyrie.dso.mil_groups.yaml index 115616ef9ea1827c45ce3b27c0056718b83f8ca0..c8c4576e07af6487c8fb84cab0a4157b40afc54f 100644 --- a/config/crd/bases/gitlab.valkyrie.dso.mil_groups.yaml +++ b/config/crd/bases/gitlab.valkyrie.dso.mil_groups.yaml @@ -48,7 +48,10 @@ spec: description: Name is the name of the Group and will be used as part of the URL in Gitlab type: string - projects:omitempty: + path: + description: FullPath is the gitlab path for this Project + type: string + projects: description: 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. @@ -58,7 +61,6 @@ spec: groupId: description: GroupID is the id of the GitLab Group id that owns this project - format: int64 type: integer impactLevel: description: ImpactLevel is the RMF Impact Level for this Project @@ -76,14 +78,14 @@ spec: description: Name is the name of this Project type: string path: - description: Path is the gitlab path for this Project + description: FullPath is the gitlab path for this Project type: string servicePort: description: ServicePort is the port for the virtual service for the application served by this Project format: int32 type: integer - storageTypes:omitempty: + storageTypes: description: StorageTypes is the storage types that will be added to the Project items: @@ -100,13 +102,14 @@ spec: - language - name - path - - storageTypes:omitempty - virtualService type: object type: array required: + - description - gitlabCredentialsName - name + - path type: object status: description: GroupStatus defines the observed state of Group @@ -114,9 +117,6 @@ spec: createdTime: format: date-time type: string - gitlabId: - format: int64 - type: integer lastUpdatedTime: format: date-time type: string @@ -124,7 +124,6 @@ spec: type: string required: - createdTime - - gitlabId - lastUpdatedTime - state type: object diff --git a/config/crd/bases/gitlab.valkyrie.dso.mil_projects.yaml b/config/crd/bases/gitlab.valkyrie.dso.mil_projects.yaml index 2e29585e44899057195631c86ced887ee9dbf9f6..ab91d33bc63d730f1af0ae0a5c0202528a360fa3 100644 --- a/config/crd/bases/gitlab.valkyrie.dso.mil_projects.yaml +++ b/config/crd/bases/gitlab.valkyrie.dso.mil_projects.yaml @@ -39,7 +39,6 @@ spec: groupId: description: GroupID is the id of the GitLab Group id that owns this project - format: int64 type: integer impactLevel: description: ImpactLevel is the RMF Impact Level for this Project @@ -57,14 +56,14 @@ spec: description: Name is the name of this Project type: string path: - description: Path is the gitlab path for this Project + description: FullPath is the gitlab path for this Project type: string servicePort: description: ServicePort is the port for the virtual service for the application served by this Project format: int32 type: integer - storageTypes:omitempty: + storageTypes: description: StorageTypes is the storage types that will be added to the Project items: @@ -81,7 +80,6 @@ spec: - language - name - path - - storageTypes:omitempty - virtualService type: object status: diff --git a/custom/p1/project.go b/custom/p1/project.go index b4b6a68e4c6588455eea8762a605ac9bba8131db..eb740ce87cd6bbfc48e1e3087a9d6ebc29fd96ed 100644 --- a/custom/p1/project.go +++ b/custom/p1/project.go @@ -28,30 +28,34 @@ func CreateProject(projectCredentials ProjectCredentials, projectSpec apigitlab. logPrefix := "CreateProject" logStart(logPrefix, projectSpec) - client, _ := gitlab.NewClient(projectCredentials.ServerURL, projectCredentials.ServerToken, httpClient) - - // confirm parent group by ID - group, statusCode, err := client.GetGroup(int(projectSpec.GroupID)) + client, err := gitlab.NewClient(projectCredentials.ServerURL, projectCredentials.ServerToken, httpClient) if err != nil { - return fmt.Errorf(fmt.Sprintf("Failed to find group with ID %d. error: %v", int(projectSpec.GroupID), err)) - } - if statusCode != http.StatusOK { - return fmt.Errorf(fmt.Sprintf("Failed to find group with ID %d. status code: %d", int(projectSpec.GroupID), statusCode)) + processError(logPrefix, err) + return err } - // confirm parent group full path - parentGroupFullPath := group.FullPath - parentGroup, statusCode, err := client.GetGroupByFullPath(&parentGroupFullPath) + // Identify parent Group for project + projectFullPath := projectSpec.FullPath + groupFullPath, projectPath := ParseGitlabPath(projectFullPath) + // strip any trailing / + groupFullPath = StripLastChar(groupFullPath, "/") + parentGroup, statusCode, err := client.GetGroupByFullPath(&groupFullPath) + if err != nil { - return fmt.Errorf(fmt.Sprintf("Failed to find group with ID %d. error: %v", int(projectSpec.GroupID), err)) + return fmt.Errorf("failed to find group with fullPath %s. error: %v", groupFullPath, err) } if statusCode != http.StatusFound { - return fmt.Errorf(fmt.Sprintf("Failed to find group with ID %d. status code: %d", int(projectSpec.GroupID), statusCode)) + return fmt.Errorf("failed to find group with fullPath %s. status code: %d", groupFullPath, statusCode) + } + + ciConfigPath, err := generateCIConfigPath(projectPath, groupFullPath) + if err != nil { + return fmt.Errorf("failed to generateCIConfigPath: %v", err) } - ciConfigPath := generateCIConfigPath(projectSpec.Name, parentGroupFullPath) projectOptions := gogitlab.CreateProjectOptions{ Name: &projectSpec.Name, + Path: &projectPath, NamespaceID: &parentGroup.ID, CIConfigPath: &ciConfigPath, } @@ -62,10 +66,10 @@ func CreateProject(projectCredentials ProjectCredentials, projectSpec apigitlab. project, statusCode, err := client.AddProject(projectOptions) if err != nil { - return fmt.Errorf(fmt.Sprintf("Failed to add project with name %s to group path %s. error: %v", *projectOptions.Name, parentGroupFullPath, err)) + return fmt.Errorf("failed to add project with name %s to group path %s. error: %v", *projectOptions.Name, groupFullPath, err) } if statusCode != http.StatusCreated { - return fmt.Errorf(fmt.Sprintf("Failed to add project with name %s to group path %s. statusCode: %d", *projectOptions.Name, parentGroupFullPath, statusCode)) + return fmt.Errorf(fmt.Sprintf("Failed to add project with name %s to group path %s. statusCode: %d", *projectOptions.Name, groupFullPath, statusCode)) } rlog.Debugf("Added project %s to path %s with status code %d", project.Name, project.NameWithNamespace, statusCode) @@ -78,28 +82,28 @@ func DeleteProject(projectCredentials ProjectCredentials, projectSpec apigitlab. logPrefix := "DeleteProject" logStart(logPrefix, projectSpec) - client, _ := gitlab.NewClient(projectCredentials.ServerURL, projectCredentials.ServerToken, httpClient) - group, _, err := client.GetGroup(int(projectSpec.GroupID)) + client, err := gitlab.NewClient(projectCredentials.ServerURL, projectCredentials.ServerToken, httpClient) if err != nil { - return fmt.Errorf(fmt.Sprintf("Faild to find group with ID %d", int(projectSpec.GroupID))) + processError(logPrefix, err) + return err } - parentGroupFullPath := group.FullPath - // get scrubbed pathname based on actual name - projectPathString, _ := GenerateGitlabPath(projectSpec.Name) - projectFullPath := parentGroupFullPath + "/" + projectPathString + + projectFullPath := projectSpec.FullPath project, statusCode, err := client.GetProjectByFullPath(&projectFullPath) if err != nil { processError(logPrefix, err) return err } + if statusCode != http.StatusFound { - return fmt.Errorf(fmt.Sprintf("Failed to find project with full path %s", projectFullPath)) + return fmt.Errorf("failed to find project with fullPath %s", projectFullPath) } - _, err = client.DeleteProject(project.ID, 0, 0) + // delete and wait for delete to complete up to 500ms * 240 tries + _, err = client.DeleteProject(project.ID, 500, 240) if err != nil { - return fmt.Errorf(fmt.Sprintf("Faild to delete project with ID %d", int(project.ID))) + return fmt.Errorf("failed to delete project with fullPath: %s", projectFullPath) } return nil } @@ -109,28 +113,40 @@ func UpdateProject(projectCredentials ProjectCredentials, projectSpec apigitlab. logPrefix := "UpdateProject" logStart(logPrefix, projectSpec) - client, _ := gitlab.NewClient(projectCredentials.ServerURL, projectCredentials.ServerToken, httpClient) + client, err := gitlab.NewClient(projectCredentials.ServerURL, projectCredentials.ServerToken, httpClient) + if err != nil { + processError(logPrefix, err) + return err + } // Identify parent Group for project - group, _, err := client.GetGroup(int(projectSpec.GroupID)) + projectFullPath := projectSpec.FullPath + groupFullPath, projectPath := ParseGitlabPath(projectSpec.FullPath) + // strip any trailing / + groupFullPath = StripLastChar(groupFullPath, "/") + group, _, err := client.GetGroupByFullPath(&groupFullPath) if err != nil { processError(logPrefix, err) - return fmt.Errorf(fmt.Sprintf("Faild to find group with ID %d", int(projectSpec.GroupID))) + return fmt.Errorf("failed to find group with fullPath %s", groupFullPath) } + parentGroupFullPath := group.FullPath - // get scrubbed pathname based on actual name - projectPathString, _ := GenerateGitlabPath(projectSpec.Name) - projectFullPath := parentGroupFullPath + "/" + projectPathString + project, statusCode, err := client.GetProjectByFullPath(&projectFullPath) if err != nil { processError(logPrefix, err) return err } if statusCode != http.StatusFound { - return fmt.Errorf(fmt.Sprintf("Failed to find project with full path %s", projectFullPath)) + return fmt.Errorf("failed to find project with fullPath %s", projectFullPath) + } + + ciConfigPath, err := generateCIConfigPath(projectPath, parentGroupFullPath) + if err != nil { + processError(logPrefix, err) + return err } - ciConfigPath := generateCIConfigPath(projectSpec.Name, parentGroupFullPath) projectOptions := gogitlab.EditProjectOptions{ Name: &projectSpec.Name, CIConfigPath: &ciConfigPath, @@ -146,8 +162,13 @@ func UpdateProject(projectCredentials ProjectCredentials, projectSpec apigitlab. return nil } -func generateCIConfigPath(projectName string, parentGroupFullPath string) string { - projectPathString, _ := GenerateGitlabPath(projectName) +// generateCIConfigPath - helper function. create CI configuration path for P1 +func generateCIConfigPath(projectName string, parentGroupFullPath string) (string, error) { + // scrub the project name + projectPathString, err := GenerateGitlabPath(projectName) + if err != nil { + return "", fmt.Errorf("failed to GenerateGitlabPath with name %s error: %v", projectName, err) + } ciConfigPath := fmt.Sprintf("%s/%s-ci.yml@platform-one/devops/pipeline-products", parentGroupFullPath, projectPathString) - return ciConfigPath + return ciConfigPath, nil } diff --git a/custom/p1/types_test.go b/custom/p1/types_test.go index 677c001c0cc29fbeaeb03f0198ce09e86a337ec0..e58d7d546b2be20eb8cc859bce077fa88fe99914 100644 --- a/custom/p1/types_test.go +++ b/custom/p1/types_test.go @@ -21,6 +21,12 @@ func TestGetProjectLanguage(t *testing.T) { want: LangTypes[LangTypeCpp], wantErr: false, }, + { + name: "project language test", + args: args{langTypeName: "BAD"}, + want: LangType{}, + wantErr: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/custom/p1/utils.go b/custom/p1/utils.go index 4cc2117620096dcae82590c8b3771497fadcd49f..979479858865b2d343c83a96c749fa1f1d233990 100644 --- a/custom/p1/utils.go +++ b/custom/p1/utils.go @@ -1,6 +1,7 @@ package p1 import ( + "path" "regexp" "strings" ) @@ -26,3 +27,19 @@ func GenerateGitlabPath(name string) (string, error) { return pathLower, nil } + +// ParseGitlabPath - extract the basename from a path +func ParseGitlabPath(fullpath string) (parent string, name string) { + parent, name = path.Split(fullpath) + return parent, name +} + +// StripLastChar - +func StripLastChar(value string, char string) string { + var re *regexp.Regexp + + // remove any trailing dash or whitespace + re, _ = regexp.Compile(`[` + char + `]{1}$`) + newValue := re.ReplaceAllString(value, "") + return newValue +} diff --git a/custom/p1/utils_test.go b/custom/p1/utils_test.go index 88722d60c24a020c2f2c6d335aceae66cb5c8ae2..0dc08bd9d26e93cf678f23f37c30e28617cb2640 100644 --- a/custom/p1/utils_test.go +++ b/custom/p1/utils_test.go @@ -1,6 +1,8 @@ package p1 -import "testing" +import ( + "testing" +) func TestGenerateGitlabPath(t *testing.T) { type args struct { @@ -34,3 +36,35 @@ func TestGenerateGitlabPath(t *testing.T) { }) } } + +func TestParseGitlabPath(t *testing.T) { + type args struct { + fullpath string + } + tests := []struct { + name string + args args + wantParent string + wantName string + }{ + + {name: "test 1", args: args{fullpath: ""}, wantParent: "", wantName: ""}, + {name: "test 1", args: args{fullpath: "test-path"}, wantParent: "", wantName: "test-path"}, + {name: "test 1", args: args{fullpath: "parent-path/base-name"}, wantParent: "parent-path/", wantName: "base-name"}, + {name: "test 1", args: args{fullpath: "/parent-path/sub-group-path/base-name"}, wantParent: "/parent-path/sub-group-path/", wantName: "base-name"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotParent, gotName := ParseGitlabPath(tt.args.fullpath) + if gotParent != tt.wantParent { + t.Errorf("ParseGitlabPath() gotParent = %v, want %v", gotParent, tt.wantParent) + return + } + if gotName != tt.wantName { + t.Errorf("ParseGitlabPath() gotName = %v, want %v", gotName, tt.wantName) + return + } + t.Logf("TestParseGitlabPath() PASS input '%s', want '%s' '%s'", tt.args.fullpath, gotParent, gotName) + }) + } +} diff --git a/integration-tests/custom/p1/p1_main_test.go b/integration-tests/custom/p1/p1_main_test.go index 06993ed8eeddedcfd3b59c28226c5144326299fd..ef8487ff9a9aeb00a3df9939856b744a8f98195b 100644 --- a/integration-tests/custom/p1/p1_main_test.go +++ b/integration-tests/custom/p1/p1_main_test.go @@ -1,4 +1,3 @@ - // +build integration package integration @@ -15,8 +14,10 @@ import ( gitlab "valkyrie.dso.mil/valkyrie-api/clients/gitlab" ) +// pathname for root group used in integration testing const p1IntegrationRootGroupPath = "integration-root-group" +// configuration obect to be shared for integration testing var P1Config struct { gitlabAPIURL string gitlabAPIToken string @@ -26,24 +27,35 @@ var P1Config struct { // TestMain - setup and teardown reusable code. wraps around other tests func TestMain(m *testing.M) { + + // setup environment for testing err := packageSetup() if err != nil { fmt.Printf("packageSetup error: %v", err) os.Exit(1) } + + // run tests resultCode := m.Run() + packageTeardown() + os.Exit(resultCode) } +// packageSetup - setup environment for integration testing func packageSetup() error { var err error // initialize P1Config.testProjectGroupPath = p1IntegrationRootGroupPath + + // read env variables err = getEnvVariables() if err != nil { return err } + + // add gitlab root group if does not exist err = addRootGroup() if err != nil { return err @@ -66,8 +78,11 @@ func getEnvVariables() error { if !ok { return errors.New("env variable GITLAB_API_TOKEN undefinded") } + + // set values in package scoped config object P1Config.gitlabAPIToken = gitlabAPIToken P1Config.gitlabAPIURL = gitlabAPIURL + return nil } @@ -107,16 +122,20 @@ func addRootGroup() error { return nil } -// getClientGroups - -func getClient() (gitlab.Client, error) { +// getClient - create a gitlab client object +func getClient() (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") + } + client, err := gitlab.NewClient(gitlabAPIURL, gitlabAPIToken, nil) + if err != nil { + return gitlab.ClientImpl{}, err } - var client, _ = gitlab.NewClient(gitlabAPIURL, gitlabAPIToken, nil) return client, nil + } diff --git a/integration-tests/custom/p1/p1_projects_test.go b/integration-tests/custom/p1/p1_projects_test.go index ded9acd3cbcf7d5524872f88e45a0545c0fcad08..189826c15f0dc62e010c85c17f1ed1f12dd6866e 100644 --- a/integration-tests/custom/p1/p1_projects_test.go +++ b/integration-tests/custom/p1/p1_projects_test.go @@ -14,13 +14,14 @@ import ( P1Config is initialized in the TestMain wrapper method */ +const integrationTestProjectPath = "int-test-project" func Test_P1_AddProject(t *testing.T) { logPrefix := "Test_P1_AddProject" t.Run("test", func(t *testing.T) { projectSpec := v1alpha1.ProjectSpec{ - Name: "My Test Project", - GroupID: int64(P1Config.integrationRootGroupID), + Name: "My Test Project", + FullPath: p1IntegrationRootGroupPath + "/" + integrationTestProjectPath, Language: custom_p1.LangTypeAngular, } @@ -43,9 +44,9 @@ func Test_P1_UpdateProject(t *testing.T) { logPrefix := "Test_P1_UpdateProject" t.Run("test", func(t *testing.T) { projectSpec := v1alpha1.ProjectSpec{ - Name: "My Test Project", - GroupID: int64(P1Config.integrationRootGroupID), - Language: custom_p1.LangTypeJavaMaven, + Name: "My Test Updated Project", + FullPath: p1IntegrationRootGroupPath + "/" + integrationTestProjectPath, + Language: custom_p1.LangTypeJavaMaven, } creds := custom_p1.ProjectCredentials{ @@ -66,8 +67,7 @@ func Test_P1_DeleteProject(t *testing.T) { logPrefix := "Test_P1_DeleteProject" t.Run("test", func(t *testing.T) { projectSpec := v1alpha1.ProjectSpec{ - Name: "My Test Project", - GroupID: int64(P1Config.integrationRootGroupID), + FullPath: p1IntegrationRootGroupPath + "/" + integrationTestProjectPath, } creds := custom_p1.ProjectCredentials{ diff --git a/integration-tests/gitlab/api/gitlab_api_adhoc_test.go b/integration-tests/gitlab/api/gitlab_api_adhoc_test.go index cc08a2ddbc08e0ad45affc37943bae77d7c33954..5c7be044fb0ad92d7dc97e67bb39cc8d0cd9eded 100644 --- a/integration-tests/gitlab/api/gitlab_api_adhoc_test.go +++ b/integration-tests/gitlab/api/gitlab_api_adhoc_test.go @@ -6,7 +6,6 @@ import ( "testing" "errors" "os" - "testing" gitlab "valkyrie.dso.mil/valkyrie-api/clients/gitlab" )