| // Copyright 2018 The Fuchsia 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 service |
| |
| import ( |
| "context" |
| "log" |
| |
| "github.com/google/uuid" |
| api "google.golang.org/genproto/googleapis/devtools/resultstore/v2" |
| "google.golang.org/genproto/protobuf/field_mask" |
| ) |
| |
| // Service executes ResultStore RPCs. |
| // |
| // ResultStore resources are hierarchical, so Service methods return keys that must be |
| // used to establish this hierarchy when creating new resources. |
| // |
| // A typical series of RPCs might look like the following. |
| // |
| // 1. Create an Invocation. |
| // 2. Create a Target, specifying the parent Invocation Key. |
| // 3. Create a Configuration, specifying the parent Invocation Key. |
| // 3. Create a ConfiguredTarget, specifying the configuration ID and parent Target Key. |
| // 4. Create an Action, specifying the parent ConfiguredTarget Key. |
| // 5. Update / Complete the Action. |
| // 6. Update / Complete the Configured Target. |
| // 7. Update / Complete the Target. |
| // 8. Complete the Invocation. |
| // |
| // For more information about the ResultStore APIs, see the proto library at |
| // https://github.com/googleapis/googleapis/tree/master/google/devtools/resultstore/v2 |
| // |
| // Service methods generate UUIDs for certain proto.Message fields. If the provided |
| // Context contains a non-empty string value for TestUUIDContextKey, that value will be |
| // used instead. |
| type Service struct { |
| authToken string |
| client api.ResultStoreUploadClient |
| } |
| |
| // New creates a new Service. Set useFakeUUIDs to true to use fake UUIDs for |
| // testing. authToken is the authorization token to use for the invocation. The same |
| // token must be used in all requests to modify a single invocation. |
| func New(client api.ResultStoreUploadClient, authToken string) *Service { |
| return &Service{client: client, authToken: authToken} |
| } |
| |
| // uuid generates an RFC-4122 compliant Version 4 UUID. If the provided Context contains |
| // a non-empty string value for TestUUIDContextKey, that value will be used instead. If |
| // there was an error when reading the UUID from the context, a message is logged |
| // describing the error and a new UUID is generated. |
| func (s *Service) uuid(ctx context.Context) string { |
| value, err := GetTestUUID(ctx) |
| |
| if err != nil { |
| log.Println(err) |
| return uuid.New().String() |
| } |
| |
| if value == "" { |
| return uuid.New().String() |
| } |
| |
| return value |
| } |
| |
| // CreateInvocation must be called before any other "Create" methods, since all resources |
| // belong to an Invocation. |
| func (s *Service) CreateInvocation( |
| ctx context.Context, invocation *Invocation) (*InvocationKey, error) { |
| output, err := s.client.CreateInvocation(ctx, &api.CreateInvocationRequest{ |
| RequestId: s.uuid(ctx), |
| AuthorizationToken: s.authToken, |
| InvocationId: s.uuid(ctx), |
| Invocation: invocation.ToResultStoreInvocation(), |
| }) |
| |
| if err != nil { |
| return nil, err |
| } |
| |
| return &InvocationKey{EntityID: output.GetId(), EntityName: output.GetName()}, nil |
| |
| } |
| |
| // CreateConfiguration creates a new Configuration representing a build or test |
| // environment. |
| func (s *Service) CreateConfiguration(ctx context.Context, config *Configuration, invocationName string) (*ConfigurationKey, error) { |
| output, err := s.client.CreateConfiguration(ctx, &api.CreateConfigurationRequest{ |
| RequestId: s.uuid(ctx), |
| AuthorizationToken: s.authToken, |
| Parent: invocationName, |
| ConfigId: config.ID, |
| Configuration: config.ToResultStoreConfiguration(), |
| }) |
| |
| if err != nil { |
| return nil, err |
| } |
| |
| return &ConfigurationKey{EntityID: output.GetId(), EntityName: output.GetName()}, nil |
| } |
| |
| // CreateTarget creates a new build or test target. |
| func (s *Service) CreateTarget(ctx context.Context, target *Target, invocationName string) (*TargetKey, error) { |
| output, err := s.client.CreateTarget(ctx, &api.CreateTargetRequest{ |
| RequestId: s.uuid(ctx), |
| AuthorizationToken: s.authToken, |
| Parent: invocationName, |
| TargetId: target.ID, |
| Target: target.ToResultStoreTarget(), |
| }) |
| |
| if err != nil { |
| return nil, err |
| } |
| |
| return &TargetKey{EntityID: output.GetId(), EntityName: output.GetName()}, nil |
| } |
| |
| // CreateConfiguredTarget creates a new ConfiguredTarget representing a target being built |
| // or tested with a specific configuration. |
| func (s *Service) CreateConfiguredTarget(ctx context.Context, configTarget *ConfiguredTarget, targetName string) (*ConfiguredTargetKey, error) { |
| output, err := s.client.CreateConfiguredTarget(ctx, &api.CreateConfiguredTargetRequest{ |
| AuthorizationToken: s.authToken, |
| RequestId: s.uuid(ctx), |
| Parent: targetName, |
| ConfigId: configTarget.ConfigID, |
| ConfiguredTarget: configTarget.ToResultStoreConfiguredTarget(), |
| }) |
| |
| if err != nil { |
| return nil, err |
| } |
| |
| return &ConfiguredTargetKey{EntityID: output.GetId(), EntityName: output.GetName()}, nil |
| } |
| |
| // CreateTestAction creates a new Action representing a Target test. |
| func (s *Service) CreateTestAction(ctx context.Context, action *TestAction, configTargetName string) (*ActionKey, error) { |
| output, err := s.client.CreateAction(ctx, &api.CreateActionRequest{ |
| AuthorizationToken: s.authToken, |
| RequestId: s.uuid(ctx), |
| Parent: configTargetName, |
| ActionId: action.ID, |
| Action: action.ToResultStoreAction(), |
| }) |
| |
| if err != nil { |
| return nil, err |
| } |
| |
| return &ActionKey{EntityID: output.GetId(), EntityName: output.GetName()}, nil |
| } |
| |
| // UpdateTestAction updates the duration and status of a previously started TestAction. |
| func (s *Service) UpdateTestAction(ctx context.Context, action *TestAction) (*ActionKey, error) { |
| output, err := s.client.UpdateAction(ctx, &api.UpdateActionRequest{ |
| AuthorizationToken: s.authToken, |
| Action: action.ToResultStoreAction(), |
| UpdateMask: &field_mask.FieldMask{ |
| Paths: []string{"timing.duration", "status_attributes"}, |
| }, |
| }) |
| |
| if err != nil { |
| return nil, err |
| } |
| |
| return &ActionKey{EntityID: output.GetId(), EntityName: output.GetName()}, nil |
| } |
| |
| // UpdateConfiguredTarget updates the duration and status of a previously started |
| // UpdateConfigured. |
| func (s *Service) UpdateConfiguredTarget(ctx context.Context, configTarget *ConfiguredTarget) (*ConfiguredTargetKey, error) { |
| output, err := s.client.UpdateConfiguredTarget(ctx, &api.UpdateConfiguredTargetRequest{ |
| AuthorizationToken: s.authToken, |
| ConfiguredTarget: configTarget.ToResultStoreConfiguredTarget(), |
| UpdateMask: &field_mask.FieldMask{ |
| Paths: []string{"timing.duration", "status_attributes"}, |
| }, |
| }) |
| |
| if err != nil { |
| return nil, err |
| } |
| |
| return &ConfiguredTargetKey{EntityID: output.GetId(), EntityName: output.GetName()}, nil |
| } |
| |
| // UpdateTarget updates the duration and status of a previously started Target. |
| func (s *Service) UpdateTarget(ctx context.Context, target *Target) (*TargetKey, error) { |
| output, err := s.client.UpdateTarget(ctx, &api.UpdateTargetRequest{ |
| AuthorizationToken: s.authToken, |
| UpdateMask: &field_mask.FieldMask{ |
| Paths: []string{"timing.duration", "status_attributes"}, |
| }, |
| Target: target.ToResultStoreTarget(), |
| }) |
| |
| if err != nil { |
| return nil, err |
| } |
| |
| return &TargetKey{EntityID: output.GetId(), EntityName: output.GetName()}, nil |
| } |
| |
| // UpdateInvocation updates the duration and status of a previously started Invocation. |
| func (s *Service) UpdateInvocation(ctx context.Context, invocation *Invocation) (*InvocationKey, error) { |
| output, err := s.client.UpdateInvocation(ctx, &api.UpdateInvocationRequest{ |
| AuthorizationToken: s.authToken, |
| UpdateMask: &field_mask.FieldMask{ |
| Paths: []string{"timing.duration", "status_attributes"}, |
| }, |
| Invocation: invocation.ToResultStoreInvocation(), |
| }) |
| |
| if err != nil { |
| return nil, err |
| } |
| |
| return &InvocationKey{EntityID: output.GetId(), EntityName: output.GetName()}, nil |
| } |
| |
| // FinishConfiguredTarget closes a ConfiguredTarget for editing. |
| func (s *Service) FinishConfiguredTarget(ctx context.Context, name string) (*ConfiguredTargetKey, error) { |
| output, err := s.client.FinishConfiguredTarget(ctx, &api.FinishConfiguredTargetRequest{ |
| AuthorizationToken: s.authToken, |
| Name: name, |
| }) |
| |
| if err != nil { |
| return nil, err |
| } |
| |
| return &ConfiguredTargetKey{EntityID: output.GetId(), EntityName: output.GetName()}, nil |
| } |
| |
| // FinishTarget closes a Target for editing. |
| func (s *Service) FinishTarget(ctx context.Context, name string) (*TargetKey, error) { |
| output, err := s.client.FinishTarget(ctx, &api.FinishTargetRequest{ |
| AuthorizationToken: s.authToken, |
| Name: name, |
| }) |
| |
| if err != nil { |
| return nil, err |
| } |
| |
| return &TargetKey{EntityID: output.GetId(), EntityName: output.GetName()}, nil |
| } |
| |
| // FinishInvocation closes an Invocation for editing. |
| func (s *Service) FinishInvocation(ctx context.Context, name string) (*InvocationKey, error) { |
| output, err := s.client.FinishInvocation(ctx, &api.FinishInvocationRequest{ |
| AuthorizationToken: s.authToken, |
| Name: name, |
| }) |
| |
| if err != nil { |
| return nil, err |
| } |
| |
| return &InvocationKey{EntityID: output.GetId(), EntityName: output.GetName()}, nil |
| } |