blob: 151712b02d3d4f48df684f708bf35e62dd635589 [file] [log] [blame]
// 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 main
// TODO(nmulcahey): Implement general Search RPC support in the buildbucket
// CLI and remove this + LKGS
import (
"context"
"flag"
"fmt"
"log"
"os"
"strconv"
"strings"
"go.chromium.org/luci/auth"
"go.chromium.org/luci/buildbucket/proto"
"go.chromium.org/luci/grpc/prpc"
"go.chromium.org/luci/auth/client/authcli"
"go.chromium.org/luci/hardcoded/chromeinfra"
)
var (
host string
builderID string
buildSet string
output string
// LUCI flags used to parse command-line authentication options.
authFlags authcli.Flags
)
func init() {
flag.StringVar(&host, "host", "cr-buildbucket.appspot.com", "the buildbucket host to use (default is cr-buildbucket.appspot.com)")
flag.StringVar(&builderID, "builder-id", "", "name of the builders to use as a reference (e.g. fuchsia/ci/garnet-x64)")
flag.StringVar(&buildSet, "build-set", "", "a unique buildset id in buildbucket (e.g. commit/gitiles/fuchsia.googlesource.com/topaz/+/e3127e0bd6d57da7a5959ee70eb0a396590e6d53)")
flag.StringVar(&output, "output-file", "", "name of the file to write snapshot to (default is stdout)")
authFlags = authcli.Flags{}
authFlags.Register(flag.CommandLine, chromeinfra.DefaultAuthOptions())
}
// praseBuilderID parses a builder ID of the form "fuchsia/ci/garnet-x64".
func parseBuilderID(builderID string) (*buildbucketpb.BuilderID, error) {
components := strings.SplitN(builderID, "/", 3)
if len(components) != 3 {
return nil, fmt.Errorf("failed to parse builder ID")
}
return &buildbucketpb.BuilderID{
Project: components[0],
Bucket: components[1],
Builder: components[2],
}, nil
}
func getBuildIDForBuilderAndBuildSet(ctx context.Context, host, buildSetID string, builderID *buildbucketpb.BuilderID, buildsClient buildbucketpb.BuildsClient) (int64, error) {
res, err := buildsClient.SearchBuilds(ctx, &buildbucketpb.SearchBuildsRequest{
Predicate: &buildbucketpb.BuildPredicate{
Builder: builderID,
Status: buildbucketpb.Status_SUCCESS,
Tags: []*buildbucketpb.StringPair{
&buildbucketpb.StringPair{
Key: "buildset",
Value: buildSetID,
},
},
},
})
if err != nil {
return -1, err
}
if len(res.Builds) == 0 {
return -1, fmt.Errorf("No builds returned")
}
return res.Builds[0].Id, nil
}
func main() {
flag.Parse()
if builderID == "" || buildSet == "" {
flag.PrintDefaults()
return
}
id, err := parseBuilderID(builderID)
if err != nil {
log.Fatalf(err.Error())
}
opts, err := authFlags.Options()
if err != nil {
log.Fatalf(err.Error())
}
ctx := context.Background()
authenticator := auth.NewAuthenticator(ctx, auth.OptionalLogin, opts)
client, err := authenticator.Client()
if err != nil {
log.Fatalf(err.Error())
}
buildsClient := buildbucketpb.NewBuildsPRPCClient(&prpc.Client{
C: client,
Host: host,
})
buildID, err := getBuildIDForBuilderAndBuildSet(ctx, host, buildSet, id, buildsClient)
if err != nil {
log.Fatalf(err.Error())
}
var outputFile *os.File
if output == "" {
outputFile = os.Stdout
} else {
outputFile, err = os.Create(output)
if err != nil {
log.Fatalf(err.Error())
}
defer outputFile.Close()
}
_, err = outputFile.Write([]byte(strconv.FormatInt(buildID, 10)))
if err != nil {
log.Fatalf("writing output: %v", err)
}
}