Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gitserver: port FirstEverCommit functionality from client to git cli backend #62165

Conversation

ggilmore
Copy link
Contributor

@ggilmore ggilmore commented Apr 24, 2024

Part of #61689

Overview

This PR adapts the existing FirstEverCommit logic from the gitserver client to our new git cli backend. This is the first step as part of a set of stacked PRs to port the functionality to gRPC.

Existing func (c *clientImplementor) FirstEverCommit() implementation for reference:

func (c *clientImplementor) FirstEverCommit(ctx context.Context, repo api.RepoName) (_ *gitdomain.Commit, err error) {
ctx, _, endObservation := c.operations.firstEverCommit.With(ctx, &err, observation.Args{
MetricLabelValues: []string{c.scope},
Attrs: []attribute.KeyValue{
repo.Attr(),
},
})
defer endObservation(1, observation.Args{})
args := []string{"rev-list", "--reverse", "--date-order", "--max-parents=0", "HEAD"}
cmd := c.gitCommand(repo, args...)
out, err := cmd.Output(ctx)
if err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("git command %v failed (output: %q)", args, out))
}
lines := bytes.TrimSpace(out)
tokens := bytes.SplitN(lines, []byte("\n"), 2)
if len(tokens) == 0 {
return nil, errors.New("FirstEverCommit returned no revisions")
}
first := tokens[0]
id := api.CommitID(bytes.TrimSpace(first))
return c.GetCommit(ctx, repo, id)
}

Note

One of the existing tests that I ported called out that code insights depended on the formatting of a specific error string in order to detect if the repository was empty.

(Test in question):

// Added for awareness if this error message changes. Insights skip over empty repos and check against error message
t.Run("empty repo", func(t *testing.T) {
repo := MakeGitRepository(t)
_, err := NewClient("test").FirstEverCommit(ctx, repo)
wantErr := `git command [rev-list --reverse --date-order --max-parents=0 HEAD] failed (output: ""): exit status 128`
if err.Error() != wantErr {
t.Errorf("expected :%s, got :%s", wantErr, err)
}
})

(String checking logic in code insights):

https://github.com/sourcegraph/sourcegraph/blob/2443801b4ea4a4d48a8badf3c34ed2761af65db4/internal/insights/gitserver/first_commit.go#L18-L38

This is quite brittle, as any unrelated formatting change with our errors could change the semantics here. I decided to create a new sentinel error for this condition, gitdomain.RepoEmptyErr, to 1) better state our intent and 2) make this check more robust against minor formatting changes in our error libraries. When we generate the gRPC bindings, we'll need to create a new protobuf message for this error and write ToProto/FromProto functions, etc.

Test plan

Adapted existing unit tests

@cla-bot cla-bot bot added the cla-signed label Apr 24, 2024
@github-actions github-actions bot added team/product-platform team/source Tickets under the purview of Source - the one Source to graph it all labels Apr 24, 2024
Copy link
Contributor Author

ggilmore commented Apr 24, 2024

This stack of pull requests is managed by Graphite. Learn more about stacking.

Join @ggilmore and the rest of your teammates on Graphite Graphite

@ggilmore ggilmore marked this pull request as ready for review April 24, 2024 19:49
@ggilmore ggilmore force-pushed the 04-24-gitserver_grpc_create_exhaustive_logger_for_repository_service branch from 0b26aab to 2443801 Compare April 24, 2024 19:50
@ggilmore ggilmore force-pushed the 04-24-gitserver_port_firstevercommit_functionality_from_client_to_git_cli_backend branch from 01ed324 to 9147a1a Compare April 24, 2024 19:51
@ggilmore ggilmore marked this pull request as draft April 24, 2024 19:52
@ggilmore ggilmore force-pushed the 04-24-gitserver_port_firstevercommit_functionality_from_client_to_git_cli_backend branch from 9147a1a to 732f339 Compare April 24, 2024 20:10
@ggilmore ggilmore force-pushed the 04-24-gitserver_grpc_create_exhaustive_logger_for_repository_service branch from 2443801 to 5d7fa42 Compare April 24, 2024 20:24
@ggilmore ggilmore force-pushed the 04-24-gitserver_port_firstevercommit_functionality_from_client_to_git_cli_backend branch from 732f339 to bf4e953 Compare April 24, 2024 20:24
@ggilmore ggilmore marked this pull request as ready for review April 24, 2024 20:26
@ggilmore ggilmore requested a review from a team April 24, 2024 20:26
@ggilmore ggilmore force-pushed the 04-24-gitserver_grpc_create_exhaustive_logger_for_repository_service branch from 5d7fa42 to 772f91b Compare April 24, 2024 20:37
@ggilmore ggilmore force-pushed the 04-24-gitserver_port_firstevercommit_functionality_from_client_to_git_cli_backend branch from bf4e953 to cf13ed9 Compare April 24, 2024 20:37
@ggilmore ggilmore force-pushed the 04-24-gitserver_port_firstevercommit_functionality_from_client_to_git_cli_backend branch from cf13ed9 to 26d91b0 Compare April 24, 2024 21:31
var cmdFailedErr *CommandFailedError
if errors.As(err, &cmdFailedErr) {
if cmdFailedErr.ExitStatus == 129 && bytes.Contains(cmdFailedErr.Stderr, []byte(revListUsageString)) {
// If the error is due to an empty repository, return a sentinel error.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strange that it'd print the usage 😬 but thanks for the link, very helpful!

Base automatically changed from 04-24-gitserver_grpc_create_exhaustive_logger_for_repository_service to main April 24, 2024 23:04
Copy link
Member

@eseliger eseliger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is quite brittle, as any unrelated formatting change with our errors could change the semantics here. I decided to create a new sentinel error for this condition, gitdomain.RepoEmptyErr, to 1) better state our intent and 2) make this check more robust against minor formatting changes in our error libraries. When we generate the gRPC bindings, we'll need to create a new protobuf message for this error and write ToProto/FromProto functions, etc.

