golang.org/x/build@v0.0.0-20240506185731-218518f32b70/internal/task/buildbucket.go (about)

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package task
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  
    11  	pb "go.chromium.org/luci/buildbucket/proto"
    12  	"google.golang.org/protobuf/types/known/structpb"
    13  )
    14  
    15  type BuildBucketClient interface {
    16  	// ListBuilders lists all the builders in bucket, keyed by their builder names.
    17  	ListBuilders(ctx context.Context, bucket string) (map[string]*pb.BuilderConfig, error)
    18  	// RunBuild runs a builder at commit with properties and returns its ID.
    19  	RunBuild(ctx context.Context, bucket, builder string, commit *pb.GitilesCommit, properties map[string]*structpb.Value) (int64, error)
    20  	// Completed reports whether a build has finished, returning an error if
    21  	// it's failed. It's suitable for use with AwaitCondition.
    22  	Completed(ctx context.Context, id int64) (string, bool, error)
    23  	// SearchBuilds searches for builds matching pred and returns their IDs.
    24  	SearchBuilds(ctx context.Context, pred *pb.BuildPredicate) ([]int64, error)
    25  }
    26  
    27  type RealBuildBucketClient struct {
    28  	BuildersClient pb.BuildersClient
    29  	BuildsClient   pb.BuildsClient
    30  }
    31  
    32  func (c *RealBuildBucketClient) ListBuilders(ctx context.Context, bucket string) (map[string]*pb.BuilderConfig, error) {
    33  	var pageToken string
    34  	builders := map[string]*pb.BuilderConfig{}
    35  nextPage:
    36  	resp, err := c.BuildersClient.ListBuilders(ctx, &pb.ListBuildersRequest{
    37  		Project:   "golang",
    38  		Bucket:    bucket,
    39  		PageSize:  1000,
    40  		PageToken: pageToken,
    41  	})
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  	for _, b := range resp.Builders {
    46  		builders[b.Id.Builder] = b.Config
    47  	}
    48  	if resp.NextPageToken != "" {
    49  		pageToken = resp.NextPageToken
    50  		goto nextPage
    51  	}
    52  	return builders, nil
    53  }
    54  
    55  func (c *RealBuildBucketClient) RunBuild(ctx context.Context, bucket, builder string, commit *pb.GitilesCommit, properties map[string]*structpb.Value) (int64, error) {
    56  	req := &pb.ScheduleBuildRequest{
    57  		Builder:  &pb.BuilderID{Project: "golang", Bucket: bucket, Builder: builder},
    58  		Priority: 20,
    59  		Properties: &structpb.Struct{
    60  			Fields: properties,
    61  		},
    62  		GitilesCommit: commit,
    63  	}
    64  	build, err := c.BuildsClient.ScheduleBuild(ctx, req)
    65  	if err != nil {
    66  		return 0, err
    67  	}
    68  	return build.Id, err
    69  }
    70  
    71  func (c *RealBuildBucketClient) Completed(ctx context.Context, id int64) (string, bool, error) {
    72  	build, err := c.BuildsClient.GetBuildStatus(ctx, &pb.GetBuildStatusRequest{
    73  		Id: id,
    74  	})
    75  	if err != nil {
    76  		return "", false, err
    77  	}
    78  	if build.Status&pb.Status_ENDED_MASK == 0 {
    79  		return "", false, nil
    80  	}
    81  	if build.Status&pb.Status_ENDED_MASK != 0 && build.Status != pb.Status_SUCCESS {
    82  		return "", true, fmt.Errorf("build failed with status %v, see https://ci.chromium.org/b/%v: %v", build.Status, id, build.SummaryMarkdown)
    83  	}
    84  	return build.SummaryMarkdown, true, nil
    85  }
    86  
    87  func (c *RealBuildBucketClient) SearchBuilds(ctx context.Context, pred *pb.BuildPredicate) ([]int64, error) {
    88  	resp, err := c.BuildsClient.SearchBuilds(ctx, &pb.SearchBuildsRequest{
    89  		Predicate: pred,
    90  	})
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  	if resp.NextPageToken != "" {
    95  		return nil, fmt.Errorf("page size to SearchBuilds insufficient")
    96  	}
    97  	var results []int64
    98  	for _, b := range resp.Builds {
    99  		results = append(results, b.Id)
   100  	}
   101  	return results, nil
   102  }