diff --git a/audit_events.go b/audit_events.go index de312e560..f51415c70 100644 --- a/audit_events.go +++ b/audit_events.go @@ -14,6 +14,7 @@ type AuditEvent struct { AuthorID int `json:"author_id"` EntityID int `json:"entity_id"` EntityType string `json:"entity_type"` + EventName string `json:"event_name"` Details AuditEventDetails `json:"details"` CreatedAt *time.Time `json:"created_at"` EventType string `json:"event_type"` @@ -42,6 +43,7 @@ type AuditEventDetails struct { IPAddress string `json:"ip_address"` EntityPath string `json:"entity_path"` FailedLogin string `json:"failed_login"` + EventName string `json:"event_name"` } // AuditEventsService handles communication with the project/group/instance diff --git a/audit_events_test.go b/audit_events_test.go index a76127129..b2c6ba296 100644 --- a/audit_events_test.go +++ b/audit_events_test.go @@ -20,7 +20,9 @@ func TestAuditEventsService_ListInstanceAuditEvents(t *testing.T) { "author_id": 1, "entity_id": 6, "entity_type": "Project", + "event_name": "project_archived", "details": { + "event_name": "project_archived", "custom_message": "Project archived", "author_name": "Venkatesh Thalluri", "target_id": "flightjs/flight", @@ -39,7 +41,9 @@ func TestAuditEventsService_ListInstanceAuditEvents(t *testing.T) { AuthorID: 1, EntityID: 6, EntityType: "Project", + EventName: "project_archived", Details: AuditEventDetails{ + EventName: "project_archived", CustomMessage: "Project archived", AuthorName: "Venkatesh Thalluri", TargetID: "flightjs/flight", @@ -86,7 +90,9 @@ func TestAuditEventsService_GetInstanceAuditEvent(t *testing.T) { "author_id": 1, "entity_id": 6, "entity_type": "Project", + "event_name": "project_archived", "details": { + "event_name": "project_archived", "custom_message": "Project archived", "author_name": "Venkatesh Thalluri", "target_id": "flightjs/flight", @@ -103,8 +109,10 @@ func TestAuditEventsService_GetInstanceAuditEvent(t *testing.T) { ID: 1, AuthorID: 1, EntityID: 6, + EventName: "project_archived", EntityType: "Project", Details: AuditEventDetails{ + EventName: "project_archived", CustomMessage: "Project archived", AuthorName: "Venkatesh Thalluri", TargetID: "flightjs/flight", @@ -143,7 +151,9 @@ func TestAuditEventsService_ListGroupAuditEvents(t *testing.T) { "author_id": 1, "entity_id": 6, "entity_type": "Group", + "event_name": "group_archived", "details": { + "event_name": "group_archived", "custom_message": "Group archived", "author_name": "Venkatesh Thalluri", "target_id": "flightjs/flight", @@ -162,7 +172,9 @@ func TestAuditEventsService_ListGroupAuditEvents(t *testing.T) { AuthorID: 1, EntityID: 6, EntityType: "Group", + EventName: "group_archived", Details: AuditEventDetails{ + EventName: "group_archived", CustomMessage: "Group archived", AuthorName: "Venkatesh Thalluri", TargetID: "flightjs/flight", @@ -205,7 +217,9 @@ func TestAuditEventsService_GetGroupAuditEvent(t *testing.T) { "author_id": 1, "entity_id": 6, "entity_type": "Group", + "event_name": "group_archived", "details": { + "event_name": "group_archived", "custom_message": "Group archived", "author_name": "Venkatesh Thalluri", "target_id": "flightjs/flight", @@ -223,7 +237,9 @@ func TestAuditEventsService_GetGroupAuditEvent(t *testing.T) { AuthorID: 1, EntityID: 6, EntityType: "Group", + EventName: "group_archived", Details: AuditEventDetails{ + EventName: "group_archived", CustomMessage: "Group archived", AuthorName: "Venkatesh Thalluri", TargetID: "flightjs/flight", @@ -267,7 +283,9 @@ func TestAuditEventsService_ListProjectAuditEvents(t *testing.T) { "author_id": 1, "entity_id": 6, "entity_type": "Project", + "event_name": "project_archived", "details": { + "event_name": "project_archived", "custom_message": "Project archived", "author_name": "Venkatesh Thalluri", "target_id": "flightjs/flight", @@ -286,7 +304,9 @@ func TestAuditEventsService_ListProjectAuditEvents(t *testing.T) { AuthorID: 1, EntityID: 6, EntityType: "Project", + EventName: "project_archived", Details: AuditEventDetails{ + EventName: "project_archived", CustomMessage: "Project archived", AuthorName: "Venkatesh Thalluri", TargetID: "flightjs/flight", @@ -329,7 +349,9 @@ func TestAuditEventsService_GetProjectAuditEvent(t *testing.T) { "author_id": 1, "entity_id": 6, "entity_type": "Project", + "event_name": "project_archived", "details": { + "event_name": "project_archived", "custom_message": "Project archived", "author_name": "Venkatesh Thalluri", "target_id": "flightjs/flight", @@ -347,7 +369,9 @@ func TestAuditEventsService_GetProjectAuditEvent(t *testing.T) { AuthorID: 1, EntityID: 6, EntityType: "Project", + EventName: "project_archived", Details: AuditEventDetails{ + EventName: "project_archived", CustomMessage: "Project archived", AuthorName: "Venkatesh Thalluri", TargetID: "flightjs/flight", diff --git a/environments.go b/environments.go index b99975a69..7ec0fa63d 100644 --- a/environments.go +++ b/environments.go @@ -37,6 +37,7 @@ type Environment struct { ID int `json:"id"` Name string `json:"name"` Slug string `json:"slug"` + Description string `json:"description"` State string `json:"state"` Tier string `json:"tier"` ExternalURL string `json:"external_url"` @@ -121,6 +122,7 @@ func (s *EnvironmentsService) GetEnvironment(pid interface{}, environment int, o // https://docs.gitlab.com/ee/api/environments.html#create-a-new-environment type CreateEnvironmentOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` ExternalURL *string `url:"external_url,omitempty" json:"external_url,omitempty"` Tier *string `url:"tier,omitempty" json:"tier,omitempty"` ClusterAgentID *int `url:"cluster_agent_id,omitempty" json:"cluster_agent_id,omitempty"` @@ -162,6 +164,7 @@ func (s *EnvironmentsService) CreateEnvironment(pid interface{}, opt *CreateEnvi // https://docs.gitlab.com/ee/api/environments.html#update-an-existing-environment type EditEnvironmentOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` ExternalURL *string `url:"external_url,omitempty" json:"external_url,omitempty"` Tier *string `url:"tier,omitempty" json:"tier,omitempty"` ClusterAgentID *int `url:"cluster_agent_id,omitempty" json:"cluster_agent_id,omitempty"` diff --git a/environments_test.go b/environments_test.go index 148bd4319..a4b0ad6ed 100644 --- a/environments_test.go +++ b/environments_test.go @@ -38,6 +38,7 @@ func TestListEnvironments(t *testing.T) { { "id": 1, "name": "review/fix-foo", + "description": "test", "slug": "review-fix-foo-dfjre3", "external_url": "https://review-fix-foo-dfjre3.example.gitlab.com", "state": "stopped", @@ -75,6 +76,7 @@ func TestListEnvironments(t *testing.T) { ID: 1, Name: "review/fix-foo", Slug: "review-fix-foo-dfjre3", + Description: "test", ExternalURL: "https://review-fix-foo-dfjre3.example.gitlab.com", State: "stopped", CreatedAt: &createdAtWant, @@ -109,6 +111,7 @@ func TestGetEnvironment(t *testing.T) { fmt.Fprint(w, `{ "id": 1, "name": "review/fix-foo", + "description": "test", "slug": "review-fix-foo-dfjre3", "external_url": "https://review-fix-foo-dfjre3.example.gitlab.com", "state": "stopped", @@ -145,6 +148,7 @@ func TestGetEnvironment(t *testing.T) { ID: 1, Name: "review/fix-foo", Slug: "review-fix-foo-dfjre3", + Description: "test", ExternalURL: "https://review-fix-foo-dfjre3.example.gitlab.com", State: "stopped", CreatedAt: &createdAtWant, @@ -180,6 +184,7 @@ func TestCreateEnvironment(t *testing.T) { fmt.Fprint(w, `{ "id": 1, "name": "deploy", + "description": "test", "slug": "deploy", "external_url": "https://deploy.example.gitlab.com", "tier": "production", @@ -205,6 +210,7 @@ func TestCreateEnvironment(t *testing.T) { envs, _, err := client.Environments.CreateEnvironment(1, &CreateEnvironmentOptions{ Name: Ptr("deploy"), + Description: Ptr("test"), ExternalURL: Ptr("https://deploy.example.gitlab.com"), Tier: Ptr("production"), ClusterAgentID: Ptr(1), @@ -220,6 +226,7 @@ func TestCreateEnvironment(t *testing.T) { ID: 1, Name: "deploy", Slug: "deploy", + Description: "test", ExternalURL: "https://deploy.example.gitlab.com", Tier: "production", ClusterAgent: &Agent{ @@ -253,6 +260,7 @@ func TestEditEnvironment(t *testing.T) { fmt.Fprint(w, `{ "id": 1, "name": "staging", + "description": "test", "slug": "staging", "external_url": "https://staging.example.gitlab.com", "tier": "staging", @@ -278,6 +286,7 @@ func TestEditEnvironment(t *testing.T) { envs, _, err := client.Environments.EditEnvironment(1, 1, &EditEnvironmentOptions{ Name: Ptr("staging"), + Description: Ptr("test"), ExternalURL: Ptr("https://staging.example.gitlab.com"), Tier: Ptr("staging"), ClusterAgentID: Ptr(1), @@ -293,6 +302,7 @@ func TestEditEnvironment(t *testing.T) { ID: 1, Name: "staging", Slug: "staging", + Description: "test", ExternalURL: "https://staging.example.gitlab.com", Tier: "staging", ClusterAgent: &Agent{ @@ -356,6 +366,7 @@ func TestUnmarshal(t *testing.T) { { "id": 10, "name": "production", + "description": "test", "slug": "production", "external_url": "https://example.com", "project": { @@ -396,6 +407,7 @@ func TestUnmarshal(t *testing.T) { if assert.NoError(t, err) { assert.Equal(t, 10, env.ID) assert.Equal(t, "production", env.Name) + assert.Equal(t, "test", env.Description) assert.Equal(t, "https://example.com", env.ExternalURL) assert.Equal(t, "available", env.State) if assert.NotNil(t, env.Project) { diff --git a/groups.go b/groups.go index 34f0cab66..4576d1095 100644 --- a/groups.go +++ b/groups.go @@ -46,6 +46,7 @@ type Group struct { MembershipLock bool `json:"membership_lock"` Visibility VisibilityValue `json:"visibility"` LFSEnabled bool `json:"lfs_enabled"` + DefaultBranch string `json:"default_branch"` DefaultBranchProtectionDefaults struct { AllowedToPush []*GroupAccessLevel `json:"allowed_to_push"` AllowForcePush bool `json:"allow_force_push"` @@ -358,6 +359,7 @@ type CreateGroupOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` Path *string `url:"path,omitempty" json:"path,omitempty"` Avatar *GroupAvatar `url:"-" json:"-"` + DefaultBranch *string `url:"default_branch,omitempty" json:"default_branch,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` MembershipLock *bool `url:"membership_lock,omitempty" json:"membership_lock,omitempty"` Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` @@ -502,6 +504,7 @@ type UpdateGroupOptions struct { Name *string `url:"name,omitempty" json:"name,omitempty"` Path *string `url:"path,omitempty" json:"path,omitempty"` Avatar *GroupAvatar `url:"-" json:"avatar,omitempty"` + DefaultBranch *string `url:"default_branch,omitempty" json:"default_branch,omitempty"` Description *string `url:"description,omitempty" json:"description,omitempty"` MembershipLock *bool `url:"membership_lock,omitempty" json:"membership_lock,omitempty"` Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` diff --git a/groups_test.go b/groups_test.go index 56eb8bbbb..d4e03c567 100644 --- a/groups_test.go +++ b/groups_test.go @@ -38,7 +38,7 @@ func TestGetGroup(t *testing.T) { mux.HandleFunc("/api/v4/groups/g", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, http.MethodGet) - fmt.Fprint(w, `{"id": 1, "name": "g"}`) + fmt.Fprint(w, `{"id": 1, "name": "g", "default_branch": "branch"}`) }) group, _, err := client.Groups.GetGroup("g", &GetGroupOptions{}) @@ -46,7 +46,7 @@ func TestGetGroup(t *testing.T) { t.Errorf("Groups.GetGroup returned error: %v", err) } - want := &Group{ID: 1, Name: "g"} + want := &Group{ID: 1, Name: "g", DefaultBranch: "branch"} if !reflect.DeepEqual(want, group) { t.Errorf("Groups.GetGroup returned %+v, want %+v", group, want) } @@ -97,6 +97,32 @@ func TestCreateGroup(t *testing.T) { } } +func TestCreateGroupWithDefaultBranch(t *testing.T) { + mux, client := setup(t) + + mux.HandleFunc("/api/v4/groups", + func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodPost) + fmt.Fprint(w, `{"id": 1, "name": "g", "path": "g", "default_branch": "branch"}`) + }) + + opt := &CreateGroupOptions{ + Name: Ptr("g"), + Path: Ptr("g"), + DefaultBranch: Ptr("branch"), + } + + group, _, err := client.Groups.CreateGroup(opt, nil) + if err != nil { + t.Errorf("Groups.CreateGroup returned error: %v", err) + } + + want := &Group{ID: 1, Name: "g", Path: "g", DefaultBranch: "branch"} + if !reflect.DeepEqual(want, group) { + t.Errorf("Groups.CreateGroup returned %+v, want %+v", group, want) + } +} + func TestCreateGroupDefaultBranchSettings(t *testing.T) { mux, client := setup(t) @@ -326,6 +352,30 @@ func TestUpdateGroup(t *testing.T) { } } +func TestUpdateGroupWithDefaultBranch(t *testing.T) { + mux, client := setup(t) + + mux.HandleFunc("/api/v4/groups/1", + func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodPut) + fmt.Fprint(w, `{"id": 1, "default_branch": "branch"}`) + }) + + opt := &UpdateGroupOptions{ + DefaultBranch: Ptr("branch"), + } + + group, _, err := client.Groups.UpdateGroup(1, opt) + if err != nil { + t.Errorf("Groups.UpdateGroup returned error: %v", err) + } + + want := &Group{ID: 1, DefaultBranch: "branch"} + if !reflect.DeepEqual(want, group) { + t.Errorf("Groups.UpdatedGroup returned %+v, want %+v", group, want) + } +} + func TestListGroupProjects(t *testing.T) { mux, client := setup(t) diff --git a/services.go b/services.go index 0059714c7..56eeca86e 100644 --- a/services.go +++ b/services.go @@ -767,6 +767,103 @@ func (s *ServicesService) DeleteGithubService(pid interface{}, options ...Reques return s.client.Do(req, nil) } +// HarborService represents the Harbor service settings. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/integrations.html#harbor +type HarborService struct { + Service + Properties *HarborServiceProperties `json:"properties"` +} + +// HarborServiceProperties represents Harbor specific properties. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/integrations.html#harbor +type HarborServiceProperties struct { + URL string `json:"url"` + ProjectName string `json:"project_name"` + Username string `json:"username"` + Password string `json:"password"` + UseInheritedSettings bool `json:"use_inherited_settings"` +} + +// GetHarborService gets Harbor service settings for a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/integrations.html#get-harbor-settings +func (s *ServicesService) GetHarborService(pid interface{}, options ...RequestOptionFunc) (*HarborService, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/integrations/harbor", PathEscape(project)) + + req, err := s.client.NewRequest(http.MethodGet, u, nil, options) + if err != nil { + return nil, nil, err + } + + svc := new(HarborService) + resp, err := s.client.Do(req, svc) + if err != nil { + return nil, resp, err + } + + return svc, resp, nil +} + +// SetHarborServiceOptions represents the available SetHarborService() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/integrations.html#set-up-harbor +type SetHarborServiceOptions struct { + URL *string `url:"url,omitempty" json:"url,omitempty"` + ProjectName *string `url:"project_name,omitempty" json:"project_name,omitempty"` + Username *string `url:"username,omitempty" json:"username,omitempty"` + Password *string `url:"password,omitempty" json:"password,omitempty"` + UseInheritedSettings *bool `url:"use_inherited_settings,omitempty" json:"use_inherited_settings,omitempty"` +} + +// SetHarborService sets Harbor service for a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/integrations.html#set-up-harbor +func (s *ServicesService) SetHarborService(pid interface{}, opt *SetHarborServiceOptions, options ...RequestOptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/integrations/harbor", PathEscape(project)) + + req, err := s.client.NewRequest(http.MethodPut, u, opt, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// DeleteHarborService deletes Harbor service for a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/integrations.html#disable-harbor +func (s *ServicesService) DeleteHarborService(pid interface{}, options ...RequestOptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/integrations/harbor", PathEscape(project)) + + req, err := s.client.NewRequest(http.MethodDelete, u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + // SlackApplication represents GitLab for slack application settings. // // GitLab API docs: diff --git a/services_test.go b/services_test.go index 36614cecf..53596eaca 100644 --- a/services_test.go +++ b/services_test.go @@ -327,6 +327,58 @@ func TestDeleteEmailsOnPushService(t *testing.T) { } } +func TestGetHarborService(t *testing.T) { + mux, client := setup(t) + + mux.HandleFunc("/api/v4/projects/1/integrations/harbor", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodGet) + fmt.Fprint(w, `{"id":1}`) + }) + want := &HarborService{Service: Service{ID: 1}} + + service, _, err := client.Services.GetHarborService(1) + if err != nil { + t.Fatalf("Services.GetHarborService returns an error: %v", err) + } + if !reflect.DeepEqual(want, service) { + t.Errorf("Services.GetHarborService returned %+v, want %+v", service, want) + } +} + +func TestSetHarborService(t *testing.T) { + mux, client := setup(t) + + mux.HandleFunc("/api/v4/projects/1/integrations/harbor", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodPut) + }) + + opt := &SetHarborServiceOptions{ + URL: Ptr("url"), + ProjectName: Ptr("project"), + Username: Ptr("user"), + Password: Ptr("pass"), + UseInheritedSettings: Ptr(false), + } + + _, err := client.Services.SetHarborService(1, opt) + if err != nil { + t.Fatalf("Services.SetHarborService returns an error: %v", err) + } +} + +func TestDeleteHarborService(t *testing.T) { + mux, client := setup(t) + + mux.HandleFunc("/api/v4/projects/1/integrations/harbor", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodDelete) + }) + + _, err := client.Services.DeleteHarborService(1) + if err != nil { + t.Fatalf("Services.DeleteHarborService returns an error: %v", err) + } +} + func TestGetSlackApplication(t *testing.T) { mux, client := setup(t)