Files
go-github/github/orgs_properties.go

318 lines
11 KiB
Go

// 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"
"encoding/json"
"errors"
"fmt"
"strconv"
)
// PropertyValueType represents the type of a custom property value.
type PropertyValueType string
// Valid values for CustomProperty.ValueType.
const (
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.
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, url.
ValueType PropertyValueType `json:"value_type"`
// Whether the property is required.
Required *bool `json:"required,omitempty"`
// Whether setting property values is mandatory.
RequireExplicitValues *bool `json:"require_explicit_values,omitempty"`
// Default value of the property.
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
// allowed values.
AllowedValues []string `json:"allowed_values,omitempty"`
// Who can edit the values of the property. Can be one of: org_actors, org_and_repo_actors, nil (null).
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:
switch v := cp.DefaultValue.(type) {
case []string:
return v, true
case []any:
vals := make([]string, len(v))
for i, item := range v {
s, ok := item.(string)
if !ok {
return nil, false
}
vals[i] = s
}
return vals, true
default:
return nil, false
}
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"`
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 any `json:"value"`
}
// ListCustomPropertyValuesOptions specifies the optional parameters to the
// OrganizationsService.ListCustomPropertyValues method.
type ListCustomPropertyValuesOptions struct {
RepositoryQuery string `url:"repository_query,omitempty"`
ListOptions
}
// UnmarshalJSON implements the json.Unmarshaler interface.
// This helps us handle the fact that Value can be either a string, []string, or nil.
func (cpv *CustomPropertyValue) UnmarshalJSON(data []byte) error {
type aliasCustomPropertyValue CustomPropertyValue
aux := &struct {
*aliasCustomPropertyValue
}{
aliasCustomPropertyValue: (*aliasCustomPropertyValue)(cpv),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
switch v := aux.Value.(type) {
case nil:
cpv.Value = nil
case string:
cpv.Value = v
case []any:
strSlice := make([]string, len(v))
for i, item := range v {
str, ok := item.(string)
if !ok {
return errors.New("non-string value in string array")
}
strSlice[i] = str
}
cpv.Value = strSlice
default:
return fmt.Errorf("unexpected value type: %T", v)
}
return nil
}
// GetAllCustomProperties gets all custom properties that are defined for the specified organization.
//
// GitHub API docs: https://docs.github.com/rest/orgs/custom-properties?apiVersion=2022-11-28#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)
req, err := s.client.NewRequest(ctx, "GET", u, nil)
if err != nil {
return nil, nil, err
}
var customProperties []*CustomProperty
resp, err := s.client.Do(req, &customProperties)
if err != nil {
return nil, resp, err
}
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/rest/orgs/custom-properties?apiVersion=2022-11-28#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)
params := struct {
Properties []*CustomProperty `json:"properties"`
}{
Properties: properties,
}
req, err := s.client.NewRequest(ctx, "PATCH", u, params)
if err != nil {
return nil, nil, err
}
var customProperties []*CustomProperty
resp, err := s.client.Do(req, &customProperties)
if err != nil {
return nil, resp, err
}
return customProperties, resp, nil
}
// GetCustomProperty gets a custom property that is defined for the specified organization.
//
// GitHub API docs: https://docs.github.com/rest/orgs/custom-properties?apiVersion=2022-11-28#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)
req, err := s.client.NewRequest(ctx, "GET", u, nil)
if err != nil {
return nil, nil, err
}
var customProperty *CustomProperty
resp, err := s.client.Do(req, &customProperty)
if err != nil {
return nil, resp, err
}
return customProperty, resp, nil
}
// CreateOrUpdateCustomProperty creates a new or updates an existing custom property that is defined for the specified organization.
//
// GitHub API docs: https://docs.github.com/rest/orgs/custom-properties?apiVersion=2022-11-28#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, customPropertyName string, body *CustomProperty) (*CustomProperty, *Response, error) {
u := fmt.Sprintf("orgs/%v/properties/schema/%v", org, customPropertyName)
req, err := s.client.NewRequest(ctx, "PUT", u, body)
if err != nil {
return nil, nil, err
}
var customProperty *CustomProperty
resp, err := s.client.Do(req, &customProperty)
if err != nil {
return nil, resp, err
}
return customProperty, resp, nil
}
// RemoveCustomProperty removes a custom property that is defined for the specified organization.
//
// GitHub API docs: https://docs.github.com/rest/orgs/custom-properties?apiVersion=2022-11-28#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, customPropertyName string) (*Response, error) {
u := fmt.Sprintf("orgs/%v/properties/schema/%v", org, customPropertyName)
req, err := s.client.NewRequest(ctx, "DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}
// ListCustomPropertyValues lists all custom property values for repositories in the specified organization.
//
// GitHub API docs: https://docs.github.com/rest/orgs/custom-properties?apiVersion=2022-11-28#list-custom-property-values-for-organization-repositories
//
//meta:operation GET /orgs/{org}/properties/values
func (s *OrganizationsService) ListCustomPropertyValues(ctx context.Context, org string, opts *ListCustomPropertyValuesOptions) ([]*RepoCustomPropertyValue, *Response, error) {
u := fmt.Sprintf("orgs/%v/properties/values", org)
u, err := addOptions(u, opts)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest(ctx, "GET", u, nil)
if err != nil {
return nil, nil, err
}
var repoCustomPropertyValues []*RepoCustomPropertyValue
resp, err := s.client.Do(req, &repoCustomPropertyValues)
if err != nil {
return nil, resp, err
}
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/rest/orgs/custom-properties?apiVersion=2022-11-28#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 []*CustomPropertyValue) (*Response, error) {
u := fmt.Sprintf("orgs/%v/properties/values", org)
params := struct {
RepositoryNames []string `json:"repository_names"`
Properties []*CustomPropertyValue `json:"properties"`
}{
RepositoryNames: repoNames,
Properties: properties,
}
req, err := s.client.NewRequest(ctx, "PATCH", u, params)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}