Skip to content

Commit

Permalink
Support querying organization custom roles
Browse files Browse the repository at this point in the history
Added support for querying, creating, updating and deleting organization
custom roles.
  • Loading branch information
tomfeigin committed Apr 16, 2024
1 parent a6806bc commit 1e8c944
Show file tree
Hide file tree
Showing 4 changed files with 279 additions and 21 deletions.
6 changes: 3 additions & 3 deletions github/github-accessors.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions github/github-accessors_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

133 changes: 123 additions & 10 deletions github/orgs_custom_roles.go
Expand Up @@ -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"`
Expand All @@ -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.

Check failure on line 82 in github/orgs_custom_roles.go

View workflow job for this annotation

GitHub Actions / lint

ST1020: comment on exported method CreateCustomOrgRole should be of the form "CreateCustomOrgRole ..." (stylecheck)
// 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.

Check failure on line 105 in github/orgs_custom_roles.go

View workflow job for this annotation

GitHub Actions / lint

ST1020: comment on exported method UpdateCustomOrgRole should be of the form "UpdateCustomOrgRole ..." (stylecheck)
// 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

Check warning on line 145 in github/orgs_custom_roles.go

View check run for this annotation

Codecov / codecov/patch

github/orgs_custom_roles.go#L145

Added line #L145 was not covered by tests
}

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.
//
Expand All @@ -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)
Expand All @@ -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)
Expand Down
149 changes: 147 additions & 2 deletions github/orgs_custom_roles_test.go
Expand Up @@ -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()
Expand Down Expand Up @@ -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"),
Expand Down Expand Up @@ -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"),
}
Expand Down

0 comments on commit 1e8c944

Please sign in to comment.