Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .changes/unreleased/deprecate-client-get-property.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
kind: Deprecated
body: '`Client.GetProperty` only resolves service owners and will fail for team identifiers. Use `Service.GetProperty` or `Team.GetProperty` instead.'
2 changes: 2 additions & 0 deletions .changes/unreleased/property-owner-type-change.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
kind: Removed
body: '[Breaking change] `Property.Owner` type changed from `EntityOwnerService` to `PropertyOwner` to support both service and team owners. Direct field access (e.g. `property.Owner.Aliases`) must be updated to go through the embedded type (e.g. `property.Owner.ServiceId.Aliases`).'
2 changes: 2 additions & 0 deletions .changes/unreleased/team-property-definitions.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
kind: Feature
body: Add CRUD operations for team property definitions (`CreateTeamPropertyDefinition`, `UpdateTeamPropertyDefinition`, `GetTeamPropertyDefinition`, `ListTeamPropertyDefinitions`, `AssignTeamPropertyDefinitions`) and entity-scoped property lookup methods (`Team.GetProperty`, `Service.GetProperty`)
16 changes: 16 additions & 0 deletions owner.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,19 @@ func (entityOwnerService *EntityOwnerService) Aliases() []string {
func (entityOwnerService *EntityOwnerService) Id() ID {
return entityOwnerService.OnService.Id
}

type PropertyOwner struct {
Typename string `graphql:"__typename"`
*TeamId `graphql:"... on Team"`
*ServiceId `graphql:"... on Service"`
}

func (o PropertyOwner) Id() ID {
if o.ServiceId != nil {
return o.ServiceId.Id
}
if o.TeamId != nil {
return o.TeamId.Id
}
return ""
}
6 changes: 6 additions & 0 deletions payload.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,12 @@ type TeamPropertyDefinitionPayload struct {
BasePayload
}

// TeamPropertyDefinitionsAssignPayload The return type for the teamPropertyDefinitionsAssign mutation
type TeamPropertyDefinitionsAssignPayload struct {
Properties TeamPropertyDefinitionConnection // The property definitions that were assigned (Optional)
BasePayload
}

// TeamUpdatePayload The return type of a `teamUpdate` mutation
type TeamUpdatePayload struct {
Team Team // A team belongs to your organization. Teams can own multiple services (Optional)
Expand Down
114 changes: 106 additions & 8 deletions property.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ type PropertyDefinitionId struct {
type Property struct {
Definition PropertyDefinitionId `graphql:"definition"`
Locked bool `graphql:"locked"`
Owner EntityOwnerService `graphql:"owner"`
Owner PropertyOwner `graphql:"owner"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a small breaking change where like property.Owner.Aliases would work before, but now you'd have to do property.Owner.ServiceId.Aliases. I think it makes sense though, maybe just ensure we record it as a breaking change in changelog? I'm not 100% sure how we handle these historically.

ValidationErrors []Error `graphql:"validationErrors"`
Value *JsonString `graphql:"value"`
}

type ServicePropertiesConnection struct {
type PropertiesConnection struct {
Nodes []Property
PageInfo PageInfo
TotalCount int `graphql:"-"`
Expand Down Expand Up @@ -111,6 +111,86 @@ func (client *Client) DeletePropertyDefinition(input string) error {
return HandleErrors(err, m.Payload.Errors)
}

func (client *Client) CreateTeamPropertyDefinition(input TeamPropertyDefinitionInput) (*TeamPropertyDefinition, error) {
var m struct {
Payload TeamPropertyDefinitionPayload `graphql:"teamPropertyDefinitionCreate(input: $input)"`
}
v := PayloadVariables{
"input": input,
}
err := client.Mutate(&m, v, WithName("TeamPropertyDefinitionCreate"))
return &m.Payload.Definition, HandleErrors(err, m.Payload.Errors)
}

func (client *Client) UpdateTeamPropertyDefinition(identifier string, input TeamPropertyDefinitionInput) (*TeamPropertyDefinition, error) {
var m struct {
Payload TeamPropertyDefinitionPayload `graphql:"teamPropertyDefinitionUpdate(propertyDefinition: $propertyDefinition, input: $input)"`
}
v := PayloadVariables{
"propertyDefinition": *NewIdentifier(identifier),
"input": input,
}
err := client.Mutate(&m, v, WithName("TeamPropertyDefinitionUpdate"))
return &m.Payload.Definition, HandleErrors(err, m.Payload.Errors)
}

func (client *Client) GetTeamPropertyDefinition(identifier string) (*TeamPropertyDefinition, error) {
var q struct {
Account struct {
Definition TeamPropertyDefinition `graphql:"teamPropertyDefinition(input: $input)"`
}
}
v := PayloadVariables{
"input": *NewIdentifier(identifier),
}
err := client.Query(&q, v, WithName("TeamPropertyDefinitionGet"))
if q.Account.Definition.Id == "" {
err = fmt.Errorf("TeamPropertyDefinition with ID or Alias matching '%s' not found", identifier)
}
return &q.Account.Definition, HandleErrors(err, nil)
}

func (client *Client) ListTeamPropertyDefinitions(variables *PayloadVariables) (*TeamPropertyDefinitionConnection, error) {
var q struct {
Account struct {
Definitions TeamPropertyDefinitionConnection `graphql:"teamPropertyDefinitions(after: $after, first: $first)"`
}
}
if variables == nil {
variables = client.InitialPageVariablesPointer()
}
if err := client.Query(&q, *variables, WithName("TeamPropertyDefinitionList")); err != nil {
return nil, err
}
q.Account.Definitions.TotalCount = len(q.Account.Definitions.Nodes)
if q.Account.Definitions.PageInfo.HasNextPage {
(*variables)["after"] = q.Account.Definitions.PageInfo.End
resp, err := client.ListTeamPropertyDefinitions(variables)
if err != nil {
return nil, err
}
q.Account.Definitions.Nodes = append(q.Account.Definitions.Nodes, resp.Nodes...)
q.Account.Definitions.PageInfo = resp.PageInfo
q.Account.Definitions.TotalCount += resp.TotalCount
}
return &q.Account.Definitions, nil
}

func (client *Client) AssignTeamPropertyDefinitions(input TeamPropertyDefinitionsAssignInput) (*TeamPropertyDefinitionConnection, error) {
var m struct {
Payload TeamPropertyDefinitionsAssignPayload `graphql:"teamPropertyDefinitionsAssign(input: $input)"`
}
v := PayloadVariables{
"input": input,
}
err := client.Mutate(&m, v, WithName("TeamPropertyDefinitionsAssign"))
m.Payload.Properties.TotalCount = len(m.Payload.Properties.Nodes)
return &m.Payload.Properties, HandleErrors(err, m.Payload.Errors)
}

// Deprecated: Use [Service.GetProperty] or [Team.GetProperty] instead.
// This method only resolves service owners. Passing a team identifier will
// return an error from the API.
func (client *Client) GetProperty(owner string, definition string) (*Property, error) {
var q struct {
Account struct {
Expand All @@ -125,6 +205,25 @@ func (client *Client) GetProperty(owner string, definition string) (*Property, e
return &q.Account.Property, HandleErrors(err, nil)
}

func (service *Service) GetProperty(client *Client, definition string) (*Property, error) {
var q struct {
Account struct {
Service struct {
Property Property `graphql:"property(definition: $definition)"`
} `graphql:"service(id: $service)"`
}
}
if service.Id == "" {
return nil, fmt.Errorf("unable to get property, invalid Service id: '%s'", service.Id)
}
v := PayloadVariables{
"service": service.Id,
"definition": *NewIdentifier(definition),
}
err := client.Query(&q, v, WithName("ServicePropertyGet"))
return &q.Account.Service.Property, HandleErrors(err, nil)
}

func (client *Client) PropertyAssign(input PropertyInput) (*Property, error) {
var m struct {
Payload PropertyPayload `graphql:"propertyAssign(input: $input)"`
Expand All @@ -148,11 +247,11 @@ func (client *Client) PropertyUnassign(owner string, definition string) error {
return HandleErrors(err, m.Payload.Errors)
}

func (service *Service) GetProperties(client *Client, variables *PayloadVariables) (*ServicePropertiesConnection, error) {
func (service *Service) GetProperties(client *Client, variables *PayloadVariables) (*PropertiesConnection, error) {
var q struct {
Account struct {
Service struct {
Properties ServicePropertiesConnection `graphql:"properties(after: $after, first: $first)"`
Properties PropertiesConnection `graphql:"properties(after: $after, first: $first)"`
} `graphql:"service(id: $service)"`
}
}
Expand All @@ -168,17 +267,16 @@ func (service *Service) GetProperties(client *Client, variables *PayloadVariable
return nil, err
}
if service.Properties == nil {
service.Properties = &ServicePropertiesConnection{}
service.Properties = &PropertiesConnection{}
}
service.Properties.Nodes = append(service.Properties.Nodes, q.Account.Service.Properties.Nodes...)
service.Properties.PageInfo = q.Account.Service.Properties.PageInfo
if service.Properties.PageInfo.HasNextPage {
(*variables)["after"] = service.Properties.PageInfo.End
resp, err := service.GetProperties(client, variables)
if err != nil {
if _, err := service.GetProperties(client, variables); err != nil {
return nil, err
}
service.Properties.TotalCount += resp.TotalCount
}
service.Properties.TotalCount = len(service.Properties.Nodes)
return service.Properties, nil
}
Loading
Loading