go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/luci_notify/notify/gitiles.go (about) 1 // Copyright 2017 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 notify 16 17 import ( 18 "context" 19 "net/http" 20 "time" 21 22 "go.chromium.org/luci/common/api/gitiles" 23 "go.chromium.org/luci/common/errors" 24 "go.chromium.org/luci/common/logging" 25 gitpb "go.chromium.org/luci/common/proto/git" 26 gitilespb "go.chromium.org/luci/common/proto/gitiles" 27 "go.chromium.org/luci/grpc/grpcutil" 28 "go.chromium.org/luci/server/auth" 29 ) 30 31 // HistoryFunc is a function that gets a list of commits from Gitiles for a 32 // specific repository, between oldRevision and newRevision, inclusive. 33 // 34 // If oldRevision is not reachable from newRevision, returns an empty slice 35 // and nil error. 36 type HistoryFunc func(ctx context.Context, luciProject, gerritHost, gerritProject, oldRevision, newRevision string) ([]*gitpb.Commit, error) 37 38 // gitilesHistory is an implementation of a HistoryFunc intended to be used 39 // in production (not for testing). 40 func gitilesHistory(ctx context.Context, luciProject, gerritHost, gerritProject, oldRevision, newRevision string) ([]*gitpb.Commit, error) { 41 ctx, cancel := context.WithTimeout(ctx, 30*time.Second) 42 defer cancel() 43 44 opts := []auth.RPCOption{ 45 auth.WithProject(luciProject), 46 auth.WithScopes(gitiles.OAuthScope), 47 } 48 transport, err := auth.GetRPCTransport(ctx, auth.AsProject, opts...) 49 if err != nil { 50 return nil, errors.Annotate(err, "getting RPC Transport").Err() 51 } 52 client, err := gitiles.NewRESTClient(&http.Client{Transport: transport}, gerritHost, true) 53 if err != nil { 54 return nil, errors.Annotate(err, "creating Gitiles client").Err() 55 } 56 57 req := &gitilespb.LogRequest{ 58 Project: gerritProject, 59 // With ~1, if newCommit.Revision == oldRevision, 60 // we'll get one commit, 61 // otherwise we will get 0 commits which is indistinguishable from 62 // oldRevision not being reachable from newRevision. 63 ExcludeAncestorsOf: oldRevision + "~1", 64 Committish: newRevision, 65 } 66 logging.Infof(ctx, "Gitiles request to host %q: %q", gerritHost, req) 67 res, err := gitiles.PagingLog(ctx, client, req, 0) 68 switch { 69 case err != nil: 70 return nil, grpcutil.WrapIfTransient(errors.Annotate(err, "fetching commit from Gitiles").Err()) 71 case len(res) > 0 && res[0].Id != newRevision: // Sanity check. 72 return nil, errors.Reason("gitiles returned inconsistent results").Err() 73 default: 74 return res, nil 75 } 76 }