Skip to content

Commit 462d5ef

Browse files
authored
Indexing from CLI now falls back to full reindex if necessary (#9517)
Notably, this PR adds a check for codesearch-enablement, and injection of the repo access token, to the main app server, before forwarding the indexing request to the codesearch server. I was able to mostly test this locally, but I wasn't able to launch the server with the github integration enabled, so I'm not confident in codesearch.go `getGitRepoAccessToken` code. I pulled most of this from [service.go](https://github.com/buildbuddy-io/buildbuddy/blob/master/enterprise/server/workflow/service/service.go#L629).
1 parent 297fd71 commit 462d5ef

File tree

7 files changed

+119
-19
lines changed

7 files changed

+119
-19
lines changed

cli/index/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ go_library(
1616
"//proto:index_go_proto",
1717
"//server/util/git",
1818
"//server/util/grpc_client",
19+
"//server/util/status",
1920
"@org_golang_google_grpc//metadata",
2021
],
2122
)

cli/index/index.go

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/buildbuddy-io/buildbuddy/codesearch/github"
1414
"github.com/buildbuddy-io/buildbuddy/server/util/git"
1515
"github.com/buildbuddy-io/buildbuddy/server/util/grpc_client"
16+
"github.com/buildbuddy-io/buildbuddy/server/util/status"
1617
"google.golang.org/grpc/metadata"
1718

1819
bbspb "github.com/buildbuddy-io/buildbuddy/proto/buildbuddy_service"
@@ -71,6 +72,40 @@ func getRepoInfo(gc github.GitClient) (*git.RepoURL, string, error) {
7172
return parseRepoURL, headSHA, nil
7273
}
7374

75+
func buildIndexRequest(gc github.GitClient, repoURL *git.RepoURL, headSHA, lastIndexSHA string) (*inpb.IndexRequest, error) {
76+
req := &inpb.IndexRequest{
77+
GitRepo: &gitpb.GitRepo{
78+
RepoUrl: repoURL.String(),
79+
Username: repoURL.Owner,
80+
},
81+
}
82+
83+
if lastIndexSHA != "" {
84+
update, err := github.ComputeIncrementalUpdate(gc, lastIndexSHA, headSHA)
85+
if err != nil {
86+
if status.IsFailedPreconditionError(err) {
87+
log.Printf("Failed to compute incremental update, falling back to full re-index: %s", err)
88+
} else {
89+
return nil, fmt.Errorf("failed to compute incremental update: %w", err)
90+
}
91+
} else {
92+
req.ReplacementStrategy = inpb.ReplacementStrategy_INCREMENTAL
93+
req.Update = update
94+
return req, nil
95+
}
96+
} else {
97+
log.Printf("No previous index found for repo %s, performing full re-index.", repoURL)
98+
}
99+
100+
req.ReplacementStrategy = inpb.ReplacementStrategy_REPLACE_REPO
101+
req.RepoState = &gitpb.RepoState{
102+
CommitSha: headSHA,
103+
}
104+
req.Async = true // Don't wait for full re-indexes to complete.
105+
// Access token will be added by the server based on user auth.
106+
return req, nil
107+
}
108+
74109
func indexRepo() error {
75110
ctx := context.Background()
76111

@@ -101,27 +136,24 @@ func indexRepo() error {
101136
return fmt.Errorf("failed to get repo status: %w", err)
102137
}
103138

104-
update, err := github.ComputeIncrementalUpdate(gc, rsp.GetLastIndexedCommitSha(), headSHA)
139+
update, err := buildIndexRequest(gc, parsedRepoURL, headSHA, rsp.GetLastIndexedCommitSha())
105140
if err != nil {
106-
return fmt.Errorf("incremental update aborted: %w", err)
107-
}
108-
109-
req := &inpb.IndexRequest{
110-
GitRepo: &gitpb.GitRepo{
111-
RepoUrl: parsedRepoURL.String(),
112-
},
113-
ReplacementStrategy: inpb.ReplacementStrategy_INCREMENTAL,
114-
Update: update,
141+
return fmt.Errorf("failed to create index request: %w", err)
115142
}
116143

117-
_, err = client.Index(ctx, req)
144+
_, err = client.Index(ctx, update)
118145
if err != nil {
119146
return err
120147
}
121148

122-
firstSha := update.Commits[0].GetSha()
123-
lastSha := update.Commits[len(update.Commits)-1].GetSha()
124-
log.Printf("Completed incremental update for %s, %s..%s", parsedRepoURL.String(), firstSha, lastSha)
149+
if update.ReplacementStrategy == inpb.ReplacementStrategy_REPLACE_REPO {
150+
log.Printf("Re-indexing entire repo %s at commit %s", parsedRepoURL.String(), headSHA)
151+
} else {
152+
commits := update.GetUpdate().GetCommits()
153+
firstSha := commits[0].GetSha()
154+
lastSha := commits[len(commits)-1].GetSha()
155+
log.Printf("Completed incremental update for %s, %s..%s", parsedRepoURL.String(), firstSha, lastSha)
156+
}
125157
return nil
126158
}
127159

codesearch/github/github.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,10 +284,10 @@ func ComputeIncrementalUpdate(gc GitClient, firstSha, lastSha string) (*inpb.Inc
284284
changes := strings.Split(strings.TrimSpace(changesStr), "\n")
285285

286286
if len(changes) > maxAllowedChanges {
287-
return nil, fmt.Errorf("too many changes in commit range %s..%s: %d", firstSha, lastSha, len(changes))
287+
return nil, status.FailedPreconditionErrorf("too many changes in commit range %s..%s: %d", firstSha, lastSha, len(changes))
288288
}
289289
if len(changes) == 0 || (len(changes) == 1 && len(changes[0]) == 0) {
290-
return nil, fmt.Errorf("no commits found between %s and %s", firstSha, lastSha)
290+
return nil, status.FailedPreconditionErrorf("no commits found between %s and %s", firstSha, lastSha)
291291
}
292292

293293
result := &inpb.IncrementalUpdate{

codesearch/server/server.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,10 @@ func (css *codesearchServer) RepoStatus(ctx context.Context, req *inpb.RepoStatu
369369

370370
rev, err := github.GetLastIndexedCommitSha(r, repoURL)
371371
if err != nil {
372-
return nil, err
372+
// If there's no status, return an empty commit SHA, but don't error.
373+
if !status.IsNotFoundError(err) {
374+
return nil, err
375+
}
373376
}
374377

375378
return &inpb.RepoStatusResponse{

codesearch/server/server_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,10 @@ func TestRepoStatus_NoStatus(t *testing.T) {
109109
response, err := server.RepoStatus(context.Background(), &inpb.RepoStatusRequest{
110110
RepoUrl: "github.com/buildbuddy-io/buildbuddy",
111111
})
112-
assert.True(t, status.IsNotFoundError(err), "expected status.NotFoundError, got: %v", err)
113-
assert.Nil(t, response)
112+
require.NoError(t, err)
113+
assert.Equal(t, &inpb.RepoStatusResponse{
114+
LastIndexedCommitSha: "",
115+
}, response)
114116
}
115117

116118
func TestRepoStatus_InvalidRepo(t *testing.T) {

enterprise/server/backends/codesearch/BUILD

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ go_library(
1111
"//proto:search_go_proto",
1212
"//server/environment",
1313
"//server/real_environment",
14+
"//server/tables",
15+
"//server/util/claims",
16+
"//server/util/db",
1417
"//server/util/flag",
1518
"//server/util/grpc_client",
1619
"//server/util/status",

enterprise/server/backends/codesearch/codesearch.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import (
55

66
"github.com/buildbuddy-io/buildbuddy/server/environment"
77
"github.com/buildbuddy-io/buildbuddy/server/real_environment"
8+
"github.com/buildbuddy-io/buildbuddy/server/tables"
9+
"github.com/buildbuddy-io/buildbuddy/server/util/claims"
10+
"github.com/buildbuddy-io/buildbuddy/server/util/db"
811
"github.com/buildbuddy-io/buildbuddy/server/util/flag"
912
"github.com/buildbuddy-io/buildbuddy/server/util/grpc_client"
1013
"github.com/buildbuddy-io/buildbuddy/server/util/status"
@@ -20,6 +23,7 @@ var (
2023

2124
type CodesearchService struct {
2225
client csspb.CodesearchServiceClient
26+
env environment.Env
2327
}
2428

2529
func Register(realEnv *real_environment.RealEnv) error {
@@ -41,6 +45,7 @@ func New(env environment.Env) (*CodesearchService, error) {
4145
}
4246
return &CodesearchService{
4347
client: csspb.NewCodesearchServiceClient(conn),
48+
env: env,
4449
}, nil
4550
}
4651

@@ -49,7 +54,61 @@ func (css *CodesearchService) Search(ctx context.Context, req *srpb.SearchReques
4954
return css.client.Search(ctx, req)
5055
}
5156

57+
func (css *CodesearchService) getGitRepoAccessToken(ctx context.Context, groupId, repoURL string) (string, error) {
58+
ghas := css.env.GetGitHubAppService()
59+
if ghas == nil {
60+
return "", status.InternalError("GitHub App service is not configured")
61+
}
62+
63+
gha, err := ghas.GetGitHubAppForOwner(ctx, repoURL)
64+
if err != nil {
65+
return "", status.UnavailableErrorf("could not get GitHub app for repo %q: %s", repoURL, err)
66+
}
67+
68+
gitRepository := &tables.GitRepository{}
69+
err = css.env.GetDBHandle().NewQuery(ctx, "hosted_runner_get_for_repo").Raw(`
70+
SELECT *
71+
FROM "GitRepositories"
72+
WHERE group_id = ?
73+
AND repo_url = ?
74+
`, groupId, repoURL).Take(gitRepository)
75+
if err != nil {
76+
if db.IsRecordNotFound(err) {
77+
return "", status.NotFoundErrorf("repo %q not found", repoURL)
78+
}
79+
return "", status.InternalErrorf("failed to look up repo %s: %s", repoURL, err)
80+
}
81+
82+
token, err := gha.GetRepositoryInstallationToken(ctx, gitRepository)
83+
if err != nil {
84+
return "", status.UnavailableErrorf("could not get access token for repo %q: %s", repoURL, err)
85+
}
86+
87+
return token, nil
88+
}
89+
5290
func (css *CodesearchService) Index(ctx context.Context, req *inpb.IndexRequest) (*inpb.IndexResponse, error) {
91+
claims, err := claims.ClaimsFromContext(ctx)
92+
if err != nil {
93+
return nil, status.UnauthenticatedErrorf("failed to get claims from context: %s", err)
94+
}
95+
96+
g, err := css.env.GetUserDB().GetGroupByID(ctx, claims.GroupID)
97+
if err != nil {
98+
return nil, err
99+
}
100+
if !g.CodeSearchEnabled {
101+
return nil, status.FailedPreconditionError("codesearch is not enabled")
102+
}
103+
104+
if req.GetReplacementStrategy() == inpb.ReplacementStrategy_REPLACE_REPO {
105+
token, err := css.getGitRepoAccessToken(ctx, claims.GroupID, req.GetGitRepo().GetRepoUrl())
106+
if err != nil {
107+
return nil, err
108+
}
109+
req.GetGitRepo().AccessToken = token
110+
}
111+
53112
return css.client.Index(ctx, req)
54113
}
55114

0 commit comments

Comments
 (0)