From 65e987389c511554bea5b9f3d4dbe9072f037b6f Mon Sep 17 00:00:00 2001 From: Daniel Liao <10663736+liaodaniel@users.noreply.github.com> Date: Sun, 29 Oct 2023 21:55:03 +1100 Subject: [PATCH 01/12] Create CustomProperty struct --- github/github-accessors.go | 32 ++++++++++++++++++++++++++ github/github-accessors_test.go | 40 +++++++++++++++++++++++++++++++++ github/orgs_properties.go | 17 ++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 github/orgs_properties.go diff --git a/github/github-accessors.go b/github/github-accessors.go index a489d66cd4..51610ce96a 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -4990,6 +4990,38 @@ func (c *CredentialAuthorization) GetTokenLastEight() string { return *c.TokenLastEight } +// GetDefaultValue returns the DefaultValue field if it's non-nil, zero value otherwise. +func (c *CustomProperty) GetDefaultValue() string { + if c == nil || c.DefaultValue == nil { + return "" + } + return *c.DefaultValue +} + +// GetDescription returns the Description field if it's non-nil, zero value otherwise. +func (c *CustomProperty) GetDescription() string { + if c == nil || c.Description == nil { + return "" + } + return *c.Description +} + +// GetPropertyName returns the PropertyName field if it's non-nil, zero value otherwise. +func (c *CustomProperty) GetPropertyName() string { + if c == nil || c.PropertyName == nil { + return "" + } + return *c.PropertyName +} + +// GetRequired returns the Required field if it's non-nil, zero value otherwise. +func (c *CustomProperty) GetRequired() bool { + if c == nil || c.Required == nil { + return false + } + return *c.Required +} + // GetBaseRole returns the BaseRole field if it's non-nil, zero value otherwise. func (c *CustomRepoRoles) GetBaseRole() string { if c == nil || c.BaseRole == nil { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index 2c26fb6ba7..7fae952c6e 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -5899,6 +5899,46 @@ func TestCredentialAuthorization_GetTokenLastEight(tt *testing.T) { c.GetTokenLastEight() } +func TestCustomProperty_GetDefaultValue(tt *testing.T) { + var zeroValue string + c := &CustomProperty{DefaultValue: &zeroValue} + c.GetDefaultValue() + c = &CustomProperty{} + c.GetDefaultValue() + c = nil + c.GetDefaultValue() +} + +func TestCustomProperty_GetDescription(tt *testing.T) { + var zeroValue string + c := &CustomProperty{Description: &zeroValue} + c.GetDescription() + c = &CustomProperty{} + c.GetDescription() + c = nil + c.GetDescription() +} + +func TestCustomProperty_GetPropertyName(tt *testing.T) { + var zeroValue string + c := &CustomProperty{PropertyName: &zeroValue} + c.GetPropertyName() + c = &CustomProperty{} + c.GetPropertyName() + c = nil + c.GetPropertyName() +} + +func TestCustomProperty_GetRequired(tt *testing.T) { + var zeroValue bool + c := &CustomProperty{Required: &zeroValue} + c.GetRequired() + c = &CustomProperty{} + c.GetRequired() + c = nil + c.GetRequired() +} + func TestCustomRepoRoles_GetBaseRole(tt *testing.T) { var zeroValue string c := &CustomRepoRoles{BaseRole: &zeroValue} diff --git a/github/orgs_properties.go b/github/orgs_properties.go new file mode 100644 index 0000000000..138044e720 --- /dev/null +++ b/github/orgs_properties.go @@ -0,0 +1,17 @@ +// Copyright 2023 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +// CustomProperty represents the organization custom property object. +type CustomProperty struct { + PropertyName *string `json:"property_name,omitempty"` + // Possible values for ValueType are: string, single_select + ValueType string `json:"value_type"` + Required *bool `json:"required,omitempty"` + DefaultValue *string `json:"default_value,omitempty"` + Description *string `json:"description,omitempty"` + AllowedValues []string `json:"allowed_values,omitempty"` +} From ecc77c200e0bf66bb9d9ebace873d11791fbdbae Mon Sep 17 00:00:00 2001 From: Daniel Liao <10663736+liaodaniel@users.noreply.github.com> Date: Sun, 29 Oct 2023 23:16:48 +1100 Subject: [PATCH 02/12] Add CreateOrUpdateCustomProperty function --- github/orgs_properties.go | 25 ++++++++++++ github/orgs_properties_test.go | 69 ++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 github/orgs_properties_test.go diff --git a/github/orgs_properties.go b/github/orgs_properties.go index 138044e720..4ad57ca93a 100644 --- a/github/orgs_properties.go +++ b/github/orgs_properties.go @@ -5,6 +5,11 @@ package github +import ( + "context" + "fmt" +) + // CustomProperty represents the organization custom property object. type CustomProperty struct { PropertyName *string `json:"property_name,omitempty"` @@ -15,3 +20,23 @@ type CustomProperty struct { Description *string `json:"description,omitempty"` AllowedValues []string `json:"allowed_values,omitempty"` } + +// CreateOrUpdateCustomProperty creates a new or updates an existing custom property that is defined for the specified organization. +// +// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#create-or-update-a-custom-property-for-an-organization +func (s *OrganizationsService) CreateOrUpdateCustomProperty(ctx context.Context, org, name string, property *CustomProperty) (*CustomProperty, *Response, error) { + u := fmt.Sprintf("orgs/%v/properties/schema/%v", org, name) + + req, err := s.client.NewRequest("PUT", u, property) + if err != nil { + return nil, nil, err + } + + var customProperty *CustomProperty + resp, err := s.client.Do(ctx, req, &customProperty) + if err != nil { + return nil, resp, err + } + + return customProperty, resp, nil +} diff --git a/github/orgs_properties_test.go b/github/orgs_properties_test.go new file mode 100644 index 0000000000..11cc760ff5 --- /dev/null +++ b/github/orgs_properties_test.go @@ -0,0 +1,69 @@ +// Copyright 2023 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "context" + "fmt" + "net/http" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestOrganizationsService_CreateOrUpdateCustomProperty(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/properties/schema/name", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + fmt.Fprint(w, `{ + "property_name": "name", + "value_type": "single_select", + "required": true, + "default_value": "production", + "description": "Prod or dev environment", + "allowed_values":[ + "production", + "development" + ] + }`) + }) + + ctx := context.Background() + property, _, err := client.Organizations.CreateOrUpdateCustomProperty(ctx, "o", "name", &CustomProperty{ + ValueType: "single_select", + Required: Bool(true), + DefaultValue: String("production"), + Description: String("Prod or dev environment"), + AllowedValues: []string{"production", "development"}, + }) + if err != nil { + t.Errorf("Organizations.CreateOrUpdateCustomProperty returned error: %v", err) + } + + want := &CustomProperty{ + PropertyName: String("name"), + ValueType: "single_select", + Required: Bool(true), + DefaultValue: String("production"), + Description: String("Prod or dev environment"), + AllowedValues: []string{"production", "development"}, + } + if !cmp.Equal(property, want) { + t.Errorf("Organizations.CreateOrUpdateCustomProperty returned %+v, want %+v", property, want) + } + + const methodName = "CreateOrUpdateCustomProperty" + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Organizations.CreateOrUpdateCustomProperty(ctx, "o", "name", nil) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} From 93faa5beaed5b0f3615a354b9aab8b3674e795a3 Mon Sep 17 00:00:00 2001 From: Daniel Liao <10663736+liaodaniel@users.noreply.github.com> Date: Sun, 29 Oct 2023 23:29:03 +1100 Subject: [PATCH 03/12] Add GetCustomProperty function --- github/orgs_properties.go | 20 ++++++++++++++ github/orgs_properties_test.go | 48 ++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/github/orgs_properties.go b/github/orgs_properties.go index 4ad57ca93a..597d9463d0 100644 --- a/github/orgs_properties.go +++ b/github/orgs_properties.go @@ -40,3 +40,23 @@ func (s *OrganizationsService) CreateOrUpdateCustomProperty(ctx context.Context, return customProperty, resp, nil } + +// GetCustomProperty gets a custom property that is defined for the specified organization. +// +// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#get-a-custom-property-for-an-organization +func (s *OrganizationsService) GetCustomProperty(ctx context.Context, org, name string) (*CustomProperty, *Response, error) { + u := fmt.Sprintf("orgs/%v/properties/schema/%v", org, name) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var customProperty *CustomProperty + resp, err := s.client.Do(ctx, req, &customProperty) + if err != nil { + return nil, resp, err + } + + return customProperty, resp, nil +} diff --git a/github/orgs_properties_test.go b/github/orgs_properties_test.go index 11cc760ff5..6c098e8f65 100644 --- a/github/orgs_properties_test.go +++ b/github/orgs_properties_test.go @@ -67,3 +67,51 @@ func TestOrganizationsService_CreateOrUpdateCustomProperty(t *testing.T) { return resp, err }) } + +func TestOrganizationsService_GetCustomProperty(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/properties/schema/name", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{ + "property_name": "name", + "value_type": "single_select", + "required": true, + "default_value": "production", + "description": "Prod or dev environment", + "allowed_values":[ + "production", + "development" + ] + }`) + }) + + ctx := context.Background() + property, _, err := client.Organizations.GetCustomProperty(ctx, "o", "name") + if err != nil { + t.Errorf("Organizations.GetCustomProperty returned error: %v", err) + } + + want := &CustomProperty{ + PropertyName: String("name"), + ValueType: "single_select", + Required: Bool(true), + DefaultValue: String("production"), + Description: String("Prod or dev environment"), + AllowedValues: []string{"production", "development"}, + } + if !cmp.Equal(property, want) { + t.Errorf("Organizations.GetCustomProperty returned %+v, want %+v", property, want) + } + + const methodName = "GetCustomProperty" + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Organizations.GetCustomProperty(ctx, "o", "name") + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} From 2f48a7df99084b55d19396fbd2fadc6963ebe5c2 Mon Sep 17 00:00:00 2001 From: Daniel Liao <10663736+liaodaniel@users.noreply.github.com> Date: Sun, 29 Oct 2023 23:35:32 +1100 Subject: [PATCH 04/12] Add RemoveCustomProperty function --- github/orgs_properties.go | 14 ++++++++++++++ github/orgs_properties_test.go | 21 +++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/github/orgs_properties.go b/github/orgs_properties.go index 597d9463d0..3855f6d7c8 100644 --- a/github/orgs_properties.go +++ b/github/orgs_properties.go @@ -60,3 +60,17 @@ func (s *OrganizationsService) GetCustomProperty(ctx context.Context, org, name return customProperty, resp, nil } + +// RemoveCustomProperty removes a custom property that is defined for the specified organization. +// +// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#remove-a-custom-property-for-an-organization +func (s *OrganizationsService) RemoveCustomProperty(ctx context.Context, org, name string) (*Response, error) { + u := fmt.Sprintf("orgs/%v/properties/schema/%v", org, name) + + req, err := s.client.NewRequest("DELETE", u, nil) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} diff --git a/github/orgs_properties_test.go b/github/orgs_properties_test.go index 6c098e8f65..07b736e6f7 100644 --- a/github/orgs_properties_test.go +++ b/github/orgs_properties_test.go @@ -115,3 +115,24 @@ func TestOrganizationsService_GetCustomProperty(t *testing.T) { return resp, err }) } + +func TestOrganizationsService_RemoveCustomProperty(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/properties/schema/name", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + }) + + ctx := context.Background() + _, err := client.Organizations.RemoveCustomProperty(ctx, "o", "name") + if err != nil { + t.Errorf("Organizations.RemoveCustomProperty returned error: %v", err) + } + + const methodName = "RemoveCustomProperty" + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Organizations.RemoveCustomProperty(ctx, "0", "name") + }) +} From 9bda84ceae10d3bea061f7565fbf5b17b4cd3ea8 Mon Sep 17 00:00:00 2001 From: Daniel Liao <10663736+liaodaniel@users.noreply.github.com> Date: Sun, 29 Oct 2023 23:56:53 +1100 Subject: [PATCH 05/12] Add GetAllCustomProperties function --- github/orgs_properties.go | 20 ++++++++++ github/orgs_properties_test.go | 70 ++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/github/orgs_properties.go b/github/orgs_properties.go index 3855f6d7c8..74b2c06323 100644 --- a/github/orgs_properties.go +++ b/github/orgs_properties.go @@ -74,3 +74,23 @@ func (s *OrganizationsService) RemoveCustomProperty(ctx context.Context, org, na return s.client.Do(ctx, req, nil) } + +// GetAllCustomProperties gets all custom properties that is defined for the specified organization. +// +// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#get-all-custom-properties-for-an-organization +func (s *OrganizationsService) GetAllCustomProperties(ctx context.Context, org string) ([]*CustomProperty, *Response, error) { + u := fmt.Sprintf("orgs/%v/properties/schema", org) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var customProperties []*CustomProperty + resp, err := s.client.Do(ctx, req, &customProperties) + if err != nil { + return nil, resp, err + } + + return customProperties, resp, nil +} diff --git a/github/orgs_properties_test.go b/github/orgs_properties_test.go index 07b736e6f7..6891e47b8d 100644 --- a/github/orgs_properties_test.go +++ b/github/orgs_properties_test.go @@ -136,3 +136,73 @@ func TestOrganizationsService_RemoveCustomProperty(t *testing.T) { return client.Organizations.RemoveCustomProperty(ctx, "0", "name") }) } + +func TestOrganizationsService_GetAllCustomProperties(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/properties/schema", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `[ + { + "property_name": "name", + "value_type": "single_select", + "required": true, + "default_value": "production", + "description": "Prod or dev environment", + "allowed_values":[ + "production", + "development" + ] + }, + { + "property_name": "service", + "value_type": "string" + }, + { + "property_name": "team", + "value_type": "string", + "description": "Team owning the repository" + } + ]`) + }) + + ctx := context.Background() + properties, _, err := client.Organizations.GetAllCustomProperties(ctx, "o") + if err != nil { + t.Errorf("Organizations.GetAllCustomProperties returned error: %v", err) + } + + want := []*CustomProperty{ + { + PropertyName: String("name"), + ValueType: "single_select", + Required: Bool(true), + DefaultValue: String("production"), + Description: String("Prod or dev environment"), + AllowedValues: []string{"production", "development"}, + }, + { + PropertyName: String("service"), + ValueType: "string", + }, + { + PropertyName: String("team"), + ValueType: "string", + Description: String("Team owning the repository"), + }, + } + if !cmp.Equal(properties, want) { + t.Errorf("Organizations.GetAllCustomProperties returned %+v, want %+v", properties, want) + } + + const methodName = "GetAllCustomProperties" + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Organizations.GetAllCustomProperties(ctx, "o") + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} From d6c57a401b501c428310422925b90b2d124dca3e Mon Sep 17 00:00:00 2001 From: Daniel Liao <10663736+liaodaniel@users.noreply.github.com> Date: Wed, 1 Nov 2023 00:49:19 +1100 Subject: [PATCH 06/12] Add CreateOrUpdateCustomProperties function --- github/orgs_properties.go | 28 ++++++++++++++- github/orgs_properties_test.go | 63 ++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/github/orgs_properties.go b/github/orgs_properties.go index 74b2c06323..82d3a3860f 100644 --- a/github/orgs_properties.go +++ b/github/orgs_properties.go @@ -10,7 +10,7 @@ import ( "fmt" ) -// CustomProperty represents the organization custom property object. +// CustomProperty represents an organization custom property object. type CustomProperty struct { PropertyName *string `json:"property_name,omitempty"` // Possible values for ValueType are: string, single_select @@ -94,3 +94,29 @@ func (s *OrganizationsService) GetAllCustomProperties(ctx context.Context, org s return customProperties, resp, nil } + +// CreateOrUpdateCustomProperties creates new or updates existing custom properties that are defined for the specified organization. +// +// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#create-or-update-custom-properties-for-an-organization +func (s *OrganizationsService) CreateOrUpdateCustomProperties(ctx context.Context, org string, properties []*CustomProperty) ([]*CustomProperty, *Response, error) { + u := fmt.Sprintf("orgs/%v/properties/schema", org) + + params := struct { + Properties []*CustomProperty `json:"properties"` + }{ + Properties: properties, + } + + req, err := s.client.NewRequest("PATCH", u, params) + if err != nil { + return nil, nil, err + } + + var customProperties []*CustomProperty + resp, err := s.client.Do(ctx, req, &customProperties) + if err != nil { + return nil, resp, err + } + + return customProperties, resp, nil +} diff --git a/github/orgs_properties_test.go b/github/orgs_properties_test.go index 6891e47b8d..2b061c7645 100644 --- a/github/orgs_properties_test.go +++ b/github/orgs_properties_test.go @@ -206,3 +206,66 @@ func TestOrganizationsService_GetAllCustomProperties(t *testing.T) { return resp, err }) } + +func TestOrganizationsService_CreateOrUpdateCustomProperties(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/properties/schema", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PATCH") + testBody(t, r, `{"properties":[{"property_name":"name","value_type":"single_select","required":true},{"property_name":"service","value_type":"string"}]}`+"\n") + fmt.Fprint(w, `[ + { + "property_name": "name", + "value_type": "single_select", + "required": true + }, + { + "property_name": "service", + "value_type": "string" + } + ]`) + }) + + ctx := context.Background() + properties, _, err := client.Organizations.CreateOrUpdateCustomProperties(ctx, "o", []*CustomProperty{ + { + PropertyName: String("name"), + ValueType: "single_select", + Required: Bool(true), + }, + { + PropertyName: String("service"), + ValueType: "string", + }, + }) + if err != nil { + t.Errorf("Organizations.CreateOrUpdateCustomProperties returned error: %v", err) + } + + want := []*CustomProperty{ + { + PropertyName: String("name"), + ValueType: "single_select", + Required: Bool(true), + }, + { + PropertyName: String("service"), + ValueType: "string", + }, + } + + if !cmp.Equal(properties, want) { + t.Errorf("Organizations.CreateOrUpdateCustomProperties returned %+v, want %+v", properties, want) + } + + const methodName = "CreateOrUpdateCustomProperties" + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Organizations.CreateOrUpdateCustomProperties(ctx, "o", nil) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} From d24c1e368f7b994e6e65f23e60bea171a066f913 Mon Sep 17 00:00:00 2001 From: Daniel Liao <10663736+liaodaniel@users.noreply.github.com> Date: Fri, 3 Nov 2023 14:41:25 +1100 Subject: [PATCH 07/12] Add CreateOrUpdateCustomPropertyValuesForRepos function Signed-off-by: Daniel Liao <10663736+liaodaniel@users.noreply.github.com> --- github/orgs_properties.go | 46 ++++++++++++++++++++++++++++++++++ github/orgs_properties_test.go | 22 ++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/github/orgs_properties.go b/github/orgs_properties.go index 82d3a3860f..546f090d77 100644 --- a/github/orgs_properties.go +++ b/github/orgs_properties.go @@ -120,3 +120,49 @@ func (s *OrganizationsService) CreateOrUpdateCustomProperties(ctx context.Contex return customProperties, resp, nil } + +// CreateOrUpdateCustomPropertyValuesForRepos creates new or updates existing custom property values across multiple repositories for the specified organization. +// +// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#create-or-update-custom-property-values-for-organization-repositories +func (s *OrganizationsService) CreateOrUpdateCustomPropertyValuesForRepos(ctx context.Context, org string, repoNames []string, properties []*CustomProperty) (*Response, error) { + u := fmt.Sprintf("orgs/%v/properties/values", org) + + params := struct { + RepositoryNames []string `json:"repository_names"` + Properties []*CustomProperty `json:"properties"` + }{ + RepositoryNames: repoNames, + Properties: properties, + } + + req, err := s.client.NewRequest("PATCH", u, params) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} + +// ListCustomPropertyValues creates new or updates existing custom properties that are defined for the specified organization. +// +// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#list-custom-property-values-for-organization-repositories +func (s *OrganizationsService) ListCustomPropertyValues(ctx context.Context, org string, opts *ListOptions) ([]*CustomProperty, *Response, error) { + u := fmt.Sprintf("orgs/%v/properties/schema", org) + u, err := addOptions(u, opts) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var customProperties []*CustomProperty + resp, err := s.client.Do(ctx, req, &customProperties) + if err != nil { + return nil, resp, err + } + + return customProperties, resp, nil +} diff --git a/github/orgs_properties_test.go b/github/orgs_properties_test.go index 2b061c7645..86a195ece0 100644 --- a/github/orgs_properties_test.go +++ b/github/orgs_properties_test.go @@ -269,3 +269,25 @@ func TestOrganizationsService_CreateOrUpdateCustomProperties(t *testing.T) { return resp, err }) } + +func TestOrganizationsService_CreateOrUpdateCustomPropertyValuesForRepos(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/properties/values", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PATCH") + testBody(t, r, `{"repository_names":["repo"],"properties":[{"property_name":"service","value_type":"string"}]}`+"\n") + }) + + ctx := context.Background() + _, err := client.Organizations.CreateOrUpdateCustomPropertyValuesForRepos(ctx, "o", []string{"repo"}, []*CustomProperty{}) + if err != nil { + t.Errorf("Organizations.CreateOrUpdateCustomPropertyValuesForRepos returned error: %v", err) + } + + const methodName = "CreateOrUpdateCustomPropertyValuesForRepos" + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Organizations.CreateOrUpdateCustomPropertyValuesForRepos(ctx, "o", nil, nil) + }) +} From dc2238b88003506b6070f8b60ca8f4cfab5f65c0 Mon Sep 17 00:00:00 2001 From: Daniel Liao <10663736+liaodaniel@users.noreply.github.com> Date: Sat, 4 Nov 2023 13:12:13 +1100 Subject: [PATCH 08/12] Add ListCustomPropertyValues function Signed-off-by: Daniel Liao <10663736+liaodaniel@users.noreply.github.com> --- github/orgs_properties.go | 24 ++++++++--- github/orgs_properties_test.go | 78 +++++++++++++++++++++++++++++++++- 2 files changed, 96 insertions(+), 6 deletions(-) diff --git a/github/orgs_properties.go b/github/orgs_properties.go index 546f090d77..a449a3047a 100644 --- a/github/orgs_properties.go +++ b/github/orgs_properties.go @@ -21,6 +21,20 @@ type CustomProperty struct { AllowedValues []string `json:"allowed_values,omitempty"` } +// RepoCustomPropertyValue represents a repository custom property value. +type RepoCustomPropertyValue struct { + RepositoryID int64 `json:"repository_id"` + RepositoryName string `json:"repository_name"` + RepositoryFullName string `json:"repository_full_name"` + Properties []*CustomPropertyValue `json:"properties"` +} + +// CustomPropertyValue represents a custom property value. +type CustomPropertyValue struct { + PropertyName string `json:"property_name"` + Value string `json:"value"` +} + // CreateOrUpdateCustomProperty creates a new or updates an existing custom property that is defined for the specified organization. // // GitHub API docs: https://docs.github.com/en/rest/orgs/properties#create-or-update-a-custom-property-for-an-organization @@ -146,8 +160,8 @@ func (s *OrganizationsService) CreateOrUpdateCustomPropertyValuesForRepos(ctx co // ListCustomPropertyValues creates new or updates existing custom properties that are defined for the specified organization. // // GitHub API docs: https://docs.github.com/en/rest/orgs/properties#list-custom-property-values-for-organization-repositories -func (s *OrganizationsService) ListCustomPropertyValues(ctx context.Context, org string, opts *ListOptions) ([]*CustomProperty, *Response, error) { - u := fmt.Sprintf("orgs/%v/properties/schema", org) +func (s *OrganizationsService) ListCustomPropertyValues(ctx context.Context, org string, opts *ListOptions) ([]*RepoCustomPropertyValue, *Response, error) { + u := fmt.Sprintf("orgs/%v/properties/values", org) u, err := addOptions(u, opts) if err != nil { return nil, nil, err @@ -158,11 +172,11 @@ func (s *OrganizationsService) ListCustomPropertyValues(ctx context.Context, org return nil, nil, err } - var customProperties []*CustomProperty - resp, err := s.client.Do(ctx, req, &customProperties) + var repoCustomPropertyValues []*RepoCustomPropertyValue + resp, err := s.client.Do(ctx, req, &repoCustomPropertyValues) if err != nil { return nil, resp, err } - return customProperties, resp, nil + return repoCustomPropertyValues, resp, nil } diff --git a/github/orgs_properties_test.go b/github/orgs_properties_test.go index 86a195ece0..f66dca0f8d 100644 --- a/github/orgs_properties_test.go +++ b/github/orgs_properties_test.go @@ -280,7 +280,12 @@ func TestOrganizationsService_CreateOrUpdateCustomPropertyValuesForRepos(t *test }) ctx := context.Background() - _, err := client.Organizations.CreateOrUpdateCustomPropertyValuesForRepos(ctx, "o", []string{"repo"}, []*CustomProperty{}) + _, err := client.Organizations.CreateOrUpdateCustomPropertyValuesForRepos(ctx, "o", []string{"repo"}, []*CustomProperty{ + { + PropertyName: String("service"), + ValueType: "string", + }, + }) if err != nil { t.Errorf("Organizations.CreateOrUpdateCustomPropertyValuesForRepos returned error: %v", err) } @@ -291,3 +296,74 @@ func TestOrganizationsService_CreateOrUpdateCustomPropertyValuesForRepos(t *test return client.Organizations.CreateOrUpdateCustomPropertyValuesForRepos(ctx, "o", nil, nil) }) } + +func TestOrganizationsService_ListCustomPropertyValues(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/properties/values", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{"page": "1", "per_page": "100"}) + fmt.Fprint(w, `[{ + "repository_id": 1296269, + "repository_name": "Hello-World", + "repository_full_name": "octocat/Hello-World", + "properties": [ + { + "property_name": "environment", + "value": "production" + }, + { + "property_name": "service", + "value": "web" + } + ] + }]`) + }) + + ctx := context.Background() + repoPropertyValues, _, err := client.Organizations.ListCustomPropertyValues(ctx, "o", &ListOptions{ + Page: 1, + PerPage: 100, + }) + if err != nil { + t.Errorf("Organizations.ListCustomPropertyValues returned error: %v", err) + } + + want := []*RepoCustomPropertyValue{ + { + RepositoryID: 1296269, + RepositoryName: "Hello-World", + RepositoryFullName: "octocat/Hello-World", + Properties: []*CustomPropertyValue{ + { + PropertyName: "environment", + Value: "production", + }, + { + PropertyName: "service", + Value: "web", + }, + }, + }, + } + + if !cmp.Equal(repoPropertyValues, want) { + t.Errorf("Organizations.ListCustomPropertyValues returned %+v, want %+v", repoPropertyValues, want) + } + + const methodName = "ListCustomPropertyValues" + + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Organizations.ListCustomPropertyValues(ctx, "\n", &ListOptions{}) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Organizations.ListCustomPropertyValues(ctx, "o", nil) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} From 05782e52c38b3daf2ecaf55bcaa54e262b67c24b Mon Sep 17 00:00:00 2001 From: Daniel Liao <10663736+liaodaniel@users.noreply.github.com> Date: Sat, 4 Nov 2023 13:23:59 +1100 Subject: [PATCH 09/12] Match the ordering with the API docs Signed-off-by: Daniel Liao <10663736+liaodaniel@users.noreply.github.com> --- github/orgs_properties.go | 128 ++++++++-------- github/orgs_properties_test.go | 270 ++++++++++++++++----------------- 2 files changed, 199 insertions(+), 199 deletions(-) diff --git a/github/orgs_properties.go b/github/orgs_properties.go index a449a3047a..2fae28bb2d 100644 --- a/github/orgs_properties.go +++ b/github/orgs_properties.go @@ -35,121 +35,99 @@ type CustomPropertyValue struct { Value string `json:"value"` } -// CreateOrUpdateCustomProperty creates a new or updates an existing custom property that is defined for the specified organization. +// GetAllCustomProperties gets all custom properties that is defined for the specified organization. // -// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#create-or-update-a-custom-property-for-an-organization -func (s *OrganizationsService) CreateOrUpdateCustomProperty(ctx context.Context, org, name string, property *CustomProperty) (*CustomProperty, *Response, error) { - u := fmt.Sprintf("orgs/%v/properties/schema/%v", org, name) +// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#get-all-custom-properties-for-an-organization +func (s *OrganizationsService) GetAllCustomProperties(ctx context.Context, org string) ([]*CustomProperty, *Response, error) { + u := fmt.Sprintf("orgs/%v/properties/schema", org) - req, err := s.client.NewRequest("PUT", u, property) + req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err } - var customProperty *CustomProperty - resp, err := s.client.Do(ctx, req, &customProperty) + var customProperties []*CustomProperty + resp, err := s.client.Do(ctx, req, &customProperties) if err != nil { return nil, resp, err } - return customProperty, resp, nil + return customProperties, resp, nil } -// GetCustomProperty gets a custom property that is defined for the specified organization. +// CreateOrUpdateCustomProperties creates new or updates existing custom properties that are defined for the specified organization. // -// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#get-a-custom-property-for-an-organization -func (s *OrganizationsService) GetCustomProperty(ctx context.Context, org, name string) (*CustomProperty, *Response, error) { - u := fmt.Sprintf("orgs/%v/properties/schema/%v", org, name) +// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#create-or-update-custom-properties-for-an-organization +func (s *OrganizationsService) CreateOrUpdateCustomProperties(ctx context.Context, org string, properties []*CustomProperty) ([]*CustomProperty, *Response, error) { + u := fmt.Sprintf("orgs/%v/properties/schema", org) - req, err := s.client.NewRequest("GET", u, nil) + params := struct { + Properties []*CustomProperty `json:"properties"` + }{ + Properties: properties, + } + + req, err := s.client.NewRequest("PATCH", u, params) if err != nil { return nil, nil, err } - var customProperty *CustomProperty - resp, err := s.client.Do(ctx, req, &customProperty) + var customProperties []*CustomProperty + resp, err := s.client.Do(ctx, req, &customProperties) if err != nil { return nil, resp, err } - return customProperty, resp, nil + return customProperties, resp, nil } -// RemoveCustomProperty removes a custom property that is defined for the specified organization. +// GetCustomProperty gets a custom property that is defined for the specified organization. // -// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#remove-a-custom-property-for-an-organization -func (s *OrganizationsService) RemoveCustomProperty(ctx context.Context, org, name string) (*Response, error) { +// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#get-a-custom-property-for-an-organization +func (s *OrganizationsService) GetCustomProperty(ctx context.Context, org, name string) (*CustomProperty, *Response, error) { u := fmt.Sprintf("orgs/%v/properties/schema/%v", org, name) - req, err := s.client.NewRequest("DELETE", u, nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -// GetAllCustomProperties gets all custom properties that is defined for the specified organization. -// -// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#get-all-custom-properties-for-an-organization -func (s *OrganizationsService) GetAllCustomProperties(ctx context.Context, org string) ([]*CustomProperty, *Response, error) { - u := fmt.Sprintf("orgs/%v/properties/schema", org) - req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err } - var customProperties []*CustomProperty - resp, err := s.client.Do(ctx, req, &customProperties) + var customProperty *CustomProperty + resp, err := s.client.Do(ctx, req, &customProperty) if err != nil { return nil, resp, err } - return customProperties, resp, nil + return customProperty, resp, nil } -// CreateOrUpdateCustomProperties creates new or updates existing custom properties that are defined for the specified organization. +// CreateOrUpdateCustomProperty creates a new or updates an existing custom property that is defined for the specified organization. // -// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#create-or-update-custom-properties-for-an-organization -func (s *OrganizationsService) CreateOrUpdateCustomProperties(ctx context.Context, org string, properties []*CustomProperty) ([]*CustomProperty, *Response, error) { - u := fmt.Sprintf("orgs/%v/properties/schema", org) - - params := struct { - Properties []*CustomProperty `json:"properties"` - }{ - Properties: properties, - } +// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#create-or-update-a-custom-property-for-an-organization +func (s *OrganizationsService) CreateOrUpdateCustomProperty(ctx context.Context, org, name string, property *CustomProperty) (*CustomProperty, *Response, error) { + u := fmt.Sprintf("orgs/%v/properties/schema/%v", org, name) - req, err := s.client.NewRequest("PATCH", u, params) + req, err := s.client.NewRequest("PUT", u, property) if err != nil { return nil, nil, err } - var customProperties []*CustomProperty - resp, err := s.client.Do(ctx, req, &customProperties) + var customProperty *CustomProperty + resp, err := s.client.Do(ctx, req, &customProperty) if err != nil { return nil, resp, err } - return customProperties, resp, nil + return customProperty, resp, nil } -// CreateOrUpdateCustomPropertyValuesForRepos creates new or updates existing custom property values across multiple repositories for the specified organization. +// RemoveCustomProperty removes a custom property that is defined for the specified organization. // -// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#create-or-update-custom-property-values-for-organization-repositories -func (s *OrganizationsService) CreateOrUpdateCustomPropertyValuesForRepos(ctx context.Context, org string, repoNames []string, properties []*CustomProperty) (*Response, error) { - u := fmt.Sprintf("orgs/%v/properties/values", org) - - params := struct { - RepositoryNames []string `json:"repository_names"` - Properties []*CustomProperty `json:"properties"` - }{ - RepositoryNames: repoNames, - Properties: properties, - } +// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#remove-a-custom-property-for-an-organization +func (s *OrganizationsService) RemoveCustomProperty(ctx context.Context, org, name string) (*Response, error) { + u := fmt.Sprintf("orgs/%v/properties/schema/%v", org, name) - req, err := s.client.NewRequest("PATCH", u, params) + req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err } @@ -157,7 +135,7 @@ func (s *OrganizationsService) CreateOrUpdateCustomPropertyValuesForRepos(ctx co return s.client.Do(ctx, req, nil) } -// ListCustomPropertyValues creates new or updates existing custom properties that are defined for the specified organization. +// ListCustomPropertyValues lists all custom property values for repositories in the specified organization. // // GitHub API docs: https://docs.github.com/en/rest/orgs/properties#list-custom-property-values-for-organization-repositories func (s *OrganizationsService) ListCustomPropertyValues(ctx context.Context, org string, opts *ListOptions) ([]*RepoCustomPropertyValue, *Response, error) { @@ -180,3 +158,25 @@ func (s *OrganizationsService) ListCustomPropertyValues(ctx context.Context, org return repoCustomPropertyValues, resp, nil } + +// CreateOrUpdateRepoCustomPropertyValues creates new or updates existing custom property values across multiple repositories for the specified organization. +// +// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#create-or-update-custom-property-values-for-organization-repositories +func (s *OrganizationsService) CreateOrUpdateRepoCustomPropertyValues(ctx context.Context, org string, repoNames []string, properties []*CustomProperty) (*Response, error) { + u := fmt.Sprintf("orgs/%v/properties/values", org) + + params := struct { + RepositoryNames []string `json:"repository_names"` + Properties []*CustomProperty `json:"properties"` + }{ + RepositoryNames: repoNames, + Properties: properties, + } + + req, err := s.client.NewRequest("PATCH", u, params) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} diff --git a/github/orgs_properties_test.go b/github/orgs_properties_test.go index f66dca0f8d..a729d8577e 100644 --- a/github/orgs_properties_test.go +++ b/github/orgs_properties_test.go @@ -14,129 +14,6 @@ import ( "github.com/google/go-cmp/cmp" ) -func TestOrganizationsService_CreateOrUpdateCustomProperty(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/orgs/o/properties/schema/name", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PUT") - fmt.Fprint(w, `{ - "property_name": "name", - "value_type": "single_select", - "required": true, - "default_value": "production", - "description": "Prod or dev environment", - "allowed_values":[ - "production", - "development" - ] - }`) - }) - - ctx := context.Background() - property, _, err := client.Organizations.CreateOrUpdateCustomProperty(ctx, "o", "name", &CustomProperty{ - ValueType: "single_select", - Required: Bool(true), - DefaultValue: String("production"), - Description: String("Prod or dev environment"), - AllowedValues: []string{"production", "development"}, - }) - if err != nil { - t.Errorf("Organizations.CreateOrUpdateCustomProperty returned error: %v", err) - } - - want := &CustomProperty{ - PropertyName: String("name"), - ValueType: "single_select", - Required: Bool(true), - DefaultValue: String("production"), - Description: String("Prod or dev environment"), - AllowedValues: []string{"production", "development"}, - } - if !cmp.Equal(property, want) { - t.Errorf("Organizations.CreateOrUpdateCustomProperty returned %+v, want %+v", property, want) - } - - const methodName = "CreateOrUpdateCustomProperty" - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Organizations.CreateOrUpdateCustomProperty(ctx, "o", "name", nil) - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} - -func TestOrganizationsService_GetCustomProperty(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/orgs/o/properties/schema/name", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `{ - "property_name": "name", - "value_type": "single_select", - "required": true, - "default_value": "production", - "description": "Prod or dev environment", - "allowed_values":[ - "production", - "development" - ] - }`) - }) - - ctx := context.Background() - property, _, err := client.Organizations.GetCustomProperty(ctx, "o", "name") - if err != nil { - t.Errorf("Organizations.GetCustomProperty returned error: %v", err) - } - - want := &CustomProperty{ - PropertyName: String("name"), - ValueType: "single_select", - Required: Bool(true), - DefaultValue: String("production"), - Description: String("Prod or dev environment"), - AllowedValues: []string{"production", "development"}, - } - if !cmp.Equal(property, want) { - t.Errorf("Organizations.GetCustomProperty returned %+v, want %+v", property, want) - } - - const methodName = "GetCustomProperty" - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Organizations.GetCustomProperty(ctx, "o", "name") - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} - -func TestOrganizationsService_RemoveCustomProperty(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/orgs/o/properties/schema/name", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "DELETE") - }) - - ctx := context.Background() - _, err := client.Organizations.RemoveCustomProperty(ctx, "o", "name") - if err != nil { - t.Errorf("Organizations.RemoveCustomProperty returned error: %v", err) - } - - const methodName = "RemoveCustomProperty" - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Organizations.RemoveCustomProperty(ctx, "0", "name") - }) -} - func TestOrganizationsService_GetAllCustomProperties(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -270,30 +147,126 @@ func TestOrganizationsService_CreateOrUpdateCustomProperties(t *testing.T) { }) } -func TestOrganizationsService_CreateOrUpdateCustomPropertyValuesForRepos(t *testing.T) { +func TestOrganizationsService_GetCustomProperty(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/orgs/o/properties/values", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PATCH") - testBody(t, r, `{"repository_names":["repo"],"properties":[{"property_name":"service","value_type":"string"}]}`+"\n") + mux.HandleFunc("/orgs/o/properties/schema/name", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{ + "property_name": "name", + "value_type": "single_select", + "required": true, + "default_value": "production", + "description": "Prod or dev environment", + "allowed_values":[ + "production", + "development" + ] + }`) }) ctx := context.Background() - _, err := client.Organizations.CreateOrUpdateCustomPropertyValuesForRepos(ctx, "o", []string{"repo"}, []*CustomProperty{ - { - PropertyName: String("service"), - ValueType: "string", - }, + property, _, err := client.Organizations.GetCustomProperty(ctx, "o", "name") + if err != nil { + t.Errorf("Organizations.GetCustomProperty returned error: %v", err) + } + + want := &CustomProperty{ + PropertyName: String("name"), + ValueType: "single_select", + Required: Bool(true), + DefaultValue: String("production"), + Description: String("Prod or dev environment"), + AllowedValues: []string{"production", "development"}, + } + if !cmp.Equal(property, want) { + t.Errorf("Organizations.GetCustomProperty returned %+v, want %+v", property, want) + } + + const methodName = "GetCustomProperty" + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Organizations.GetCustomProperty(ctx, "o", "name") + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestOrganizationsService_CreateOrUpdateCustomProperty(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/properties/schema/name", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + fmt.Fprint(w, `{ + "property_name": "name", + "value_type": "single_select", + "required": true, + "default_value": "production", + "description": "Prod or dev environment", + "allowed_values":[ + "production", + "development" + ] + }`) + }) + + ctx := context.Background() + property, _, err := client.Organizations.CreateOrUpdateCustomProperty(ctx, "o", "name", &CustomProperty{ + ValueType: "single_select", + Required: Bool(true), + DefaultValue: String("production"), + Description: String("Prod or dev environment"), + AllowedValues: []string{"production", "development"}, }) if err != nil { - t.Errorf("Organizations.CreateOrUpdateCustomPropertyValuesForRepos returned error: %v", err) + t.Errorf("Organizations.CreateOrUpdateCustomProperty returned error: %v", err) } - const methodName = "CreateOrUpdateCustomPropertyValuesForRepos" + want := &CustomProperty{ + PropertyName: String("name"), + ValueType: "single_select", + Required: Bool(true), + DefaultValue: String("production"), + Description: String("Prod or dev environment"), + AllowedValues: []string{"production", "development"}, + } + if !cmp.Equal(property, want) { + t.Errorf("Organizations.CreateOrUpdateCustomProperty returned %+v, want %+v", property, want) + } + + const methodName = "CreateOrUpdateCustomProperty" + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Organizations.CreateOrUpdateCustomProperty(ctx, "o", "name", nil) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestOrganizationsService_RemoveCustomProperty(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/properties/schema/name", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + }) + + ctx := context.Background() + _, err := client.Organizations.RemoveCustomProperty(ctx, "o", "name") + if err != nil { + t.Errorf("Organizations.RemoveCustomProperty returned error: %v", err) + } + + const methodName = "RemoveCustomProperty" testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Organizations.CreateOrUpdateCustomPropertyValuesForRepos(ctx, "o", nil, nil) + return client.Organizations.RemoveCustomProperty(ctx, "0", "name") }) } @@ -367,3 +340,30 @@ func TestOrganizationsService_ListCustomPropertyValues(t *testing.T) { return resp, err }) } + +func TestOrganizationsService_CreateOrUpdateRepoCustomPropertyValues(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/properties/values", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PATCH") + testBody(t, r, `{"repository_names":["repo"],"properties":[{"property_name":"service","value_type":"string"}]}`+"\n") + }) + + ctx := context.Background() + _, err := client.Organizations.CreateOrUpdateRepoCustomPropertyValues(ctx, "o", []string{"repo"}, []*CustomProperty{ + { + PropertyName: String("service"), + ValueType: "string", + }, + }) + if err != nil { + t.Errorf("Organizations.CreateOrUpdateCustomPropertyValuesForRepos returned error: %v", err) + } + + const methodName = "CreateOrUpdateCustomPropertyValuesForRepos" + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Organizations.CreateOrUpdateRepoCustomPropertyValues(ctx, "o", nil, nil) + }) +} From 0b1aa7b34ab2b07c3b4bc7c5879c27f8cea2351f Mon Sep 17 00:00:00 2001 From: Daniel Liao <10663736+liaodaniel@users.noreply.github.com> Date: Sat, 4 Nov 2023 13:46:02 +1100 Subject: [PATCH 10/12] Add openapi metadata Signed-off-by: Daniel Liao <10663736+liaodaniel@users.noreply.github.com> --- github/orgs_properties.go | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/github/orgs_properties.go b/github/orgs_properties.go index 2fae28bb2d..292ba1c964 100644 --- a/github/orgs_properties.go +++ b/github/orgs_properties.go @@ -37,7 +37,9 @@ type CustomPropertyValue struct { // GetAllCustomProperties gets all custom properties that is defined for the specified organization. // -// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#get-all-custom-properties-for-an-organization +// GitHub API docs: https://docs.github.com/rest/orgs/properties#get-all-custom-properties-for-an-organization +// +//meta:operation GET /orgs/{org}/properties/schema func (s *OrganizationsService) GetAllCustomProperties(ctx context.Context, org string) ([]*CustomProperty, *Response, error) { u := fmt.Sprintf("orgs/%v/properties/schema", org) @@ -57,7 +59,9 @@ func (s *OrganizationsService) GetAllCustomProperties(ctx context.Context, org s // CreateOrUpdateCustomProperties creates new or updates existing custom properties that are defined for the specified organization. // -// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#create-or-update-custom-properties-for-an-organization +// GitHub API docs: https://docs.github.com/rest/orgs/properties#create-or-update-custom-properties-for-an-organization +// +//meta:operation PATCH /orgs/{org}/properties/schema func (s *OrganizationsService) CreateOrUpdateCustomProperties(ctx context.Context, org string, properties []*CustomProperty) ([]*CustomProperty, *Response, error) { u := fmt.Sprintf("orgs/%v/properties/schema", org) @@ -83,7 +87,9 @@ func (s *OrganizationsService) CreateOrUpdateCustomProperties(ctx context.Contex // GetCustomProperty gets a custom property that is defined for the specified organization. // -// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#get-a-custom-property-for-an-organization +// GitHub API docs: https://docs.github.com/rest/orgs/properties#get-a-custom-property-for-an-organization +// +//meta:operation GET /orgs/{org}/properties/schema/{custom_property_name} func (s *OrganizationsService) GetCustomProperty(ctx context.Context, org, name string) (*CustomProperty, *Response, error) { u := fmt.Sprintf("orgs/%v/properties/schema/%v", org, name) @@ -103,7 +109,9 @@ func (s *OrganizationsService) GetCustomProperty(ctx context.Context, org, name // CreateOrUpdateCustomProperty creates a new or updates an existing custom property that is defined for the specified organization. // -// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#create-or-update-a-custom-property-for-an-organization +// GitHub API docs: https://docs.github.com/rest/orgs/properties#create-or-update-a-custom-property-for-an-organization +// +//meta:operation PUT /orgs/{org}/properties/schema/{custom_property_name} func (s *OrganizationsService) CreateOrUpdateCustomProperty(ctx context.Context, org, name string, property *CustomProperty) (*CustomProperty, *Response, error) { u := fmt.Sprintf("orgs/%v/properties/schema/%v", org, name) @@ -123,7 +131,9 @@ func (s *OrganizationsService) CreateOrUpdateCustomProperty(ctx context.Context, // RemoveCustomProperty removes a custom property that is defined for the specified organization. // -// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#remove-a-custom-property-for-an-organization +// GitHub API docs: https://docs.github.com/rest/orgs/properties#remove-a-custom-property-for-an-organization +// +//meta:operation DELETE /orgs/{org}/properties/schema/{custom_property_name} func (s *OrganizationsService) RemoveCustomProperty(ctx context.Context, org, name string) (*Response, error) { u := fmt.Sprintf("orgs/%v/properties/schema/%v", org, name) @@ -137,7 +147,9 @@ func (s *OrganizationsService) RemoveCustomProperty(ctx context.Context, org, na // ListCustomPropertyValues lists all custom property values for repositories in the specified organization. // -// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#list-custom-property-values-for-organization-repositories +// GitHub API docs: https://docs.github.com/rest/orgs/properties#list-custom-property-values-for-organization-repositories +// +//meta:operation GET /orgs/{org}/properties/values func (s *OrganizationsService) ListCustomPropertyValues(ctx context.Context, org string, opts *ListOptions) ([]*RepoCustomPropertyValue, *Response, error) { u := fmt.Sprintf("orgs/%v/properties/values", org) u, err := addOptions(u, opts) @@ -161,7 +173,9 @@ func (s *OrganizationsService) ListCustomPropertyValues(ctx context.Context, org // CreateOrUpdateRepoCustomPropertyValues creates new or updates existing custom property values across multiple repositories for the specified organization. // -// GitHub API docs: https://docs.github.com/en/rest/orgs/properties#create-or-update-custom-property-values-for-organization-repositories +// GitHub API docs: https://docs.github.com/rest/orgs/properties#create-or-update-custom-property-values-for-organization-repositories +// +//meta:operation PATCH /orgs/{org}/properties/values func (s *OrganizationsService) CreateOrUpdateRepoCustomPropertyValues(ctx context.Context, org string, repoNames []string, properties []*CustomProperty) (*Response, error) { u := fmt.Sprintf("orgs/%v/properties/values", org) From 2967adce121b6db0629f871fc0aaab5eb5758a68 Mon Sep 17 00:00:00 2001 From: Daniel Liao <10663736+liaodaniel@users.noreply.github.com> Date: Mon, 6 Nov 2023 17:22:30 +1100 Subject: [PATCH 11/12] Address the PR comments Signed-off-by: Daniel Liao <10663736+liaodaniel@users.noreply.github.com> --- github/github-accessors.go | 8 ++++++++ github/github-accessors_test.go | 10 ++++++++++ github/orgs_properties.go | 14 +++++++------- github/orgs_properties_test.go | 4 ++-- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/github/github-accessors.go b/github/github-accessors.go index 51610ce96a..da15d45160 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -5022,6 +5022,14 @@ func (c *CustomProperty) GetRequired() bool { return *c.Required } +// GetValue returns the Value field if it's non-nil, zero value otherwise. +func (c *CustomPropertyValue) GetValue() string { + if c == nil || c.Value == nil { + return "" + } + return *c.Value +} + // GetBaseRole returns the BaseRole field if it's non-nil, zero value otherwise. func (c *CustomRepoRoles) GetBaseRole() string { if c == nil || c.BaseRole == nil { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index 7fae952c6e..cdb5370bdb 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -5939,6 +5939,16 @@ func TestCustomProperty_GetRequired(tt *testing.T) { c.GetRequired() } +func TestCustomPropertyValue_GetValue(tt *testing.T) { + var zeroValue string + c := &CustomPropertyValue{Value: &zeroValue} + c.GetValue() + c = &CustomPropertyValue{} + c.GetValue() + c = nil + c.GetValue() +} + func TestCustomRepoRoles_GetBaseRole(tt *testing.T) { var zeroValue string c := &CustomRepoRoles{BaseRole: &zeroValue} diff --git a/github/orgs_properties.go b/github/orgs_properties.go index 292ba1c964..6933c0e41d 100644 --- a/github/orgs_properties.go +++ b/github/orgs_properties.go @@ -31,11 +31,11 @@ type RepoCustomPropertyValue struct { // CustomPropertyValue represents a custom property value. type CustomPropertyValue struct { - PropertyName string `json:"property_name"` - Value string `json:"value"` + PropertyName string `json:"property_name"` + Value *string `json:"value,omitempty"` } -// GetAllCustomProperties gets all custom properties that is defined for the specified organization. +// GetAllCustomProperties gets all custom properties that are defined for the specified organization. // // GitHub API docs: https://docs.github.com/rest/orgs/properties#get-all-custom-properties-for-an-organization // @@ -112,8 +112,8 @@ func (s *OrganizationsService) GetCustomProperty(ctx context.Context, org, name // GitHub API docs: https://docs.github.com/rest/orgs/properties#create-or-update-a-custom-property-for-an-organization // //meta:operation PUT /orgs/{org}/properties/schema/{custom_property_name} -func (s *OrganizationsService) CreateOrUpdateCustomProperty(ctx context.Context, org, name string, property *CustomProperty) (*CustomProperty, *Response, error) { - u := fmt.Sprintf("orgs/%v/properties/schema/%v", org, name) +func (s *OrganizationsService) CreateOrUpdateCustomProperty(ctx context.Context, org, customPropertyName string, property *CustomProperty) (*CustomProperty, *Response, error) { + u := fmt.Sprintf("orgs/%v/properties/schema/%v", org, customPropertyName) req, err := s.client.NewRequest("PUT", u, property) if err != nil { @@ -134,8 +134,8 @@ func (s *OrganizationsService) CreateOrUpdateCustomProperty(ctx context.Context, // GitHub API docs: https://docs.github.com/rest/orgs/properties#remove-a-custom-property-for-an-organization // //meta:operation DELETE /orgs/{org}/properties/schema/{custom_property_name} -func (s *OrganizationsService) RemoveCustomProperty(ctx context.Context, org, name string) (*Response, error) { - u := fmt.Sprintf("orgs/%v/properties/schema/%v", org, name) +func (s *OrganizationsService) RemoveCustomProperty(ctx context.Context, org, customPropertyName string) (*Response, error) { + u := fmt.Sprintf("orgs/%v/properties/schema/%v", org, customPropertyName) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { diff --git a/github/orgs_properties_test.go b/github/orgs_properties_test.go index a729d8577e..1a37230604 100644 --- a/github/orgs_properties_test.go +++ b/github/orgs_properties_test.go @@ -311,11 +311,11 @@ func TestOrganizationsService_ListCustomPropertyValues(t *testing.T) { Properties: []*CustomPropertyValue{ { PropertyName: "environment", - Value: "production", + Value: String("production"), }, { PropertyName: "service", - Value: "web", + Value: String("web"), }, }, }, From 756900a0f2622ce740a1387569cf51b4c083fd54 Mon Sep 17 00:00:00 2001 From: Daniel Liao <10663736+liaodaniel@users.noreply.github.com> Date: Tue, 7 Nov 2023 21:55:05 +1100 Subject: [PATCH 12/12] Comment on PropertyName as pointer with omitempty --- github/orgs_properties.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/github/orgs_properties.go b/github/orgs_properties.go index 6933c0e41d..1daac81180 100644 --- a/github/orgs_properties.go +++ b/github/orgs_properties.go @@ -12,6 +12,8 @@ import ( // CustomProperty represents an organization custom property object. type CustomProperty struct { + // PropertyName is required for most endpoints except when calling CreateOrUpdateCustomProperty; + // where this is sent in the path and thus can be omitted. PropertyName *string `json:"property_name,omitempty"` // Possible values for ValueType are: string, single_select ValueType string `json:"value_type"`