diff --git a/github/enterprise_properties_test.go b/github/enterprise_properties_test.go index 94bf1db966c..e94ae903fed 100644 --- a/github/enterprise_properties_test.go +++ b/github/enterprise_properties_test.go @@ -55,7 +55,7 @@ func TestEnterpriseService_GetAllCustomProperties(t *testing.T) { PropertyName: Ptr("name"), ValueType: PropertyValueTypeSingleSelect, Required: Ptr(true), - DefaultValue: Ptr("production"), + DefaultValue: "production", Description: Ptr("Prod or dev environment"), AllowedValues: []string{"production", "development"}, ValuesEditableBy: Ptr("org_actors"), @@ -178,7 +178,7 @@ func TestEnterpriseService_GetCustomProperty(t *testing.T) { PropertyName: Ptr("name"), ValueType: PropertyValueTypeSingleSelect, Required: Ptr(true), - DefaultValue: Ptr("production"), + DefaultValue: "production", Description: Ptr("Prod or dev environment"), AllowedValues: []string{"production", "development"}, ValuesEditableBy: Ptr("org_actors"), @@ -222,7 +222,7 @@ func TestEnterpriseService_CreateOrUpdateCustomProperty(t *testing.T) { property, _, err := client.Enterprise.CreateOrUpdateCustomProperty(ctx, "e", "name", &CustomProperty{ ValueType: PropertyValueTypeSingleSelect, Required: Ptr(true), - DefaultValue: Ptr("production"), + DefaultValue: "production", Description: Ptr("Prod or dev environment"), AllowedValues: []string{"production", "development"}, ValuesEditableBy: Ptr("org_actors"), @@ -235,7 +235,7 @@ func TestEnterpriseService_CreateOrUpdateCustomProperty(t *testing.T) { PropertyName: Ptr("name"), ValueType: PropertyValueTypeSingleSelect, Required: Ptr(true), - DefaultValue: Ptr("production"), + DefaultValue: "production", Description: Ptr("Prod or dev environment"), AllowedValues: []string{"production", "development"}, ValuesEditableBy: Ptr("org_actors"), diff --git a/github/event_types_test.go b/github/event_types_test.go index 05843206d49..2c0e7f88796 100644 --- a/github/event_types_test.go +++ b/github/event_types_test.go @@ -13732,7 +13732,7 @@ func TestCustomPropertyEvent_Marshal(t *testing.T) { ValueType: PropertyValueTypeSingleSelect, SourceType: Ptr("enterprise"), Required: Ptr(true), - DefaultValue: Ptr("production"), + DefaultValue: "production", Description: Ptr("Prod or dev environment"), AllowedValues: []string{"production", "development"}, ValuesEditableBy: Ptr("org_actors"), diff --git a/github/github-accessors.go b/github/github-accessors.go index 01f36e3418d..4ac72f5319b 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -7102,14 +7102,6 @@ func (c *CustomPatternBackfillScan) GetPatternSlug() string { return *c.PatternSlug } -// 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 { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index 0b10ee00c8a..c79b58d99e7 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -9290,17 +9290,6 @@ func TestCustomPatternBackfillScan_GetPatternSlug(tt *testing.T) { c.GetPatternSlug() } -func TestCustomProperty_GetDefaultValue(tt *testing.T) { - tt.Parallel() - var zeroValue string - c := &CustomProperty{DefaultValue: &zeroValue} - c.GetDefaultValue() - c = &CustomProperty{} - c.GetDefaultValue() - c = nil - c.GetDefaultValue() -} - func TestCustomProperty_GetDescription(tt *testing.T) { tt.Parallel() var zeroValue string diff --git a/github/orgs_properties.go b/github/orgs_properties.go index 502713b8bac..927f93c17fc 100644 --- a/github/orgs_properties.go +++ b/github/orgs_properties.go @@ -10,15 +10,19 @@ import ( "encoding/json" "errors" "fmt" + "strconv" ) +// PropertyValueType represents the type of a custom property value. +type PropertyValueType string + // Valid values for CustomProperty.ValueType. const ( - PropertyValueTypeString = "string" - PropertyValueTypeSingleSelect = "single_select" - PropertyValueTypeMultiSelect = "multi_select" - PropertyValueTypeTrueFalse = "true_false" - PropertyValueTypeURL = "url" + PropertyValueTypeString PropertyValueType = "string" + PropertyValueTypeSingleSelect PropertyValueType = "single_select" + PropertyValueTypeMultiSelect PropertyValueType = "multi_select" + PropertyValueTypeTrueFalse PropertyValueType = "true_false" + PropertyValueTypeURL PropertyValueType = "url" ) // CustomProperty represents an organization custom property object. @@ -31,11 +35,11 @@ type CustomProperty struct { // 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, url. - ValueType string `json:"value_type"` + ValueType PropertyValueType `json:"value_type"` // Whether the property is required. Required *bool `json:"required,omitempty"` // Default value of the property. - DefaultValue *string `json:"default_value,omitempty"` + DefaultValue any `json:"default_value,omitempty"` // Short description of the property. Description *string `json:"description,omitempty"` // An ordered list of the allowed values of the property. The property can have up to 200 @@ -45,6 +49,42 @@ type CustomProperty struct { ValuesEditableBy *string `json:"values_editable_by,omitempty"` } +// DefaultValueString returns the DefaultValue as a string if the ValueType is string or single_select or url. +func (cp CustomProperty) DefaultValueString() (string, bool) { + switch cp.ValueType { + case PropertyValueTypeString, PropertyValueTypeSingleSelect, PropertyValueTypeURL: + s, ok := cp.DefaultValue.(string) + return s, ok + default: + return "", false + } +} + +// DefaultValueStrings returns the DefaultValue as a slice of string if the ValueType is multi_select. +func (cp CustomProperty) DefaultValueStrings() ([]string, bool) { + switch cp.ValueType { + case PropertyValueTypeMultiSelect: + s, ok := cp.DefaultValue.([]string) + return s, ok + default: + return nil, false + } +} + +// DefaultValueBool returns the DefaultValue as a string if the ValueType is true_false. +func (cp CustomProperty) DefaultValueBool() (bool, bool) { + switch cp.ValueType { + case PropertyValueTypeTrueFalse: + if s, ok := cp.DefaultValue.(string); ok { + b, err := strconv.ParseBool(s) + return b, err == nil + } + return false, false + default: + return false, false + } +} + // RepoCustomPropertyValue represents a repository custom property value. type RepoCustomPropertyValue struct { RepositoryID int64 `json:"repository_id"` diff --git a/github/orgs_properties_test.go b/github/orgs_properties_test.go index bac673d3eed..8e795b7843c 100644 --- a/github/orgs_properties_test.go +++ b/github/orgs_properties_test.go @@ -11,6 +11,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" ) func TestOrganizationsService_GetAllCustomProperties(t *testing.T) { @@ -62,7 +63,7 @@ func TestOrganizationsService_GetAllCustomProperties(t *testing.T) { PropertyName: Ptr("name"), ValueType: PropertyValueTypeSingleSelect, Required: Ptr(true), - DefaultValue: Ptr("production"), + DefaultValue: "production", Description: Ptr("Prod or dev environment"), AllowedValues: []string{"production", "development"}, ValuesEditableBy: Ptr("org_actors"), @@ -81,7 +82,7 @@ func TestOrganizationsService_GetAllCustomProperties(t *testing.T) { ValueType: PropertyValueTypeURL, Required: Ptr(true), Description: Ptr("Link to the documentation"), - DefaultValue: Ptr("https://example.com/docs"), + DefaultValue: "https://example.com/docs", }, } if !cmp.Equal(properties, want) { @@ -192,7 +193,7 @@ func TestOrganizationsService_GetCustomProperty(t *testing.T) { PropertyName: Ptr("name"), ValueType: PropertyValueTypeSingleSelect, Required: Ptr(true), - DefaultValue: Ptr("production"), + DefaultValue: "production", Description: Ptr("Prod or dev environment"), AllowedValues: []string{"production", "development"}, ValuesEditableBy: Ptr("org_actors"), @@ -236,7 +237,7 @@ func TestOrganizationsService_CreateOrUpdateCustomProperty(t *testing.T) { property, _, err := client.Organizations.CreateOrUpdateCustomProperty(ctx, "o", "name", &CustomProperty{ ValueType: PropertyValueTypeSingleSelect, Required: Ptr(true), - DefaultValue: Ptr("production"), + DefaultValue: "production", Description: Ptr("Prod or dev environment"), AllowedValues: []string{"production", "development"}, ValuesEditableBy: Ptr("org_actors"), @@ -249,7 +250,7 @@ func TestOrganizationsService_CreateOrUpdateCustomProperty(t *testing.T) { PropertyName: Ptr("name"), ValueType: PropertyValueTypeSingleSelect, Required: Ptr(true), - DefaultValue: Ptr("production"), + DefaultValue: "production", Description: Ptr("Prod or dev environment"), AllowedValues: []string{"production", "development"}, ValuesEditableBy: Ptr("org_actors"), @@ -484,3 +485,255 @@ func TestOrganizationsService_CreateOrUpdateRepoCustomPropertyValues(t *testing. return client.Organizations.CreateOrUpdateRepoCustomPropertyValues(ctx, "o", nil, nil) }) } + +func TestCustomPropertyDefaultValueString(t *testing.T) { + t.Parallel() + for _, d := range []struct { + testName string + property *CustomProperty + ok bool + want string + }{ + { + testName: "invalid_type", + property: &CustomProperty{ + ValueType: PropertyValueTypeMultiSelect, + DefaultValue: []string{"a", "b"}, + }, + ok: false, + want: "", + }, + { + testName: "string_invalid_value", + property: &CustomProperty{ + ValueType: PropertyValueTypeString, + DefaultValue: []string{"a", "b"}, + }, + ok: false, + want: "", + }, + { + testName: "string_nil_value", + property: &CustomProperty{ + ValueType: PropertyValueTypeString, + DefaultValue: nil, + }, + ok: false, + want: "", + }, + { + testName: "string_value", + property: &CustomProperty{ + ValueType: PropertyValueTypeString, + DefaultValue: "test-string", + }, + ok: true, + want: "test-string", + }, + { + testName: "single_select_invalid_value", + property: &CustomProperty{ + ValueType: PropertyValueTypeSingleSelect, + DefaultValue: []string{"a", "b"}, + }, + ok: false, + want: "", + }, + { + testName: "single_select_nil_value", + property: &CustomProperty{ + ValueType: PropertyValueTypeSingleSelect, + DefaultValue: nil, + }, + ok: false, + want: "", + }, + { + testName: "single_select_value", + property: &CustomProperty{ + ValueType: PropertyValueTypeSingleSelect, + DefaultValue: "test-string", + }, + ok: true, + want: "test-string", + }, + { + testName: "url_invalid_value", + property: &CustomProperty{ + ValueType: PropertyValueTypeURL, + DefaultValue: []string{"a", "b"}, + }, + ok: false, + want: "", + }, + { + testName: "url_nil_value", + property: &CustomProperty{ + ValueType: PropertyValueTypeURL, + DefaultValue: nil, + }, + ok: false, + want: "", + }, + { + testName: "url_value", + property: &CustomProperty{ + ValueType: PropertyValueTypeURL, + DefaultValue: "http://example.com", + }, + ok: true, + want: "http://example.com", + }, + } { + t.Run(d.testName, func(t *testing.T) { + t.Parallel() + got, ok := d.property.DefaultValueString() + + if ok != d.ok { + t.Fatalf("CustomProperty.DefaultValueString set ok to %+v, want %+v", ok, d.ok) + } + + if got != d.want { + t.Fatalf("CustomProperty.DefaultValueString returned %+v, want %+v", got, d.want) + } + }) + } +} + +func TestCustomPropertyDefaultValueStrings(t *testing.T) { + t.Parallel() + for _, d := range []struct { + testName string + property *CustomProperty + ok bool + want []string + }{ + { + testName: "invalid_type", + property: &CustomProperty{ + ValueType: PropertyValueTypeString, + DefaultValue: "test", + }, + ok: false, + want: []string{}, + }, + { + testName: "multi_select_invalid_value", + property: &CustomProperty{ + ValueType: PropertyValueTypeMultiSelect, + DefaultValue: "test", + }, + ok: false, + want: []string{}, + }, + { + testName: "multi_select_nil_value", + property: &CustomProperty{ + ValueType: PropertyValueTypeMultiSelect, + DefaultValue: nil, + }, + ok: false, + want: []string{}, + }, + { + testName: "multi_select_single_value", + property: &CustomProperty{ + ValueType: PropertyValueTypeMultiSelect, + DefaultValue: []string{"a"}, + }, + ok: true, + want: []string{"a"}, + }, + { + testName: "multi_select_multi_value", + property: &CustomProperty{ + ValueType: PropertyValueTypeMultiSelect, + DefaultValue: []string{"a", "b"}, + }, + ok: true, + want: []string{"a", "b"}, + }, + } { + t.Run(d.testName, func(t *testing.T) { + t.Parallel() + got, ok := d.property.DefaultValueStrings() + + if ok != d.ok { + t.Fatalf("CustomProperty.DefaultValueStrings set ok to %+v, want %+v", ok, d.ok) + } + + if !cmp.Equal(got, d.want, cmpopts.EquateEmpty()) { + t.Fatalf("CustomProperty.DefaultValueStrings returned %+v, want %+v", got, d.want) + } + }) + } +} + +func TestCustomPropertyDefaultValueBool(t *testing.T) { + t.Parallel() + for _, d := range []struct { + testName string + property *CustomProperty + ok bool + want bool + }{ + { + testName: "invalid_type", + property: &CustomProperty{ + ValueType: PropertyValueTypeString, + DefaultValue: "test", + }, + ok: false, + want: false, + }, + { + testName: "true_false_invalid_value", + property: &CustomProperty{ + ValueType: PropertyValueTypeTrueFalse, + DefaultValue: "test", + }, + ok: false, + want: false, + }, + { + testName: "true_false_nil_value", + property: &CustomProperty{ + ValueType: PropertyValueTypeTrueFalse, + DefaultValue: nil, + }, + ok: false, + want: false, + }, + { + testName: "true_false_true_value", + property: &CustomProperty{ + ValueType: PropertyValueTypeTrueFalse, + DefaultValue: "true", + }, + ok: true, + want: true, + }, + { + testName: "true_false_false_value", + property: &CustomProperty{ + ValueType: PropertyValueTypeTrueFalse, + DefaultValue: "false", + }, + ok: true, + want: false, + }, + } { + t.Run(d.testName, func(t *testing.T) { + t.Parallel() + got, ok := d.property.DefaultValueBool() + + if ok != d.ok { + t.Fatalf("CustomProperty.DefaultValueBool set ok to %+v, want %+v", ok, d.ok) + } + + if ok != d.ok { + t.Fatalf("CustomProperty.DefaultValueBool returned %+v, want %+v", got, d.want) + } + }) + } +}