diff --git a/github/enterprise_organization_properties.go b/github/enterprise_organization_properties.go new file mode 100644 index 00000000000..01a646b38aa --- /dev/null +++ b/github/enterprise_organization_properties.go @@ -0,0 +1,189 @@ +// Copyright 2025 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" +) + +// EnterpriseCustomPropertySchema represents the schema response for GetEnterpriseCustomPropertiesSchema. +type EnterpriseCustomPropertySchema struct { + // An ordered list of the custom property defined in the enterprise. + Properties []*CustomProperty `json:"properties,omitempty"` +} + +// EnterpriseCustomPropertiesValues represents the custom properties values for an organization within an enterprise. +type EnterpriseCustomPropertiesValues struct { + // The Organization ID that the custom property values will be applied to. + OrganizationID *int64 `json:"organization_id,omitempty"` + // The names of organizations that the custom property values will be applied to. + OrganizationLogin *string `json:"organization_login,omitempty"` + // List of custom property names and associated values to apply to the organizations. + Properties []*CustomPropertyValue `json:"properties,omitempty"` +} + +// EnterpriseCustomPropertyValuesRequest represents the request to update custom property values for organizations within an enterprise. +type EnterpriseCustomPropertyValuesRequest struct { + // The names of organizations that the custom property values will be applied to. + // OrganizationLogin specifies the organization name when updating multiple organizations. + OrganizationLogin []string `json:"organization_login"` + // List of custom property names and associated values to apply to the organizations. + Properties []*CustomPropertyValue `json:"properties"` +} + +// GetOrganizationCustomPropertySchema gets all organization custom property definitions that are defined on an enterprise. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/custom-properties-for-orgs#get-organization-custom-properties-schema-for-an-enterprise +// +//meta:operation GET /enterprises/{enterprise}/org-properties/schema +func (s *EnterpriseService) GetOrganizationCustomPropertySchema(ctx context.Context, enterprise string) (*EnterpriseCustomPropertySchema, *Response, error) { + u := fmt.Sprintf("enterprises/%v/org-properties/schema", enterprise) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var schema *EnterpriseCustomPropertySchema + resp, err := s.client.Do(ctx, req, &schema) + if err != nil { + return nil, resp, err + } + + return schema, resp, nil +} + +// CreateOrUpdateOrganizationCustomPropertySchema creates new or updates existing organization custom properties defined on an enterprise in a batch. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/custom-properties-for-orgs#create-or-update-organization-custom-property-definitions-on-an-enterprise +// +//meta:operation PATCH /enterprises/{enterprise}/org-properties/schema +func (s *EnterpriseService) CreateOrUpdateOrganizationCustomPropertySchema(ctx context.Context, enterprise string, schema EnterpriseCustomPropertySchema) (*Response, error) { + u := fmt.Sprintf("enterprises/%v/org-properties/schema", enterprise) + req, err := s.client.NewRequest("PATCH", u, schema) + if err != nil { + return nil, err + } + + resp, err := s.client.Do(ctx, req, nil) + if err != nil { + return resp, err + } + + return resp, nil +} + +// GetOrganizationCustomProperty retrieves a specific organization custom property definition from an enterprise. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/custom-properties-for-orgs#get-an-organization-custom-property-definition-from-an-enterprise +// +//meta:operation GET /enterprises/{enterprise}/org-properties/schema/{custom_property_name} +func (s *EnterpriseService) GetOrganizationCustomProperty(ctx context.Context, enterprise, customPropertyName string) (*CustomProperty, *Response, error) { + u := fmt.Sprintf("enterprises/%v/org-properties/schema/%v", enterprise, customPropertyName) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var property *CustomProperty + resp, err := s.client.Do(ctx, req, &property) + if err != nil { + return nil, resp, err + } + + return property, resp, nil +} + +// CreateOrUpdateOrganizationCustomProperty creates a new or updates an existing organization custom property definition that is defined on an enterprise. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/custom-properties-for-orgs#create-or-update-an-organization-custom-property-definition-on-an-enterprise +// +//meta:operation PUT /enterprises/{enterprise}/org-properties/schema/{custom_property_name} +func (s *EnterpriseService) CreateOrUpdateOrganizationCustomProperty(ctx context.Context, enterprise, customPropertyName string, property CustomProperty) (*Response, error) { + u := fmt.Sprintf("enterprises/%v/org-properties/schema/%v", enterprise, customPropertyName) + req, err := s.client.NewRequest("PUT", u, property) + if err != nil { + return nil, err + } + + resp, err := s.client.Do(ctx, req, nil) + if err != nil { + return resp, err + } + + return resp, nil +} + +// DeleteOrganizationCustomProperty removes an organization custom property definition that is defined on an enterprise. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/custom-properties-for-orgs#remove-an-organization-custom-property-definition-from-an-enterprise +// +//meta:operation DELETE /enterprises/{enterprise}/org-properties/schema/{custom_property_name} +func (s *EnterpriseService) DeleteOrganizationCustomProperty(ctx context.Context, enterprise, customPropertyName string) (*Response, error) { + u := fmt.Sprintf("enterprises/%v/org-properties/schema/%v", enterprise, customPropertyName) + req, err := s.client.NewRequest("DELETE", u, nil) + if err != nil { + return nil, err + } + + resp, err := s.client.Do(ctx, req, nil) + if err != nil { + return resp, err + } + + return resp, nil +} + +// ListOrganizationCustomPropertyValues lists enterprise organizations with all of their custom property values. +// Returns a list of organizations and their custom property values defined in the enterprise. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/custom-properties-for-orgs#list-custom-property-values-for-organizations-in-an-enterprise +// +//meta:operation GET /enterprises/{enterprise}/org-properties/values +func (s *EnterpriseService) ListOrganizationCustomPropertyValues(ctx context.Context, enterprise string, opts *ListOptions) ([]*EnterpriseCustomPropertiesValues, *Response, error) { + u := fmt.Sprintf("enterprises/%v/org-properties/values", enterprise) + + 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 values []*EnterpriseCustomPropertiesValues + resp, err := s.client.Do(ctx, req, &values) + if err != nil { + return nil, resp, err + } + + return values, resp, nil +} + +// CreateOrUpdateOrganizationCustomPropertyValues creates or updates custom property values for organizations in an enterprise. +// To remove a custom property value from an organization, set the property value to null. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/custom-properties-for-orgs#create-or-update-custom-property-values-for-organizations-in-an-enterprise +// +//meta:operation PATCH /enterprises/{enterprise}/org-properties/values +func (s *EnterpriseService) CreateOrUpdateOrganizationCustomPropertyValues(ctx context.Context, enterprise string, values EnterpriseCustomPropertyValuesRequest) (*Response, error) { + u := fmt.Sprintf("enterprises/%v/org-properties/values", enterprise) + req, err := s.client.NewRequest("PATCH", u, values) + if err != nil { + return nil, err + } + + resp, err := s.client.Do(ctx, req, nil) + if err != nil { + return resp, err + } + + return resp, nil +} diff --git a/github/enterprise_organization_properties_test.go b/github/enterprise_organization_properties_test.go new file mode 100644 index 00000000000..2248285bd3f --- /dev/null +++ b/github/enterprise_organization_properties_test.go @@ -0,0 +1,267 @@ +// Copyright 2025 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 ( + "fmt" + "net/http" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestEnterpriseService_GetOrganizationCustomPropertySchema(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/enterprises/e/org-properties/schema", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{ + "properties": [{ + "property_name": "team", + "value_type": "string", + "description": "Team name" + }] + }`) + }) + + ctx := t.Context() + got, _, err := client.Enterprise.GetOrganizationCustomPropertySchema(ctx, "e") + if err != nil { + t.Fatalf("Enterprise.GetOrganizationCustomPropertySchema returned error: %v", err) + } + + want := &EnterpriseCustomPropertySchema{ + Properties: []*CustomProperty{ + { + PropertyName: Ptr("team"), + ValueType: "string", + Description: Ptr("Team name"), + }, + }, + } + + if !cmp.Equal(got, want) { + t.Errorf("Enterprise.GetOrganizationCustomPropertySchema = %+v, want %+v", got, want) + } + + const methodName = "GetOrganizationCustomPropertySchema" + testBadOptions(t, methodName, func() error { + _, _, err := client.Enterprise.GetOrganizationCustomPropertySchema(ctx, "\n") + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Enterprise.GetOrganizationCustomPropertySchema(ctx, "e") + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestEnterpriseService_CreateOrUpdateOrganizationCustomPropertySchema(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/enterprises/e/org-properties/schema", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PATCH") + fmt.Fprint(w, `{}`) + }) + + ctx := t.Context() + schema := EnterpriseCustomPropertySchema{ + Properties: []*CustomProperty{{PropertyName: Ptr("team")}}, + } + _, err := client.Enterprise.CreateOrUpdateOrganizationCustomPropertySchema(ctx, "e", schema) + if err != nil { + t.Errorf("Enterprise.CreateOrUpdateOrganizationCustomPropertySchema returned error: %v", err) + } + + const methodName = "CreateOrUpdateOrganizationCustomPropertySchema" + testBadOptions(t, methodName, func() error { + _, err := client.Enterprise.CreateOrUpdateOrganizationCustomPropertySchema(ctx, "\n", schema) + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Enterprise.CreateOrUpdateOrganizationCustomPropertySchema(ctx, "e", schema) + }) +} + +func TestEnterpriseService_GetOrganizationCustomProperty(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/enterprises/e/org-properties/schema/prop", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{ + "property_name": "team", + "value_type": "string", + "description": "Team name" + }`) + }) + + ctx := t.Context() + got, _, err := client.Enterprise.GetOrganizationCustomProperty(ctx, "e", "prop") + if err != nil { + t.Fatalf("Enterprise.GetOrganizationCustomProperty returned error: %v", err) + } + + want := &CustomProperty{ + PropertyName: Ptr("team"), + ValueType: "string", + Description: Ptr("Team name"), + } + + if !cmp.Equal(got, want) { + t.Errorf("Enterprise.GetOrganizationCustomProperty = %+v, want %+v", got, want) + } + + const methodName = "GetOrganizationCustomProperty" + testBadOptions(t, methodName, func() error { + _, _, err := client.Enterprise.GetOrganizationCustomProperty(ctx, "\n", "prop") + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Enterprise.GetOrganizationCustomProperty(ctx, "e", "prop") + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestEnterpriseService_CreateOrUpdateOrganizationCustomProperty(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/enterprises/e/org-properties/schema/prop", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + fmt.Fprint(w, `{}`) + }) + + ctx := t.Context() + property := CustomProperty{PropertyName: Ptr("team")} + _, err := client.Enterprise.CreateOrUpdateOrganizationCustomProperty(ctx, "e", "prop", property) + if err != nil { + t.Errorf("Enterprise.CreateOrUpdateOrganizationCustomProperty returned error: %v", err) + } + + const methodName = "CreateOrUpdateOrganizationCustomProperty" + testBadOptions(t, methodName, func() error { + _, err := client.Enterprise.CreateOrUpdateOrganizationCustomProperty(ctx, "\n", "prop", property) + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Enterprise.CreateOrUpdateOrganizationCustomProperty(ctx, "e", "prop", property) + }) +} + +func TestEnterpriseService_DeleteOrganizationCustomProperty(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/enterprises/e/org-properties/schema/prop", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + w.WriteHeader(http.StatusNoContent) + }) + + ctx := t.Context() + _, err := client.Enterprise.DeleteOrganizationCustomProperty(ctx, "e", "prop") + if err != nil { + t.Errorf("Enterprise.DeleteOrganizationCustomProperty returned error: %v", err) + } + + const methodName = "DeleteOrganizationCustomProperty" + testBadOptions(t, methodName, func() error { + _, err := client.Enterprise.DeleteOrganizationCustomProperty(ctx, "\n", "prop") + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Enterprise.DeleteOrganizationCustomProperty(ctx, "e", "prop") + }) +} + +func TestEnterpriseService_ListOrganizationCustomPropertyValues(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/enterprises/e/org-properties/values", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `[{ + "organization_id": 1, + "organization_login": "org1", + "properties": [ + {"property_name": "team", "value": "core"} + ] + }]`) + }) + + ctx := t.Context() + opts := &ListOptions{Page: 1, PerPage: 10} + got, _, err := client.Enterprise.ListOrganizationCustomPropertyValues(ctx, "e", opts) + if err != nil { + t.Fatalf("Enterprise.ListOrganizationCustomPropertyValues returned error: %v", err) + } + + want := []*EnterpriseCustomPropertiesValues{ + { + OrganizationID: Ptr(int64(1)), + OrganizationLogin: Ptr("org1"), + Properties: []*CustomPropertyValue{ + {PropertyName: "team", Value: "core"}, + }, + }, + } + + if !cmp.Equal(got, want) { + t.Errorf("Enterprise.ListOrganizationCustomPropertyValues = %+v, want %+v", got, want) + } + + const methodName = "ListEnterpriseCustomPropertyValues" + testBadOptions(t, methodName, func() error { + _, _, err := client.Enterprise.ListOrganizationCustomPropertyValues(ctx, "\n", opts) + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Enterprise.ListOrganizationCustomPropertyValues(ctx, "e", nil) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestEnterpriseService_CreateOrUpdateOrganizationCustomPropertyValues(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/enterprises/e/org-properties/values", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PATCH") + fmt.Fprint(w, `{}`) + }) + + ctx := t.Context() + values := []*CustomPropertyValue{{PropertyName: "team", Value: Ptr("core")}} + orgs := []string{"org1"} + + opts := EnterpriseCustomPropertyValuesRequest{ + OrganizationLogin: orgs, + Properties: values, + } + _, err := client.Enterprise.CreateOrUpdateOrganizationCustomPropertyValues(ctx, "e", opts) + if err != nil { + t.Errorf("Enterprise.CreateOrUpdateOrganizationCustomPropertyValues returned error: %v", err) + } + + const methodName = "CreateOrUpdateOrganizationCustomPropertyValues" + testBadOptions(t, methodName, func() error { + _, err := client.Enterprise.CreateOrUpdateOrganizationCustomPropertyValues(ctx, "\n", opts) + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Enterprise.CreateOrUpdateOrganizationCustomPropertyValues(ctx, "e", opts) + }) +} diff --git a/github/github-accessors.go b/github/github-accessors.go index c32e2159611..9b619eb8f31 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -6902,6 +6902,14 @@ func (c *CustomProperty) GetSourceType() string { return *c.SourceType } +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (c *CustomProperty) GetURL() string { + if c == nil || c.URL == nil { + return "" + } + return *c.URL +} + // GetValuesEditableBy returns the ValuesEditableBy field if it's non-nil, zero value otherwise. func (c *CustomProperty) GetValuesEditableBy() string { if c == nil || c.ValuesEditableBy == nil { @@ -9206,6 +9214,22 @@ func (e *Enterprise) GetWebsiteURL() string { return *e.WebsiteURL } +// GetOrganizationID returns the OrganizationID field if it's non-nil, zero value otherwise. +func (e *EnterpriseCustomPropertiesValues) GetOrganizationID() int64 { + if e == nil || e.OrganizationID == nil { + return 0 + } + return *e.OrganizationID +} + +// GetOrganizationLogin returns the OrganizationLogin field if it's non-nil, zero value otherwise. +func (e *EnterpriseCustomPropertiesValues) GetOrganizationLogin() string { + if e == nil || e.OrganizationLogin == nil { + return "" + } + return *e.OrganizationLogin +} + // GetEnterpriseServerUser returns the EnterpriseServerUser field if it's non-nil, zero value otherwise. func (e *EnterpriseLicensedUsers) GetEnterpriseServerUser() bool { if e == nil || e.EnterpriseServerUser == nil { @@ -24622,6 +24646,14 @@ func (r *RepositoryRulesetConditions) GetOrganizationName() *RepositoryRulesetOr return r.OrganizationName } +// GetOrganizationProperty returns the OrganizationProperty field. +func (r *RepositoryRulesetConditions) GetOrganizationProperty() *RepositoryRulesetOrganizationPropertyConditionParameters { + if r == nil { + return nil + } + return r.OrganizationProperty +} + // GetRefName returns the RefName field. func (r *RepositoryRulesetConditions) GetRefName() *RepositoryRulesetRefConditionParameters { if r == nil { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index d3bef6e4a9d..4503a4a1b48 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -9033,6 +9033,17 @@ func TestCustomProperty_GetSourceType(tt *testing.T) { c.GetSourceType() } +func TestCustomProperty_GetURL(tt *testing.T) { + tt.Parallel() + var zeroValue string + c := &CustomProperty{URL: &zeroValue} + c.GetURL() + c = &CustomProperty{} + c.GetURL() + c = nil + c.GetURL() +} + func TestCustomProperty_GetValuesEditableBy(tt *testing.T) { tt.Parallel() var zeroValue string @@ -11925,6 +11936,28 @@ func TestEnterprise_GetWebsiteURL(tt *testing.T) { e.GetWebsiteURL() } +func TestEnterpriseCustomPropertiesValues_GetOrganizationID(tt *testing.T) { + tt.Parallel() + var zeroValue int64 + e := &EnterpriseCustomPropertiesValues{OrganizationID: &zeroValue} + e.GetOrganizationID() + e = &EnterpriseCustomPropertiesValues{} + e.GetOrganizationID() + e = nil + e.GetOrganizationID() +} + +func TestEnterpriseCustomPropertiesValues_GetOrganizationLogin(tt *testing.T) { + tt.Parallel() + var zeroValue string + e := &EnterpriseCustomPropertiesValues{OrganizationLogin: &zeroValue} + e.GetOrganizationLogin() + e = &EnterpriseCustomPropertiesValues{} + e.GetOrganizationLogin() + e = nil + e.GetOrganizationLogin() +} + func TestEnterpriseLicensedUsers_GetEnterpriseServerUser(tt *testing.T) { tt.Parallel() var zeroValue bool @@ -31820,6 +31853,14 @@ func TestRepositoryRulesetConditions_GetOrganizationName(tt *testing.T) { r.GetOrganizationName() } +func TestRepositoryRulesetConditions_GetOrganizationProperty(tt *testing.T) { + tt.Parallel() + r := &RepositoryRulesetConditions{} + r.GetOrganizationProperty() + r = nil + r.GetOrganizationProperty() +} + func TestRepositoryRulesetConditions_GetRefName(tt *testing.T) { tt.Parallel() r := &RepositoryRulesetConditions{} diff --git a/github/orgs_organization_properties.go b/github/orgs_organization_properties.go new file mode 100644 index 00000000000..ef997ec7996 --- /dev/null +++ b/github/orgs_organization_properties.go @@ -0,0 +1,60 @@ +// Copyright 2025 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" +) + +// OrganizationCustomPropertyValues represents the custom property values for an organization. +type OrganizationCustomPropertyValues struct { + // List of custom property names and associated values to apply to the organization. + Properties []*CustomPropertyValue `json:"properties,omitempty"` +} + +// GetOrganizationCustomPropertyValues returns all custom property names and their values for an organization. +// +// GitHub API docs: https://docs.github.com/rest/orgs/custom-properties-for-orgs#get-all-custom-property-values-for-an-organization +// +//meta:operation GET /organizations/{org}/org-properties/values +func (s *OrganizationsService) GetOrganizationCustomPropertyValues(ctx context.Context, org string) ([]*CustomPropertyValue, *Response, error) { + u := fmt.Sprintf("organizations/%v/org-properties/values", org) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var values []*CustomPropertyValue + resp, err := s.client.Do(ctx, req, &values) + if err != nil { + return nil, resp, err + } + + return values, resp, nil +} + +// CreateOrUpdateOrganizationCustomPropertyValues creates or updates custom property values for an organization. +// To remove a custom property value from an organization, set the property value to null. +// +// GitHub API docs: https://docs.github.com/rest/orgs/custom-properties-for-orgs#create-or-update-custom-property-values-for-an-organization +// +//meta:operation PATCH /organizations/{org}/org-properties/values +func (s *OrganizationsService) CreateOrUpdateOrganizationCustomPropertyValues(ctx context.Context, org string, values OrganizationCustomPropertyValues) (*Response, error) { + u := fmt.Sprintf("organizations/%v/org-properties/values", org) + req, err := s.client.NewRequest("PATCH", u, values) + if err != nil { + return nil, err + } + + resp, err := s.client.Do(ctx, req, nil) + if err != nil { + return resp, err + } + + return resp, nil +} diff --git a/github/orgs_organization_properties_test.go b/github/orgs_organization_properties_test.go new file mode 100644 index 00000000000..e7bc715c164 --- /dev/null +++ b/github/orgs_organization_properties_test.go @@ -0,0 +1,94 @@ +// Copyright 2025 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 ( + "fmt" + "net/http" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestOrganizationsService_GetOrganizationCustomPropertyValues(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/organizations/o/org-properties/values", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `[{ + "property_name": "team", + "value": "core" + }, + { + "property_name": "level", + "value": "gold" + }]`) + }) + + ctx := t.Context() + got, _, err := client.Organizations.GetOrganizationCustomPropertyValues(ctx, "o") + if err != nil { + t.Fatalf("Organizations.GetOrganizationCustomPropertyValues returned error: %v", err) + } + + want := []*CustomPropertyValue{ + {PropertyName: "team", Value: "core"}, + {PropertyName: "level", Value: "gold"}, + } + + if !cmp.Equal(got, want) { + t.Errorf("Organizations.GetOrganizationCustomPropertyValues = %+v, want %+v", got, want) + } + + const methodName = "GetOrganizationCustomPropertyValues" + + testBadOptions(t, methodName, func() error { + _, _, err := client.Organizations.GetOrganizationCustomPropertyValues(ctx, "\n") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Organizations.GetOrganizationCustomPropertyValues(ctx, "o") + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestOrganizationsService_CreateOrUpdateOrganizationCustomPropertyValues(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/organizations/o/org-properties/values", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PATCH") + fmt.Fprint(w, `{}`) + }) + + ctx := t.Context() + values := []*CustomPropertyValue{ + {PropertyName: "team", Value: Ptr("core")}, + {PropertyName: "level", Value: Ptr("gold")}, + } + + props := OrganizationCustomPropertyValues{ + Properties: values, + } + _, err := client.Organizations.CreateOrUpdateOrganizationCustomPropertyValues(ctx, "o", props) + if err != nil { + t.Errorf("Organizations.CreateOrUpdateOrganizationCustomPropertyValues returned error: %v", err) + } + + const methodName = "CreateOrUpdateOrganizationCustomPropertyValues" + testBadOptions(t, methodName, func() error { + _, err := client.Organizations.CreateOrUpdateOrganizationCustomPropertyValues(ctx, "\n", props) + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Organizations.CreateOrUpdateOrganizationCustomPropertyValues(ctx, "o", props) + }) +} diff --git a/github/orgs_properties.go b/github/orgs_properties.go index 257e765993b..0c23c91b227 100644 --- a/github/orgs_properties.go +++ b/github/orgs_properties.go @@ -17,6 +17,8 @@ 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"` + // The URL that can be used to fetch, update, or delete info about this property via the API. + URL *string `json:"url,omitempty"` // SourceType is the source type of the property where it has been created. Can be one of: organization, enterprise. SourceType *string `json:"source_type,omitempty"` // The type of the value for the property. Can be one of: string, single_select, multi_select, true_false. diff --git a/github/rules.go b/github/rules.go index 7b474f00e68..dc95abc0fc1 100644 --- a/github/rules.go +++ b/github/rules.go @@ -203,12 +203,13 @@ type RepositoryRulesetLink struct { // RepositoryRulesetConditions represents the conditions object in a ruleset. // Set either RepositoryName or RepositoryID or RepositoryProperty, not more than one. type RepositoryRulesetConditions struct { - RefName *RepositoryRulesetRefConditionParameters `json:"ref_name,omitempty"` - RepositoryID *RepositoryRulesetRepositoryIDsConditionParameters `json:"repository_id,omitempty"` - RepositoryName *RepositoryRulesetRepositoryNamesConditionParameters `json:"repository_name,omitempty"` - RepositoryProperty *RepositoryRulesetRepositoryPropertyConditionParameters `json:"repository_property,omitempty"` - OrganizationID *RepositoryRulesetOrganizationIDsConditionParameters `json:"organization_id,omitempty"` - OrganizationName *RepositoryRulesetOrganizationNamesConditionParameters `json:"organization_name,omitempty"` + RefName *RepositoryRulesetRefConditionParameters `json:"ref_name,omitempty"` + RepositoryID *RepositoryRulesetRepositoryIDsConditionParameters `json:"repository_id,omitempty"` + RepositoryName *RepositoryRulesetRepositoryNamesConditionParameters `json:"repository_name,omitempty"` + RepositoryProperty *RepositoryRulesetRepositoryPropertyConditionParameters `json:"repository_property,omitempty"` + OrganizationID *RepositoryRulesetOrganizationIDsConditionParameters `json:"organization_id,omitempty"` + OrganizationName *RepositoryRulesetOrganizationNamesConditionParameters `json:"organization_name,omitempty"` + OrganizationProperty *RepositoryRulesetOrganizationPropertyConditionParameters `json:"organization_property,omitempty"` } // RepositoryRulesetRefConditionParameters represents the conditions object for ref_names. @@ -217,6 +218,12 @@ type RepositoryRulesetRefConditionParameters struct { Exclude []string `json:"exclude"` } +// RepositoryRulesetOrganizationPropertyConditionParameters represents the conditions object for an organization property selector. +type RepositoryRulesetOrganizationPropertyConditionParameters struct { + Include []*RepositoryRulesetRepositoryPropertyTargetParameters `json:"include"` + Exclude []*RepositoryRulesetRepositoryPropertyTargetParameters `json:"exclude"` +} + // RepositoryRulesetRepositoryIDsConditionParameters represents the conditions object for repository_id. type RepositoryRulesetRepositoryIDsConditionParameters struct { RepositoryIDs []int64 `json:"repository_ids,omitempty"`