diff --git a/github/github-accessors.go b/github/github-accessors.go index 57a7165f7ff..a1114a69957 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -4351,7 +4351,7 @@ func (c *CreateOrgInvitationOptions) GetRole() string { } // GetBaseRole returns the BaseRole field if it's non-nil, zero value otherwise. -func (c *CreateOrUpdateCustomRoleOptions) GetBaseRole() string { +func (c *CreateOrUpdateCustomRepoRoleOptions) GetBaseRole() string { if c == nil || c.BaseRole == nil { return "" } @@ -4359,7 +4359,7 @@ func (c *CreateOrUpdateCustomRoleOptions) GetBaseRole() string { } // GetDescription returns the Description field if it's non-nil, zero value otherwise. -func (c *CreateOrUpdateCustomRoleOptions) GetDescription() string { +func (c *CreateOrUpdateCustomRepoRoleOptions) GetDescription() string { if c == nil || c.Description == nil { return "" } @@ -4367,7 +4367,7 @@ func (c *CreateOrUpdateCustomRoleOptions) GetDescription() string { } // GetName returns the Name field if it's non-nil, zero value otherwise. -func (c *CreateOrUpdateCustomRoleOptions) GetName() string { +func (c *CreateOrUpdateCustomRepoRoleOptions) GetName() string { if c == nil || c.Name == nil { return "" } diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index bbf9fb8422c..0bf17eb8bfe 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -5107,9 +5107,9 @@ func TestCreateOrgInvitationOptions_GetRole(tt *testing.T) { func TestCreateOrUpdateCustomRoleOptions_GetBaseRole(tt *testing.T) { var zeroValue string - c := &CreateOrUpdateCustomRoleOptions{BaseRole: &zeroValue} + c := &CreateOrUpdateCustomRepoRoleOptions{BaseRole: &zeroValue} c.GetBaseRole() - c = &CreateOrUpdateCustomRoleOptions{} + c = &CreateOrUpdateCustomRepoRoleOptions{} c.GetBaseRole() c = nil c.GetBaseRole() @@ -5117,9 +5117,9 @@ func TestCreateOrUpdateCustomRoleOptions_GetBaseRole(tt *testing.T) { func TestCreateOrUpdateCustomRoleOptions_GetDescription(tt *testing.T) { var zeroValue string - c := &CreateOrUpdateCustomRoleOptions{Description: &zeroValue} + c := &CreateOrUpdateCustomRepoRoleOptions{Description: &zeroValue} c.GetDescription() - c = &CreateOrUpdateCustomRoleOptions{} + c = &CreateOrUpdateCustomRepoRoleOptions{} c.GetDescription() c = nil c.GetDescription() @@ -5127,9 +5127,9 @@ func TestCreateOrUpdateCustomRoleOptions_GetDescription(tt *testing.T) { func TestCreateOrUpdateCustomRoleOptions_GetName(tt *testing.T) { var zeroValue string - c := &CreateOrUpdateCustomRoleOptions{Name: &zeroValue} + c := &CreateOrUpdateCustomRepoRoleOptions{Name: &zeroValue} c.GetName() - c = &CreateOrUpdateCustomRoleOptions{} + c = &CreateOrUpdateCustomRepoRoleOptions{} c.GetName() c = nil c.GetName() diff --git a/github/orgs_custom_roles.go b/github/orgs_custom_roles.go index 45de896a2f9..142245c7736 100644 --- a/github/orgs_custom_roles.go +++ b/github/orgs_custom_roles.go @@ -10,6 +10,20 @@ import ( "fmt" ) +// OrganizationCustomRoles represents custom organization roles available in specified organization. +type OrganizationCustomRoles struct { + TotalCount *int `json:"total_count,omitempty"` + CustomRepoRoles []*CustomOrgRoles `json:"roles,omitempty"` +} + +// CustomOrgRoles represents custom organization role available in specified organization. +type CustomOrgRoles struct { + ID *int64 `json:"id,omitempty"` + Name *string `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + Permissions []string `json:"permissions,omitempty"` +} + // OrganizationCustomRepoRoles represents custom repository roles available in specified organization. type OrganizationCustomRepoRoles struct { TotalCount *int `json:"total_count,omitempty"` @@ -27,6 +41,113 @@ type CustomRepoRoles struct { Permissions []string `json:"permissions,omitempty"` } +// CreateOrUpdateOrgRoleOptions represents options required to create or update a custom organization role. +type CreateOrUpdateOrgRoleOptions struct { + Name *string `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + Permissions []string `json:"permissions,omitempty"` +} + +// CreateOrUpdateCustomRepoRoleOptions represents options required to create or update a custom repository role. +type CreateOrUpdateCustomRepoRoleOptions struct { + Name *string `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + BaseRole *string `json:"base_role,omitempty"` + Permissions []string `json:"permissions,omitempty"` +} + +// ListRoles lists the custom roles available in this organization. +// In order to see custom roles in an organization, the authenticated user must be an organization owner. +// +// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/orgs/organization-roles#get-all-organization-roles-for-an-organization +// +//meta:operation GET /orgs/{org}/organization-roles +func (s *OrganizationsService) ListRoles(ctx context.Context, org string) (*OrganizationCustomRoles, *Response, error) { + u := fmt.Sprintf("orgs/%v/organization-roles", org) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + customRepoRoles := new(OrganizationCustomRoles) + resp, err := s.client.Do(ctx, req, customRepoRoles) + if err != nil { + return nil, resp, err + } + + return customRepoRoles, resp, nil +} + +// CreateCustomRole creates a custom role in this organization. +// In order to create custom roles in an organization, the authenticated user must be an organization owner. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/orgs/organization-roles#create-a-custom-organization-role +// +//meta:operation POST /orgs/{org}/organization-roles +func (s *OrganizationsService) CreateCustomOrgRole(ctx context.Context, org string, opts *CreateOrUpdateOrgRoleOptions) (*CustomOrgRoles, *Response, error) { + u := fmt.Sprintf("orgs/%v/organization-roles", org) + + req, err := s.client.NewRequest("POST", u, opts) + if err != nil { + return nil, nil, err + } + + resultingRole := new(CustomOrgRoles) + resp, err := s.client.Do(ctx, req, resultingRole) + if err != nil { + return nil, resp, err + } + + return resultingRole, resp, err +} + +// UpdateCustomPrgRole updates a custom role in this organization. +// In order to update custom roles in an organization, the authenticated user must be an organization owner. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/orgs/organization-roles#update-a-custom-organization-role +// +//meta:operation PATCH /orgs/{org}/organization-roles/{role_id} +func (s *OrganizationsService) UpdateCustomOrgRole(ctx context.Context, org, roleID string, opts *CreateOrUpdateOrgRoleOptions) (*CustomOrgRoles, *Response, error) { + u := fmt.Sprintf("orgs/%v/organization-roles/%v", org, roleID) + + req, err := s.client.NewRequest("PATCH", u, opts) + if err != nil { + return nil, nil, err + } + + resultingRole := new(CustomOrgRoles) + resp, err := s.client.Do(ctx, req, resultingRole) + if err != nil { + return nil, resp, err + } + + return resultingRole, resp, err +} + +// DeleteCustomOrgRole deletes an existing custom role in this organization. +// In order to delete custom roles in an organization, the authenticated user must be an organization owner. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/orgs/organization-roles#delete-a-custom-organization-role +// +//meta:operation DELETE /orgs/{org}/organization-roles/{role_id} +func (s *OrganizationsService) DeleteCustomOrgRole(ctx context.Context, org, roleID string) (*Response, error) { + u := fmt.Sprintf("orgs/%v/organization-roles/%v", org, roleID) + + req, err := s.client.NewRequest("DELETE", u, nil) + if err != nil { + return nil, err + } + + resultingRole := new(CustomOrgRoles) + resp, err := s.client.Do(ctx, req, resultingRole) + if err != nil { + return resp, err + } + + return resp, nil +} + // ListCustomRepoRoles lists the custom repository roles available in this organization. // In order to see custom repository roles in an organization, the authenticated user must be an organization owner. // @@ -50,21 +171,13 @@ func (s *OrganizationsService) ListCustomRepoRoles(ctx context.Context, org stri return customRepoRoles, resp, nil } -// CreateOrUpdateCustomRoleOptions represents options required to create or update a custom repository role. -type CreateOrUpdateCustomRoleOptions struct { - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - BaseRole *string `json:"base_role,omitempty"` - Permissions []string `json:"permissions,omitempty"` -} - // CreateCustomRepoRole creates a custom repository role in this organization. // In order to create custom repository roles in an organization, the authenticated user must be an organization owner. // // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/orgs/custom-roles#create-a-custom-repository-role // //meta:operation POST /orgs/{org}/custom-repository-roles -func (s *OrganizationsService) CreateCustomRepoRole(ctx context.Context, org string, opts *CreateOrUpdateCustomRoleOptions) (*CustomRepoRoles, *Response, error) { +func (s *OrganizationsService) CreateCustomRepoRole(ctx context.Context, org string, opts *CreateOrUpdateCustomRepoRoleOptions) (*CustomRepoRoles, *Response, error) { u := fmt.Sprintf("orgs/%v/custom-repository-roles", org) req, err := s.client.NewRequest("POST", u, opts) @@ -87,7 +200,7 @@ func (s *OrganizationsService) CreateCustomRepoRole(ctx context.Context, org str // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/orgs/custom-roles#update-a-custom-repository-role // //meta:operation PATCH /orgs/{org}/custom-repository-roles/{role_id} -func (s *OrganizationsService) UpdateCustomRepoRole(ctx context.Context, org, roleID string, opts *CreateOrUpdateCustomRoleOptions) (*CustomRepoRoles, *Response, error) { +func (s *OrganizationsService) UpdateCustomRepoRole(ctx context.Context, org, roleID string, opts *CreateOrUpdateCustomRepoRoleOptions) (*CustomRepoRoles, *Response, error) { u := fmt.Sprintf("orgs/%v/custom-repository-roles/%v", org, roleID) req, err := s.client.NewRequest("PATCH", u, opts) diff --git a/github/orgs_custom_roles_test.go b/github/orgs_custom_roles_test.go index 08810909a06..7cb91633b7e 100644 --- a/github/orgs_custom_roles_test.go +++ b/github/orgs_custom_roles_test.go @@ -14,6 +14,151 @@ import ( "github.com/google/go-cmp/cmp" ) +func TestOrganizationsService_ListRoles(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/organization-roles", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"total_count": 1, "roles": [{ "id": 1, "name": "Auditor", "permissions": ["read_audit_logs"]}]}`) + }) + + ctx := context.Background() + apps, _, err := client.Organizations.ListRoles(ctx, "o") + if err != nil { + t.Errorf("Organizations.ListRoles returned error: %v", err) + } + + want := &OrganizationCustomRoles{TotalCount: Int(1), CustomRepoRoles: []*CustomOrgRoles{{ID: Int64(1), Name: String("Auditor"), Permissions: []string{"read_audit_logs"}}}} + if !cmp.Equal(apps, want) { + t.Errorf("Organizations.ListRoles returned %+v, want %+v", apps, want) + } + + const methodName = "ListRoles" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Organizations.ListRoles(ctx, "\no") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Organizations.ListRoles(ctx, "o") + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestOrganizationsService_CreateCustomOrgRole(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/organization-roles", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + fmt.Fprint(w, `{"id":8030,"name":"Reader","description":"A role for reading custom org roles","permissions":["read_organization_custom_org_role"]}`) + }) + + ctx := context.Background() + + opts := &CreateOrUpdateOrgRoleOptions{ + Name: String("Reader"), + Description: String("A role for reading custom org roles"), + Permissions: []string{"read_organization_custom_org_role"}, + } + gotRoles, _, err := client.Organizations.CreateCustomOrgRole(ctx, "o", opts) + if err != nil { + t.Errorf("Organizations.CreateCustomOrgRole returned error: %v", err) + } + + want := &CustomOrgRoles{ID: Int64(8030), Name: String("Reader"), Permissions: []string{"read_organization_custom_org_role"}, Description: String("A role for reading custom org roles")} + + if !cmp.Equal(gotRoles, want) { + t.Errorf("Organizations.CreateCustomOrgRole returned %+v, want %+v", gotRoles, want) + } + + const methodName = "CreateCustomOrgRole" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Organizations.CreateCustomOrgRole(ctx, "\no", nil) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Organizations.CreateCustomOrgRole(ctx, "o", nil) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestOrganizationsService_UpdateCustomOrgRole(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/organization-roles/8030", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PATCH") + fmt.Fprint(w, `{"id":8030,"name":"Updated Name","description":"Updated Description","permissions":["read_organization_custom_org_role"]}`) + }) + + ctx := context.Background() + + opts := &CreateOrUpdateOrgRoleOptions{ + Name: String("Updated Name"), + Description: String("Updated Description"), + } + gotRoles, _, err := client.Organizations.UpdateCustomOrgRole(ctx, "o", "8030", opts) + if err != nil { + t.Errorf("Organizations.UpdateCustomOrgRole returned error: %v", err) + } + + want := &CustomOrgRoles{ID: Int64(8030), Name: String("Updated Name"), Permissions: []string{"read_organization_custom_org_role"}, Description: String("Updated Description")} + + if !cmp.Equal(gotRoles, want) { + t.Errorf("Organizations.UpdateCustomOrgRole returned %+v, want %+v", gotRoles, want) + } + + const methodName = "UpdateCustomOrgRole" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Organizations.UpdateCustomOrgRole(ctx, "\no", "8030", nil) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Organizations.UpdateCustomOrgRole(ctx, "o", "8030", nil) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestOrganizationsService_DeleteCustomOrgRole(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/organization-roles/8030", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + w.WriteHeader(http.StatusNoContent) + }) + + ctx := context.Background() + + resp, err := client.Organizations.DeleteCustomOrgRole(ctx, "o", "8030") + if err != nil { + t.Errorf("Organizations.DeleteCustomOrgRole returned error: %v", err) + } + + if !cmp.Equal(resp.StatusCode, 204) { + t.Errorf("Organizations.DeleteCustomOrgRole returned status code %+v, want %+v", resp.StatusCode, "204") + } + + const methodName = "DeleteCustomOrgRole" + testBadOptions(t, methodName, func() (err error) { + _, err = client.Organizations.DeleteCustomOrgRole(ctx, "\no", "8030") + return err + }) +} + func TestOrganizationsService_ListCustomRepoRoles(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -60,7 +205,7 @@ func TestOrganizationsService_CreateCustomRepoRole(t *testing.T) { ctx := context.Background() - opts := &CreateOrUpdateCustomRoleOptions{ + opts := &CreateOrUpdateCustomRepoRoleOptions{ Name: String("Labeler"), Description: String("A role for issue and PR labelers"), BaseRole: String("read"), @@ -103,7 +248,7 @@ func TestOrganizationsService_UpdateCustomRepoRole(t *testing.T) { ctx := context.Background() - opts := &CreateOrUpdateCustomRoleOptions{ + opts := &CreateOrUpdateCustomRepoRoleOptions{ Name: String("Updated Name"), Description: String("Updated Description"), }