Strongly agree that no caller should depend on any git error message. We want to fully own the process of potentially switching to go-git, libgit2, or any self-made implementations that will yield different error strings.

One question - in alignment with gRPC saying "there should not be too many different error codes, because callers will most likely not add more than a few checks", should we try to keep the error types in check as well, and repurpose the RevisionNotFoundError here?
I think it's technically a correct error, since FirstEverCommit would try to look at HEAD, HEAD resolves to no branch yet, so HEAD is not found?

cmd/gitserver/internal/git/observability.go Outdated Show resolved Hide resolved
Comment on lines 25 to 26
if strings.Contains(err.Error(), emptyRepoErrMessage) {
return true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we remove this, after the gRPC API PR is merged? Once the client makes use of the gRPC API there's no way this could still be returned.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ping :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var cmdFailedErr *CommandFailedError
if errors.As(err, &cmdFailedErr) {
if cmdFailedErr.ExitStatus == 129 && bytes.Contains(cmdFailedErr.Stderr, []byte(revListUsageString)) {
// If the error is due to an empty repository, return a sentinel error.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strange that it'd print the usage 😬 but thanks for the link, very helpful!

cmd/gitserver/internal/git/gitcli/odb_test.go Outdated Show resolved Hide resolved
cmd/gitserver/internal/git/gitcli/odb.go Outdated Show resolved Hide resolved
cmd/gitserver/internal/git/gitcli/odb.go Outdated Show resolved Hide resolved
cmd/gitserver/internal/git/iface.go Outdated Show resolved Hide resolved
@ggilmore ggilmore force-pushed the 04-24-gitserver_port_firstevercommit_functionality_from_client_to_git_cli_backend branch 5 times, most recently from 78388ea to 1bbfc10 Compare April 26, 2024 18:59
@ggilmore ggilmore force-pushed the 04-24-gitserver_port_firstevercommit_functionality_from_client_to_git_cli_backend branch from 1bbfc10 to 521a52c Compare April 26, 2024 20:50
Comment on lines 25 to 26
if strings.Contains(err.Error(), emptyRepoErrMessage) {
return true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ping :)

@ggilmore ggilmore force-pushed the 04-24-gitserver_port_firstevercommit_functionality_from_client_to_git_cli_backend branch from 0dbd2b6 to dd47983 Compare April 30, 2024 17:02
@ggilmore ggilmore force-pushed the 04-24-gitserver_port_firstevercommit_functionality_from_client_to_git_cli_backend branch 4 times, most recently from 0a3ffb5 to a8d5080 Compare April 30, 2024 20:34
@ggilmore ggilmore force-pushed the 04-24-gitserver_port_firstevercommit_functionality_from_client_to_git_cli_backend branch from a8d5080 to df87c59 Compare April 30, 2024 22:29
@ggilmore ggilmore merged commit 75e6258 into main May 1, 2024
16 checks passed
@ggilmore ggilmore deleted the 04-24-gitserver_port_firstevercommit_functionality_from_client_to_git_cli_backend branch May 1, 2024 04:14
Copy link
Contributor Author

ggilmore commented May 1, 2024

Merge activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla-signed team/product-platform team/source Tickets under the purview of Source - the one Source to graph it all
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants