go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/analysis/internal/gerrit/gerrit.go (about)

     1  // Copyright 2022 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package gerrit contains logic for interacting with Gerrit.
    16  package gerrit
    17  
    18  import (
    19  	"context"
    20  	"net/http"
    21  
    22  	"go.chromium.org/luci/common/api/gerrit"
    23  	"go.chromium.org/luci/common/errors"
    24  	gerritpb "go.chromium.org/luci/common/proto/gerrit"
    25  	"go.chromium.org/luci/server/auth"
    26  
    27  	"go.chromium.org/luci/analysis/internal/scopedauth"
    28  )
    29  
    30  // testingGerritClientKey is the context key to indicate using a substitute
    31  // Gerrit client in tests.
    32  var testingGerritClientKey = "used in tests only for setting the mock gerrit client"
    33  
    34  // gerritClientFactory generates gerrit clients for testing that are specific to
    35  // the host requested.
    36  type gerritClientFactory interface {
    37  	WithHost(host string) gerritpb.GerritClient
    38  }
    39  
    40  // Client is the client to communicate with Gerrit.
    41  // It wraps a gerritpb.GerritClient.
    42  type Client struct {
    43  	gerritClient gerritpb.GerritClient
    44  }
    45  
    46  func newGerritClient(ctx context.Context, host, project string) (gerritpb.GerritClient, error) {
    47  	if testingClientFactory, ok := ctx.Value(&testingGerritClientKey).(gerritClientFactory); ok {
    48  		// return a Gerrit client for tests.
    49  		return testingClientFactory.WithHost(host), nil
    50  	}
    51  
    52  	t, err := scopedauth.GetRPCTransport(ctx, project, auth.WithScopes(gerrit.OAuthScope))
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	return gerrit.NewRESTClient(&http.Client{Transport: t}, host, true)
    58  }
    59  
    60  // NewClient creates a client to communicate with Gerrit, acting as the
    61  // given LUCI Project.
    62  func NewClient(ctx context.Context, host, project string) (*Client, error) {
    63  	client, err := newGerritClient(ctx, host, project)
    64  	if err != nil {
    65  		return nil, errors.Annotate(err, "creating Gerrit client for host %s", host).Err()
    66  	}
    67  
    68  	return &Client{
    69  		gerritClient: client,
    70  	}, nil
    71  }
    72  
    73  // GetChange gets a gerrit change by its ID.
    74  func (c *Client) GetChange(ctx context.Context, req *gerritpb.GetChangeRequest) (*gerritpb.ChangeInfo, error) {
    75  	res, err := c.gerritClient.GetChange(ctx, req)
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	return res, nil
    80  }