diff options
author | Patrick Steinhardt <psteinhardt@gitlab.com> | 2022-07-29 09:16:09 +0300 |
---|---|---|
committer | Patrick Steinhardt <psteinhardt@gitlab.com> | 2022-07-29 09:58:33 +0300 |
commit | 415d32e1df58972d715010d63954b3618d5093bf (patch) | |
tree | 103a03ba0545d67c023ff609e6d11d9aa4231611 | |
parent | a14e97112b0dc78266df414e98c7d307e9fdf859 (diff) |
ref: Split out code related to the FindTag RPC
The FindTag RPC is implemented alongside a set of other RPCs in the
`refs.go` file. It's thus a tad hard to find and doesn't conform to our
usual best practice, where each RPC is implemented in its own code unit.
Move the code into a separate file to make it easier to locate.
-rw-r--r-- | internal/gitaly/service/ref/find_tag.go | 120 | ||||
-rw-r--r-- | internal/gitaly/service/ref/find_tag_test.go | 318 | ||||
-rw-r--r-- | internal/gitaly/service/ref/refs.go | 109 | ||||
-rw-r--r-- | internal/gitaly/service/ref/refs_test.go | 298 |
4 files changed, 438 insertions, 407 deletions
diff --git a/internal/gitaly/service/ref/find_tag.go b/internal/gitaly/service/ref/find_tag.go new file mode 100644 index 000000000..9f33ced3a --- /dev/null +++ b/internal/gitaly/service/ref/find_tag.go @@ -0,0 +1,120 @@ +package ref + +import ( + "bufio" + "context" + "errors" + "fmt" + "strings" + + "gitlab.com/gitlab-org/gitaly/v15/internal/git" + "gitlab.com/gitlab-org/gitaly/v15/internal/git/catfile" + "gitlab.com/gitlab-org/gitaly/v15/internal/helper" + "gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypb" +) + +func (s *server) FindTag(ctx context.Context, in *gitalypb.FindTagRequest) (*gitalypb.FindTagResponse, error) { + if err := s.validateFindTagRequest(in); err != nil { + return nil, helper.ErrInvalidArgument(err) + } + + repo := s.localrepo(in.GetRepository()) + + tag, err := s.findTag(ctx, repo, in.GetTagName()) + if err != nil { + return nil, helper.ErrInternal(err) + } + + return &gitalypb.FindTagResponse{Tag: tag}, nil +} + +// parseTagLine parses a line of text with the output format %(objectname) %(objecttype) %(refname:lstrip=2) +func parseTagLine(ctx context.Context, objectReader catfile.ObjectReader, tagLine string) (*gitalypb.Tag, error) { + fields := strings.SplitN(tagLine, " ", 3) + if len(fields) != 3 { + return nil, fmt.Errorf("invalid output from for-each-ref command: %v", tagLine) + } + + tagID, refType, refName := fields[0], fields[1], fields[2] + + tag := &gitalypb.Tag{ + Id: tagID, + Name: []byte(refName), + } + + switch refType { + // annotated tag + case "tag": + tag, err := catfile.GetTag(ctx, objectReader, git.Revision(tagID), refName) + if err != nil { + return nil, fmt.Errorf("getting annotated tag: %v", err) + } + catfile.TrimTagMessage(tag) + + return tag, nil + case "commit": + commit, err := catfile.GetCommit(ctx, objectReader, git.Revision(tagID)) + if err != nil { + return nil, fmt.Errorf("getting commit catfile: %v", err) + } + tag.TargetCommit = commit + return tag, nil + default: + return tag, nil + } +} + +func (s *server) findTag(ctx context.Context, repo git.RepositoryExecutor, tagName []byte) (*gitalypb.Tag, error) { + tagCmd, err := repo.Exec(ctx, + git.SubCmd{ + Name: "tag", + Flags: []git.Option{ + git.Flag{Name: "-l"}, git.ValueFlag{Name: "--format", Value: tagFormat}, + }, + Args: []string{string(tagName)}, + }, + git.WithRefTxHook(repo), + ) + if err != nil { + return nil, fmt.Errorf("for-each-ref error: %v", err) + } + + objectReader, cancel, err := s.catfileCache.ObjectReader(ctx, repo) + if err != nil { + return nil, err + } + defer cancel() + + var tag *gitalypb.Tag + + scanner := bufio.NewScanner(tagCmd) + if scanner.Scan() { + tag, err = parseTagLine(ctx, objectReader, scanner.Text()) + if err != nil { + return nil, err + } + } else { + return nil, errors.New("no tag found") + } + + if err = tagCmd.Wait(); err != nil { + return nil, err + } + + return tag, nil +} + +func (s *server) validateFindTagRequest(in *gitalypb.FindTagRequest) error { + if in.GetRepository() == nil { + return errors.New("repository is empty") + } + + if _, err := s.locator.GetRepoPath(in.GetRepository()); err != nil { + return fmt.Errorf("invalid git directory: %v", err) + } + + if in.GetTagName() == nil { + return errors.New("tag name is empty") + } + return nil +} diff --git a/internal/gitaly/service/ref/find_tag_test.go b/internal/gitaly/service/ref/find_tag_test.go new file mode 100644 index 000000000..13a2be53c --- /dev/null +++ b/internal/gitaly/service/ref/find_tag_test.go @@ -0,0 +1,318 @@ +//go:build !gitaly_test_sha256 + +package ref + +import ( + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/v15/internal/git" + "gitlab.com/gitlab-org/gitaly/v15/internal/git/catfile" + "gitlab.com/gitlab-org/gitaly/v15/internal/git/gittest" + "gitlab.com/gitlab-org/gitaly/v15/internal/git/localrepo" + "gitlab.com/gitlab-org/gitaly/v15/internal/git/updateref" + "gitlab.com/gitlab-org/gitaly/v15/internal/helper" + "gitlab.com/gitlab-org/gitaly/v15/internal/testhelper" + "gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypb" + "google.golang.org/grpc/codes" + "google.golang.org/protobuf/types/known/timestamppb" +) + +func TestSuccessfulFindTagRequest(t *testing.T) { + ctx := testhelper.Context(t) + cfg, repoProto, repoPath, client := setupRefService(ctx, t) + + repo := localrepo.NewTestRepo(t, cfg, repoProto) + + blobID := git.ObjectID("faaf198af3a36dbf41961466703cc1d47c61d051") + commitID := git.ObjectID("6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9") + + gitCommit := testhelper.GitLabTestCommit(commitID.String()) + + bigCommitID := gittest.WriteCommit(t, cfg, repoPath, + gittest.WithBranch("local-big-commits"), + gittest.WithMessage("An empty commit with REALLY BIG message\n\n"+strings.Repeat("a", helper.MaxCommitOrTagMessageSize+1)), + gittest.WithParents("60ecb67744cb56576c30214ff52294f8ce2def98"), + ) + bigCommit, err := repo.ReadCommit(ctx, git.Revision(bigCommitID)) + require.NoError(t, err) + + annotatedTagID := gittest.WriteTag(t, cfg, repoPath, "v1.2.0", blobID.Revision(), gittest.WriteTagConfig{Message: "Blob tag"}) + + gittest.WriteTag(t, cfg, repoPath, "v1.3.0", commitID.Revision()) + gittest.WriteTag(t, cfg, repoPath, "v1.4.0", blobID.Revision()) + + // To test recursive resolving to a commit + gittest.WriteTag(t, cfg, repoPath, "v1.5.0", "v1.3.0") + + // A tag to commit with a big message + gittest.WriteTag(t, cfg, repoPath, "v1.6.0", bigCommitID.Revision()) + + // A tag with a big message + bigMessage := strings.Repeat("a", 11*1024) + bigMessageTag1ID := gittest.WriteTag(t, cfg, repoPath, "v1.7.0", commitID.Revision(), gittest.WriteTagConfig{Message: bigMessage}) + + // A tag with a commit id as its name + commitTagID := gittest.WriteTag(t, cfg, repoPath, commitID.String(), commitID.Revision(), gittest.WriteTagConfig{Message: "commit tag with a commit sha as the name"}) + + // a tag of a tag + tagOfTagID := gittest.WriteTag(t, cfg, repoPath, "tag-of-tag", commitTagID.Revision(), gittest.WriteTagConfig{Message: "tag of a tag"}) + + expectedTags := []*gitalypb.Tag{ + { + Name: []byte(commitID), + Id: commitTagID.String(), + TargetCommit: gitCommit, + Message: []byte("commit tag with a commit sha as the name"), + MessageSize: 40, + Tagger: &gitalypb.CommitAuthor{ + Name: []byte(gittest.DefaultCommitterName), + Email: []byte(gittest.DefaultCommitterMail), + Date: timestamppb.New(gittest.DefaultCommitTime), + Timezone: []byte("+0100"), + }, + }, + { + Name: []byte("tag-of-tag"), + Id: tagOfTagID.String(), + TargetCommit: gitCommit, + Message: []byte("tag of a tag"), + MessageSize: 12, + Tagger: &gitalypb.CommitAuthor{ + Name: []byte(gittest.DefaultCommitterName), + Email: []byte(gittest.DefaultCommitterMail), + Date: timestamppb.New(gittest.DefaultCommitTime), + Timezone: []byte("+0100"), + }, + }, + { + Name: []byte("v1.0.0"), + Id: "f4e6814c3e4e7a0de82a9e7cd20c626cc963a2f8", + TargetCommit: gitCommit, + Message: []byte("Release"), + MessageSize: 7, + Tagger: &gitalypb.CommitAuthor{ + Name: []byte("Dmitriy Zaporozhets"), + Email: []byte("dmitriy.zaporozhets@gmail.com"), + Date: ×tamppb.Timestamp{Seconds: 1393491299}, + Timezone: []byte("+0200"), + }, + SignatureType: gitalypb.SignatureType_NONE, + }, + { + Name: []byte("v1.1.0"), + Id: "8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b", + TargetCommit: testhelper.GitLabTestCommit("5937ac0a7beb003549fc5fd26fc247adbce4a52e"), + Message: []byte("Version 1.1.0"), + MessageSize: 13, + Tagger: &gitalypb.CommitAuthor{ + Name: []byte("Dmitriy Zaporozhets"), + Email: []byte("dmitriy.zaporozhets@gmail.com"), + Date: ×tamppb.Timestamp{Seconds: 1393505709}, + Timezone: []byte("+0200"), + }, + }, + { + Name: []byte("v1.1.1"), + Id: "8f03acbcd11c53d9c9468078f32a2622005a4841", + TargetCommit: testhelper.GitLabTestCommit("189a6c924013fc3fe40d6f1ec1dc20214183bc97"), + Message: []byte("x509 signed tag\n-----BEGIN SIGNED MESSAGE-----\nMIISfwYJKoZIhvcNAQcCoIIScDCCEmwCAQExDTALBglghkgBZQMEAgEwCwYJKoZI\nhvcNAQcBoIIP8zCCB3QwggVcoAMCAQICBBXXLOIwDQYJKoZIhvcNAQELBQAwgbYx\nCzAJBgNVBAYTAkRFMQ8wDQYDVQQIDAZCYXllcm4xETAPBgNVBAcMCE11ZW5jaGVu\nMRAwDgYDVQQKDAdTaWVtZW5zMREwDwYDVQQFEwhaWlpaWlpBNjEdMBsGA1UECwwU\nU2llbWVucyBUcnVzdCBDZW50ZXIxPzA9BgNVBAMMNlNpZW1lbnMgSXNzdWluZyBD\nQSBNZWRpdW0gU3RyZW5ndGggQXV0aGVudGljYXRpb24gMjAxNjAeFw0xNzAyMDMw\nNjU4MzNaFw0yMDAyMDMwNjU4MzNaMFsxETAPBgNVBAUTCFowMDBOV0RIMQ4wDAYD\nVQQqDAVSb2dlcjEOMAwGA1UEBAwFTWVpZXIxEDAOBgNVBAoMB1NpZW1lbnMxFDAS\nBgNVBAMMC01laWVyIFJvZ2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\nAQEAuBNea/68ZCnHYQjpm/k3ZBG0wBpEKSwG6lk9CEQlSxsqVLQHAoAKBIlJm1in\nYVLcK/Sq1yhYJ/qWcY/M53DhK2rpPuhtrWJUdOUy8EBWO20F4bd4Fw9pO7jt8bme\nu33TSrK772vKjuppzB6SeG13Cs08H+BIeD106G27h7ufsO00pvsxoSDL+uc4slnr\npBL+2TAL7nSFnB9QHWmRIK27SPqJE+lESdb0pse11x1wjvqKy2Q7EjL9fpqJdHzX\nNLKHXd2r024TOORTa05DFTNR+kQEKKV96XfpYdtSBomXNQ44cisiPBJjFtYvfnFE\nwgrHa8fogn/b0C+A+HAoICN12wIDAQABo4IC4jCCAt4wHQYDVR0OBBYEFCF+gkUp\nXQ6xGc0kRWXuDFxzA14zMEMGA1UdEQQ8MDqgIwYKKwYBBAGCNxQCA6AVDBNyLm1l\naWVyQHNpZW1lbnMuY29tgRNyLm1laWVyQHNpZW1lbnMuY29tMA4GA1UdDwEB/wQE\nAwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwgcoGA1UdHwSBwjCB\nvzCBvKCBuaCBtoYmaHR0cDovL2NoLnNpZW1lbnMuY29tL3BraT9aWlpaWlpBNi5j\ncmyGQWxkYXA6Ly9jbC5zaWVtZW5zLm5ldC9DTj1aWlpaWlpBNixMPVBLST9jZXJ0\naWZpY2F0ZVJldm9jYXRpb25MaXN0hklsZGFwOi8vY2wuc2llbWVucy5jb20vQ049\nWlpaWlpaQTYsbz1UcnVzdGNlbnRlcj9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0\nMEUGA1UdIAQ+MDwwOgYNKwYBBAGhaQcCAgMBAzApMCcGCCsGAQUFBwIBFhtodHRw\nOi8vd3d3LnNpZW1lbnMuY29tL3BraS8wDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAW\ngBT4FV1HDGx3e3LEAheRaKK292oJRDCCAQQGCCsGAQUFBwEBBIH3MIH0MDIGCCsG\nAQUFBzAChiZodHRwOi8vYWguc2llbWVucy5jb20vcGtpP1paWlpaWkE2LmNydDBB\nBggrBgEFBQcwAoY1bGRhcDovL2FsLnNpZW1lbnMubmV0L0NOPVpaWlpaWkE2LEw9\nUEtJP2NBQ2VydGlmaWNhdGUwSQYIKwYBBQUHMAKGPWxkYXA6Ly9hbC5zaWVtZW5z\nLmNvbS9DTj1aWlpaWlpBNixvPVRydXN0Y2VudGVyP2NBQ2VydGlmaWNhdGUwMAYI\nKwYBBQUHMAGGJGh0dHA6Ly9vY3NwLnBraS1zZXJ2aWNlcy5zaWVtZW5zLmNvbTAN\nBgkqhkiG9w0BAQsFAAOCAgEAXPVcX6vaEcszJqg5IemF9aFTlwTrX5ITNIpzcqG+\nkD5haOf2mZYLjl+MKtLC1XfmIsGCUZNb8bjP6QHQEI+2d6x/ZOqPq7Kd7PwVu6x6\nxZrkDjUyhUbUntT5+RBy++l3Wf6Cq6Kx+K8ambHBP/bu90/p2U8KfFAG3Kr2gI2q\nfZrnNMOxmJfZ3/sXxssgLkhbZ7hRa+MpLfQ6uFsSiat3vlawBBvTyHnoZ/7oRc8y\nqi6QzWcd76CPpMElYWibl+hJzKbBZUWvc71AzHR6i1QeZ6wubYz7vr+FF5Y7tnxB\nVz6omPC9XAg0F+Dla6Zlz3Awj5imCzVXa+9SjtnsidmJdLcKzTAKyDewewoxYOOJ\nj3cJU7VSjJPl+2fVmDBaQwcNcUcu/TPAKApkegqO7tRF9IPhjhW8QkRnkqMetO3D\nOXmAFVIsEI0Hvb2cdb7B6jSpjGUuhaFm9TCKhQtCk2p8JCDTuaENLm1x34rrJKbT\n2vzyYN0CZtSkUdgD4yQxK9VWXGEzexRisWb4AnZjD2NAquLPpXmw8N0UwFD7MSpC\ndpaX7FktdvZmMXsnGiAdtLSbBgLVWOD1gmJFDjrhNbI8NOaOaNk4jrfGqNh5lhGU\n4DnBT2U6Cie1anLmFH/oZooAEXR2o3Nu+1mNDJChnJp0ovs08aa3zZvBdcloOvfU\nqdowggh3MIIGX6ADAgECAgQtyi/nMA0GCSqGSIb3DQEBCwUAMIGZMQswCQYDVQQG\nEwJERTEPMA0GA1UECAwGQmF5ZXJuMREwDwYDVQQHDAhNdWVuY2hlbjEQMA4GA1UE\nCgwHU2llbWVuczERMA8GA1UEBRMIWlpaWlpaQTExHTAbBgNVBAsMFFNpZW1lbnMg\nVHJ1c3QgQ2VudGVyMSIwIAYDVQQDDBlTaWVtZW5zIFJvb3QgQ0EgVjMuMCAyMDE2\nMB4XDTE2MDcyMDEzNDYxMFoXDTIyMDcyMDEzNDYxMFowgbYxCzAJBgNVBAYTAkRF\nMQ8wDQYDVQQIDAZCYXllcm4xETAPBgNVBAcMCE11ZW5jaGVuMRAwDgYDVQQKDAdT\naWVtZW5zMREwDwYDVQQFEwhaWlpaWlpBNjEdMBsGA1UECwwUU2llbWVucyBUcnVz\ndCBDZW50ZXIxPzA9BgNVBAMMNlNpZW1lbnMgSXNzdWluZyBDQSBNZWRpdW0gU3Ry\nZW5ndGggQXV0aGVudGljYXRpb24gMjAxNjCCAiIwDQYJKoZIhvcNAQEBBQADggIP\nADCCAgoCggIBAL9UfK+JAZEqVMVvECdYF9IK4KSw34AqyNl3rYP5x03dtmKaNu+2\n0fQqNESA1NGzw3s6LmrKLh1cR991nB2cvKOXu7AvEGpSuxzIcOROd4NpvRx+Ej1p\nJIPeqf+ScmVK7lMSO8QL/QzjHOpGV3is9sG+ZIxOW9U1ESooy4Hal6ZNs4DNItsz\npiCKqm6G3et4r2WqCy2RRuSqvnmMza7Y8BZsLy0ZVo5teObQ37E/FxqSrbDI8nxn\nB7nVUve5ZjrqoIGSkEOtyo11003dVO1vmWB9A0WQGDqE/q3w178hGhKfxzRaqzyi\nSoADUYS2sD/CglGTUxVq6u0pGLLsCFjItcCWqW+T9fPYfJ2CEd5b3hvqdCn+pXjZ\n/gdX1XAcdUF5lRnGWifaYpT9n4s4adzX8q6oHSJxTppuAwLRKH6eXALbGQ1I9lGQ\nDSOipD/09xkEsPw6HOepmf2U3YxZK1VU2sHqugFJboeLcHMzp6E1n2ctlNG1GKE9\nFDHmdyFzDi0Nnxtf/GgVjnHF68hByEE1MYdJ4nJLuxoT9hyjYdRW9MpeNNxxZnmz\nW3zh7QxIqP0ZfIz6XVhzrI9uZiqwwojDiM5tEOUkQ7XyW6grNXe75yt6mTj89LlB\nH5fOW2RNmCy/jzBXDjgyskgK7kuCvUYTuRv8ITXbBY5axFA+CpxZqokpAgMBAAGj\nggKmMIICojCCAQUGCCsGAQUFBwEBBIH4MIH1MEEGCCsGAQUFBzAChjVsZGFwOi8v\nYWwuc2llbWVucy5uZXQvQ049WlpaWlpaQTEsTD1QS0k/Y0FDZXJ0aWZpY2F0ZTAy\nBggrBgEFBQcwAoYmaHR0cDovL2FoLnNpZW1lbnMuY29tL3BraT9aWlpaWlpBMS5j\ncnQwSgYIKwYBBQUHMAKGPmxkYXA6Ly9hbC5zaWVtZW5zLmNvbS91aWQ9WlpaWlpa\nQTEsbz1UcnVzdGNlbnRlcj9jQUNlcnRpZmljYXRlMDAGCCsGAQUFBzABhiRodHRw\nOi8vb2NzcC5wa2ktc2VydmljZXMuc2llbWVucy5jb20wHwYDVR0jBBgwFoAUcG2g\nUOyp0CxnnRkV/v0EczXD4tQwEgYDVR0TAQH/BAgwBgEB/wIBADBABgNVHSAEOTA3\nMDUGCCsGAQQBoWkHMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuc2llbWVucy5j\nb20vcGtpLzCBxwYDVR0fBIG/MIG8MIG5oIG2oIGzhj9sZGFwOi8vY2wuc2llbWVu\ncy5uZXQvQ049WlpaWlpaQTEsTD1QS0k/YXV0aG9yaXR5UmV2b2NhdGlvbkxpc3SG\nJmh0dHA6Ly9jaC5zaWVtZW5zLmNvbS9wa2k/WlpaWlpaQTEuY3JshkhsZGFwOi8v\nY2wuc2llbWVucy5jb20vdWlkPVpaWlpaWkExLG89VHJ1c3RjZW50ZXI/YXV0aG9y\naXR5UmV2b2NhdGlvbkxpc3QwJwYDVR0lBCAwHgYIKwYBBQUHAwIGCCsGAQUFBwME\nBggrBgEFBQcDCTAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPgVXUcMbHd7csQC\nF5Foorb3aglEMA0GCSqGSIb3DQEBCwUAA4ICAQBw+sqMp3SS7DVKcILEmXbdRAg3\nlLO1r457KY+YgCT9uX4VG5EdRKcGfWXK6VHGCi4Dos5eXFV34Mq/p8nu1sqMuoGP\nYjHn604eWDprhGy6GrTYdxzcE/GGHkpkuE3Ir/45UcmZlOU41SJ9SNjuIVrSHMOf\nccSY42BCspR/Q1Z/ykmIqQecdT3/Kkx02GzzSN2+HlW6cEO4GBW5RMqsvd2n0h2d\nfe2zcqOgkLtx7u2JCR/U77zfyxG3qXtcymoz0wgSHcsKIl+GUjITLkHfS9Op8V7C\nGr/dX437sIg5pVHmEAWadjkIzqdHux+EF94Z6kaHywohc1xG0KvPYPX7iSNjkvhz\n4NY53DHmxl4YEMLffZnaS/dqyhe1GTpcpyN8WiR4KuPfxrkVDOsuzWFtMSvNdlOV\ngdI0MXcLMP+EOeANZWX6lGgJ3vWyemo58nzgshKd24MY3w3i6masUkxJH2KvI7UH\n/1Db3SC8oOUjInvSRej6M3ZhYWgugm6gbpUgFoDw/o9Cg6Qm71hY0JtcaPC13rzm\nN8a2Br0+Fa5e2VhwLmAxyfe1JKzqPwuHT0S5u05SQghL5VdzqfA8FCL/j4XC9yI6\ncsZTAQi73xFQYVjZt3+aoSz84lOlTmVo/jgvGMY/JzH9I4mETGgAJRNj34Z/0meh\nM+pKWCojNH/dgyJSwDGCAlIwggJOAgEBMIG/MIG2MQswCQYDVQQGEwJERTEPMA0G\nA1UECAwGQmF5ZXJuMREwDwYDVQQHDAhNdWVuY2hlbjEQMA4GA1UECgwHU2llbWVu\nczERMA8GA1UEBRMIWlpaWlpaQTYxHTAbBgNVBAsMFFNpZW1lbnMgVHJ1c3QgQ2Vu\ndGVyMT8wPQYDVQQDDDZTaWVtZW5zIElzc3VpbmcgQ0EgTWVkaXVtIFN0cmVuZ3Ro\nIEF1dGhlbnRpY2F0aW9uIDIwMTYCBBXXLOIwCwYJYIZIAWUDBAIBoGkwHAYJKoZI\nhvcNAQkFMQ8XDTE5MTEyMDE0NTYyMFowLwYJKoZIhvcNAQkEMSIEIJDnZUpcVLzC\nOdtpkH8gtxwLPIDE0NmAmFC9uM8q2z+OMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0B\nBwEwCwYJKoZIhvcNAQEBBIIBAH/Pqv2xp3a0jSPkwU1K3eGA/1lfoNJMUny4d/PS\nLVWlkgrmedXdLmuBzAGEaaZOJS0lEpNd01pR/reHs7xxZ+RZ0olTs2ufM0CijQSx\nOL9HDl2O3OoD77NWx4tl3Wy1yJCeV3XH/cEI7AkKHCmKY9QMoMYWh16ORBtr+YcS\nYK+gONOjpjgcgTJgZ3HSFgQ50xiD4WT1kFBHsuYsLqaOSbTfTN6Ayyg4edjrPQqa\nVcVf1OQcIrfWA3yMQrnEZfOYfN/D4EPjTfxBV+VCi/F2bdZmMbJ7jNk1FbewSwWO\nSDH1i0K32NyFbnh0BSos7njq7ELqKlYBsoB/sZfaH2vKy5U=\n-----END SIGNED MESSAGE-----"), + MessageSize: 6494, + Tagger: &gitalypb.CommitAuthor{ + Name: []byte("Roger Meier"), + Email: []byte("r.meier@siemens.com"), + Date: ×tamppb.Timestamp{Seconds: 1574261780}, + Timezone: []byte("+0100"), + }, + SignatureType: gitalypb.SignatureType_X509, + }, + { + Name: []byte("v1.2.0"), + Id: annotatedTagID.String(), + Message: []byte("Blob tag"), + MessageSize: 8, + Tagger: &gitalypb.CommitAuthor{ + Name: []byte(gittest.DefaultCommitterName), + Email: []byte(gittest.DefaultCommitterMail), + Date: timestamppb.New(gittest.DefaultCommitTime), + Timezone: []byte("+0100"), + }, + }, + { + Name: []byte("v1.3.0"), + Id: commitID.String(), + TargetCommit: gitCommit, + }, + { + Name: []byte("v1.4.0"), + Id: blobID.String(), + }, + { + Name: []byte("v1.5.0"), + Id: commitID.String(), + TargetCommit: gitCommit, + }, + { + Name: []byte("v1.6.0"), + Id: bigCommitID.String(), + TargetCommit: bigCommit, + }, + { + Name: []byte("v1.7.0"), + Id: bigMessageTag1ID.String(), + Message: []byte(bigMessage[:helper.MaxCommitOrTagMessageSize]), + MessageSize: int64(len(bigMessage)), + TargetCommit: gitCommit, + Tagger: &gitalypb.CommitAuthor{ + Name: []byte(gittest.DefaultCommitterName), + Email: []byte(gittest.DefaultCommitterMail), + Date: timestamppb.New(gittest.DefaultCommitTime), + Timezone: []byte("+0100"), + }, + }, + } + + for _, expectedTag := range expectedTags { + rpcRequest := &gitalypb.FindTagRequest{Repository: repoProto, TagName: expectedTag.Name} + + resp, err := client.FindTag(ctx, rpcRequest) + require.NoError(t, err) + + testhelper.ProtoEqual(t, expectedTag, resp.GetTag()) + } +} + +func TestFindTagNestedTag(t *testing.T) { + ctx := testhelper.Context(t) + cfg, repoProto, repoPath, client := setupRefService(ctx, t) + + repo := localrepo.NewTestRepo(t, cfg, repoProto) + + blobID := git.ObjectID("faaf198af3a36dbf41961466703cc1d47c61d051") + commitID := git.ObjectID("6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9") + + testCases := []struct { + description string + depth int + originalOid git.ObjectID + }{ + { + description: "nested 1 deep, points to a commit", + depth: 1, + originalOid: commitID, + }, + { + description: "nested 4 deep, points to a commit", + depth: 4, + originalOid: commitID, + }, + { + description: "nested 3 deep, points to a blob", + depth: 3, + originalOid: blobID, + }, + { + description: "nested 20 deep, points to a commit", + depth: 20, + originalOid: commitID, + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + tags, err := repo.GetReferences(ctx, "refs/tags/") + require.NoError(t, err) + + updater, err := updateref.New(ctx, repo) + require.NoError(t, err) + for _, tag := range tags { + require.NoError(t, updater.Delete(tag.Name)) + } + require.NoError(t, updater.Commit()) + + catfileCache := catfile.NewCache(cfg) + defer catfileCache.Stop() + + objectReader, cancel, err := catfileCache.ObjectReader(ctx, repo) + require.NoError(t, err) + defer cancel() + + objectInfoReader, cancel, err := catfileCache.ObjectInfoReader(ctx, repo) + require.NoError(t, err) + defer cancel() + + info, err := objectInfoReader.Info(ctx, git.Revision(tc.originalOid)) + require.NoError(t, err) + + tagID := tc.originalOid + var tagName, tagMessage string + + for depth := 0; depth < tc.depth; depth++ { + tagName = fmt.Sprintf("tag-depth-%d", depth) + tagMessage = fmt.Sprintf("a commit %d deep", depth) + tagID = gittest.WriteTag(t, cfg, repoPath, tagName, tagID.Revision(), gittest.WriteTagConfig{Message: tagMessage}) + } + expectedTag := &gitalypb.Tag{ + Name: []byte(tagName), + Id: tagID.String(), + Message: []byte(tagMessage), + MessageSize: int64(len([]byte(tagMessage))), + Tagger: &gitalypb.CommitAuthor{ + Name: []byte(gittest.DefaultCommitterName), + Email: []byte(gittest.DefaultCommitterMail), + Date: timestamppb.New(gittest.DefaultCommitTime), + Timezone: []byte("+0100"), + }, + } + if info.Type == "commit" { + commit, err := catfile.GetCommit(ctx, objectReader, git.Revision(tc.originalOid)) + require.NoError(t, err) + expectedTag.TargetCommit = commit + } + rpcRequest := &gitalypb.FindTagRequest{Repository: repoProto, TagName: []byte(tagName)} + + resp, err := client.FindTag(ctx, rpcRequest) + require.NoError(t, err) + require.Equal(t, expectedTag, resp.GetTag()) + }) + } +} + +func TestInvalidFindTagRequest(t *testing.T) { + ctx := testhelper.Context(t) + _, repo, _, client := setupRefService(ctx, t) + + testCases := []struct { + desc string + request *gitalypb.FindTagRequest + }{ + { + desc: "empty request", + request: &gitalypb.FindTagRequest{}, + }, + { + desc: "invalid repo", + request: &gitalypb.FindTagRequest{ + Repository: &gitalypb.Repository{ + StorageName: "fake", + RelativePath: "repo", + }, + }, + }, + { + desc: "empty tag name", + request: &gitalypb.FindTagRequest{ + Repository: repo, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.desc, func(t *testing.T) { + _, err := client.FindTag(ctx, tc.request) + testhelper.RequireGrpcCode(t, err, codes.InvalidArgument) + }) + } +} diff --git a/internal/gitaly/service/ref/refs.go b/internal/gitaly/service/ref/refs.go index 998415e6d..0e1f13eb6 100644 --- a/internal/gitaly/service/ref/refs.go +++ b/internal/gitaly/service/ref/refs.go @@ -1,16 +1,13 @@ package ref import ( - "bufio" "bytes" "context" - "errors" "fmt" "math" "strings" "gitlab.com/gitlab-org/gitaly/v15/internal/git" - "gitlab.com/gitlab-org/gitaly/v15/internal/git/catfile" "gitlab.com/gitlab-org/gitaly/v15/internal/helper" "gitlab.com/gitlab-org/gitaly/v15/internal/helper/lines" "gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypb" @@ -175,112 +172,6 @@ func (s *server) findAllBranches(in *gitalypb.FindAllBranchesRequest, stream git return s.findRefs(ctx, writer, repo, patterns, opts) } -func (s *server) FindTag(ctx context.Context, in *gitalypb.FindTagRequest) (*gitalypb.FindTagResponse, error) { - if err := s.validateFindTagRequest(in); err != nil { - return nil, helper.ErrInvalidArgument(err) - } - - repo := s.localrepo(in.GetRepository()) - - tag, err := s.findTag(ctx, repo, in.GetTagName()) - if err != nil { - return nil, helper.ErrInternal(err) - } - - return &gitalypb.FindTagResponse{Tag: tag}, nil -} - -// parseTagLine parses a line of text with the output format %(objectname) %(objecttype) %(refname:lstrip=2) -func parseTagLine(ctx context.Context, objectReader catfile.ObjectReader, tagLine string) (*gitalypb.Tag, error) { - fields := strings.SplitN(tagLine, " ", 3) - if len(fields) != 3 { - return nil, fmt.Errorf("invalid output from for-each-ref command: %v", tagLine) - } - - tagID, refType, refName := fields[0], fields[1], fields[2] - - tag := &gitalypb.Tag{ - Id: tagID, - Name: []byte(refName), - } - - switch refType { - // annotated tag - case "tag": - tag, err := catfile.GetTag(ctx, objectReader, git.Revision(tagID), refName) - if err != nil { - return nil, fmt.Errorf("getting annotated tag: %v", err) - } - catfile.TrimTagMessage(tag) - - return tag, nil - case "commit": - commit, err := catfile.GetCommit(ctx, objectReader, git.Revision(tagID)) - if err != nil { - return nil, fmt.Errorf("getting commit catfile: %v", err) - } - tag.TargetCommit = commit - return tag, nil - default: - return tag, nil - } -} - -func (s *server) findTag(ctx context.Context, repo git.RepositoryExecutor, tagName []byte) (*gitalypb.Tag, error) { - tagCmd, err := repo.Exec(ctx, - git.SubCmd{ - Name: "tag", - Flags: []git.Option{ - git.Flag{Name: "-l"}, git.ValueFlag{Name: "--format", Value: tagFormat}, - }, - Args: []string{string(tagName)}, - }, - git.WithRefTxHook(repo), - ) - if err != nil { - return nil, fmt.Errorf("for-each-ref error: %v", err) - } - - objectReader, cancel, err := s.catfileCache.ObjectReader(ctx, repo) - if err != nil { - return nil, err - } - defer cancel() - - var tag *gitalypb.Tag - - scanner := bufio.NewScanner(tagCmd) - if scanner.Scan() { - tag, err = parseTagLine(ctx, objectReader, scanner.Text()) - if err != nil { - return nil, err - } - } else { - return nil, errors.New("no tag found") - } - - if err = tagCmd.Wait(); err != nil { - return nil, err - } - - return tag, nil -} - -func (s *server) validateFindTagRequest(in *gitalypb.FindTagRequest) error { - if in.GetRepository() == nil { - return errors.New("repository is empty") - } - - if _, err := s.locator.GetRepoPath(in.GetRepository()); err != nil { - return fmt.Errorf("invalid git directory: %v", err) - } - - if in.GetTagName() == nil { - return errors.New("tag name is empty") - } - return nil -} - func buildPaginationOpts(ctx context.Context, p *gitalypb.PaginationParameter) *paginationOpts { opts := &paginationOpts{} opts.IsPageToken = func(_ []byte) bool { return true } diff --git a/internal/gitaly/service/ref/refs_test.go b/internal/gitaly/service/ref/refs_test.go index 99e4a3d6f..404ea6af8 100644 --- a/internal/gitaly/service/ref/refs_test.go +++ b/internal/gitaly/service/ref/refs_test.go @@ -12,7 +12,6 @@ import ( "github.com/stretchr/testify/require" "gitlab.com/gitlab-org/gitaly/v15/internal/git" - "gitlab.com/gitlab-org/gitaly/v15/internal/git/catfile" "gitlab.com/gitlab-org/gitaly/v15/internal/git/gittest" "gitlab.com/gitlab-org/gitaly/v15/internal/git/localrepo" "gitlab.com/gitlab-org/gitaly/v15/internal/git/updateref" @@ -863,300 +862,3 @@ func TestListBranchNamesContainingCommit(t *testing.T) { }) } } - -func TestSuccessfulFindTagRequest(t *testing.T) { - ctx := testhelper.Context(t) - cfg, repoProto, repoPath, client := setupRefService(ctx, t) - - repo := localrepo.NewTestRepo(t, cfg, repoProto) - - blobID := git.ObjectID("faaf198af3a36dbf41961466703cc1d47c61d051") - commitID := git.ObjectID("6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9") - - gitCommit := testhelper.GitLabTestCommit(commitID.String()) - - bigCommitID := gittest.WriteCommit(t, cfg, repoPath, - gittest.WithBranch("local-big-commits"), - gittest.WithMessage("An empty commit with REALLY BIG message\n\n"+strings.Repeat("a", helper.MaxCommitOrTagMessageSize+1)), - gittest.WithParents("60ecb67744cb56576c30214ff52294f8ce2def98"), - ) - bigCommit, err := repo.ReadCommit(ctx, git.Revision(bigCommitID)) - require.NoError(t, err) - - annotatedTagID := gittest.WriteTag(t, cfg, repoPath, "v1.2.0", blobID.Revision(), gittest.WriteTagConfig{Message: "Blob tag"}) - - gittest.WriteTag(t, cfg, repoPath, "v1.3.0", commitID.Revision()) - gittest.WriteTag(t, cfg, repoPath, "v1.4.0", blobID.Revision()) - - // To test recursive resolving to a commit - gittest.WriteTag(t, cfg, repoPath, "v1.5.0", "v1.3.0") - - // A tag to commit with a big message - gittest.WriteTag(t, cfg, repoPath, "v1.6.0", bigCommitID.Revision()) - - // A tag with a big message - bigMessage := strings.Repeat("a", 11*1024) - bigMessageTag1ID := gittest.WriteTag(t, cfg, repoPath, "v1.7.0", commitID.Revision(), gittest.WriteTagConfig{Message: bigMessage}) - - // A tag with a commit id as its name - commitTagID := gittest.WriteTag(t, cfg, repoPath, commitID.String(), commitID.Revision(), gittest.WriteTagConfig{Message: "commit tag with a commit sha as the name"}) - - // a tag of a tag - tagOfTagID := gittest.WriteTag(t, cfg, repoPath, "tag-of-tag", commitTagID.Revision(), gittest.WriteTagConfig{Message: "tag of a tag"}) - - expectedTags := []*gitalypb.Tag{ - { - Name: []byte(commitID), - Id: commitTagID.String(), - TargetCommit: gitCommit, - Message: []byte("commit tag with a commit sha as the name"), - MessageSize: 40, - Tagger: &gitalypb.CommitAuthor{ - Name: []byte(gittest.DefaultCommitterName), - Email: []byte(gittest.DefaultCommitterMail), - Date: timestamppb.New(gittest.DefaultCommitTime), - Timezone: []byte("+0100"), - }, - }, - { - Name: []byte("tag-of-tag"), - Id: tagOfTagID.String(), - TargetCommit: gitCommit, - Message: []byte("tag of a tag"), - MessageSize: 12, - Tagger: &gitalypb.CommitAuthor{ - Name: []byte(gittest.DefaultCommitterName), - Email: []byte(gittest.DefaultCommitterMail), - Date: timestamppb.New(gittest.DefaultCommitTime), - Timezone: []byte("+0100"), - }, - }, - { - Name: []byte("v1.0.0"), - Id: "f4e6814c3e4e7a0de82a9e7cd20c626cc963a2f8", - TargetCommit: gitCommit, - Message: []byte("Release"), - MessageSize: 7, - Tagger: &gitalypb.CommitAuthor{ - Name: []byte("Dmitriy Zaporozhets"), - Email: []byte("dmitriy.zaporozhets@gmail.com"), - Date: ×tamppb.Timestamp{Seconds: 1393491299}, - Timezone: []byte("+0200"), - }, - SignatureType: gitalypb.SignatureType_NONE, - }, - { - Name: []byte("v1.1.0"), - Id: "8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b", - TargetCommit: testhelper.GitLabTestCommit("5937ac0a7beb003549fc5fd26fc247adbce4a52e"), - Message: []byte("Version 1.1.0"), - MessageSize: 13, - Tagger: &gitalypb.CommitAuthor{ - Name: []byte("Dmitriy Zaporozhets"), - Email: []byte("dmitriy.zaporozhets@gmail.com"), - Date: ×tamppb.Timestamp{Seconds: 1393505709}, - Timezone: []byte("+0200"), - }, - }, - { - Name: []byte("v1.1.1"), - Id: "8f03acbcd11c53d9c9468078f32a2622005a4841", - TargetCommit: testhelper.GitLabTestCommit("189a6c924013fc3fe40d6f1ec1dc20214183bc97"), - Message: []byte("x509 signed tag\n-----BEGIN SIGNED MESSAGE-----\nMIISfwYJKoZIhvcNAQcCoIIScDCCEmwCAQExDTALBglghkgBZQMEAgEwCwYJKoZI\nhvcNAQcBoIIP8zCCB3QwggVcoAMCAQICBBXXLOIwDQYJKoZIhvcNAQELBQAwgbYx\nCzAJBgNVBAYTAkRFMQ8wDQYDVQQIDAZCYXllcm4xETAPBgNVBAcMCE11ZW5jaGVu\nMRAwDgYDVQQKDAdTaWVtZW5zMREwDwYDVQQFEwhaWlpaWlpBNjEdMBsGA1UECwwU\nU2llbWVucyBUcnVzdCBDZW50ZXIxPzA9BgNVBAMMNlNpZW1lbnMgSXNzdWluZyBD\nQSBNZWRpdW0gU3RyZW5ndGggQXV0aGVudGljYXRpb24gMjAxNjAeFw0xNzAyMDMw\nNjU4MzNaFw0yMDAyMDMwNjU4MzNaMFsxETAPBgNVBAUTCFowMDBOV0RIMQ4wDAYD\nVQQqDAVSb2dlcjEOMAwGA1UEBAwFTWVpZXIxEDAOBgNVBAoMB1NpZW1lbnMxFDAS\nBgNVBAMMC01laWVyIFJvZ2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\nAQEAuBNea/68ZCnHYQjpm/k3ZBG0wBpEKSwG6lk9CEQlSxsqVLQHAoAKBIlJm1in\nYVLcK/Sq1yhYJ/qWcY/M53DhK2rpPuhtrWJUdOUy8EBWO20F4bd4Fw9pO7jt8bme\nu33TSrK772vKjuppzB6SeG13Cs08H+BIeD106G27h7ufsO00pvsxoSDL+uc4slnr\npBL+2TAL7nSFnB9QHWmRIK27SPqJE+lESdb0pse11x1wjvqKy2Q7EjL9fpqJdHzX\nNLKHXd2r024TOORTa05DFTNR+kQEKKV96XfpYdtSBomXNQ44cisiPBJjFtYvfnFE\nwgrHa8fogn/b0C+A+HAoICN12wIDAQABo4IC4jCCAt4wHQYDVR0OBBYEFCF+gkUp\nXQ6xGc0kRWXuDFxzA14zMEMGA1UdEQQ8MDqgIwYKKwYBBAGCNxQCA6AVDBNyLm1l\naWVyQHNpZW1lbnMuY29tgRNyLm1laWVyQHNpZW1lbnMuY29tMA4GA1UdDwEB/wQE\nAwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwgcoGA1UdHwSBwjCB\nvzCBvKCBuaCBtoYmaHR0cDovL2NoLnNpZW1lbnMuY29tL3BraT9aWlpaWlpBNi5j\ncmyGQWxkYXA6Ly9jbC5zaWVtZW5zLm5ldC9DTj1aWlpaWlpBNixMPVBLST9jZXJ0\naWZpY2F0ZVJldm9jYXRpb25MaXN0hklsZGFwOi8vY2wuc2llbWVucy5jb20vQ049\nWlpaWlpaQTYsbz1UcnVzdGNlbnRlcj9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0\nMEUGA1UdIAQ+MDwwOgYNKwYBBAGhaQcCAgMBAzApMCcGCCsGAQUFBwIBFhtodHRw\nOi8vd3d3LnNpZW1lbnMuY29tL3BraS8wDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAW\ngBT4FV1HDGx3e3LEAheRaKK292oJRDCCAQQGCCsGAQUFBwEBBIH3MIH0MDIGCCsG\nAQUFBzAChiZodHRwOi8vYWguc2llbWVucy5jb20vcGtpP1paWlpaWkE2LmNydDBB\nBggrBgEFBQcwAoY1bGRhcDovL2FsLnNpZW1lbnMubmV0L0NOPVpaWlpaWkE2LEw9\nUEtJP2NBQ2VydGlmaWNhdGUwSQYIKwYBBQUHMAKGPWxkYXA6Ly9hbC5zaWVtZW5z\nLmNvbS9DTj1aWlpaWlpBNixvPVRydXN0Y2VudGVyP2NBQ2VydGlmaWNhdGUwMAYI\nKwYBBQUHMAGGJGh0dHA6Ly9vY3NwLnBraS1zZXJ2aWNlcy5zaWVtZW5zLmNvbTAN\nBgkqhkiG9w0BAQsFAAOCAgEAXPVcX6vaEcszJqg5IemF9aFTlwTrX5ITNIpzcqG+\nkD5haOf2mZYLjl+MKtLC1XfmIsGCUZNb8bjP6QHQEI+2d6x/ZOqPq7Kd7PwVu6x6\nxZrkDjUyhUbUntT5+RBy++l3Wf6Cq6Kx+K8ambHBP/bu90/p2U8KfFAG3Kr2gI2q\nfZrnNMOxmJfZ3/sXxssgLkhbZ7hRa+MpLfQ6uFsSiat3vlawBBvTyHnoZ/7oRc8y\nqi6QzWcd76CPpMElYWibl+hJzKbBZUWvc71AzHR6i1QeZ6wubYz7vr+FF5Y7tnxB\nVz6omPC9XAg0F+Dla6Zlz3Awj5imCzVXa+9SjtnsidmJdLcKzTAKyDewewoxYOOJ\nj3cJU7VSjJPl+2fVmDBaQwcNcUcu/TPAKApkegqO7tRF9IPhjhW8QkRnkqMetO3D\nOXmAFVIsEI0Hvb2cdb7B6jSpjGUuhaFm9TCKhQtCk2p8JCDTuaENLm1x34rrJKbT\n2vzyYN0CZtSkUdgD4yQxK9VWXGEzexRisWb4AnZjD2NAquLPpXmw8N0UwFD7MSpC\ndpaX7FktdvZmMXsnGiAdtLSbBgLVWOD1gmJFDjrhNbI8NOaOaNk4jrfGqNh5lhGU\n4DnBT2U6Cie1anLmFH/oZooAEXR2o3Nu+1mNDJChnJp0ovs08aa3zZvBdcloOvfU\nqdowggh3MIIGX6ADAgECAgQtyi/nMA0GCSqGSIb3DQEBCwUAMIGZMQswCQYDVQQG\nEwJERTEPMA0GA1UECAwGQmF5ZXJuMREwDwYDVQQHDAhNdWVuY2hlbjEQMA4GA1UE\nCgwHU2llbWVuczERMA8GA1UEBRMIWlpaWlpaQTExHTAbBgNVBAsMFFNpZW1lbnMg\nVHJ1c3QgQ2VudGVyMSIwIAYDVQQDDBlTaWVtZW5zIFJvb3QgQ0EgVjMuMCAyMDE2\nMB4XDTE2MDcyMDEzNDYxMFoXDTIyMDcyMDEzNDYxMFowgbYxCzAJBgNVBAYTAkRF\nMQ8wDQYDVQQIDAZCYXllcm4xETAPBgNVBAcMCE11ZW5jaGVuMRAwDgYDVQQKDAdT\naWVtZW5zMREwDwYDVQQFEwhaWlpaWlpBNjEdMBsGA1UECwwUU2llbWVucyBUcnVz\ndCBDZW50ZXIxPzA9BgNVBAMMNlNpZW1lbnMgSXNzdWluZyBDQSBNZWRpdW0gU3Ry\nZW5ndGggQXV0aGVudGljYXRpb24gMjAxNjCCAiIwDQYJKoZIhvcNAQEBBQADggIP\nADCCAgoCggIBAL9UfK+JAZEqVMVvECdYF9IK4KSw34AqyNl3rYP5x03dtmKaNu+2\n0fQqNESA1NGzw3s6LmrKLh1cR991nB2cvKOXu7AvEGpSuxzIcOROd4NpvRx+Ej1p\nJIPeqf+ScmVK7lMSO8QL/QzjHOpGV3is9sG+ZIxOW9U1ESooy4Hal6ZNs4DNItsz\npiCKqm6G3et4r2WqCy2RRuSqvnmMza7Y8BZsLy0ZVo5teObQ37E/FxqSrbDI8nxn\nB7nVUve5ZjrqoIGSkEOtyo11003dVO1vmWB9A0WQGDqE/q3w178hGhKfxzRaqzyi\nSoADUYS2sD/CglGTUxVq6u0pGLLsCFjItcCWqW+T9fPYfJ2CEd5b3hvqdCn+pXjZ\n/gdX1XAcdUF5lRnGWifaYpT9n4s4adzX8q6oHSJxTppuAwLRKH6eXALbGQ1I9lGQ\nDSOipD/09xkEsPw6HOepmf2U3YxZK1VU2sHqugFJboeLcHMzp6E1n2ctlNG1GKE9\nFDHmdyFzDi0Nnxtf/GgVjnHF68hByEE1MYdJ4nJLuxoT9hyjYdRW9MpeNNxxZnmz\nW3zh7QxIqP0ZfIz6XVhzrI9uZiqwwojDiM5tEOUkQ7XyW6grNXe75yt6mTj89LlB\nH5fOW2RNmCy/jzBXDjgyskgK7kuCvUYTuRv8ITXbBY5axFA+CpxZqokpAgMBAAGj\nggKmMIICojCCAQUGCCsGAQUFBwEBBIH4MIH1MEEGCCsGAQUFBzAChjVsZGFwOi8v\nYWwuc2llbWVucy5uZXQvQ049WlpaWlpaQTEsTD1QS0k/Y0FDZXJ0aWZpY2F0ZTAy\nBggrBgEFBQcwAoYmaHR0cDovL2FoLnNpZW1lbnMuY29tL3BraT9aWlpaWlpBMS5j\ncnQwSgYIKwYBBQUHMAKGPmxkYXA6Ly9hbC5zaWVtZW5zLmNvbS91aWQ9WlpaWlpa\nQTEsbz1UcnVzdGNlbnRlcj9jQUNlcnRpZmljYXRlMDAGCCsGAQUFBzABhiRodHRw\nOi8vb2NzcC5wa2ktc2VydmljZXMuc2llbWVucy5jb20wHwYDVR0jBBgwFoAUcG2g\nUOyp0CxnnRkV/v0EczXD4tQwEgYDVR0TAQH/BAgwBgEB/wIBADBABgNVHSAEOTA3\nMDUGCCsGAQQBoWkHMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuc2llbWVucy5j\nb20vcGtpLzCBxwYDVR0fBIG/MIG8MIG5oIG2oIGzhj9sZGFwOi8vY2wuc2llbWVu\ncy5uZXQvQ049WlpaWlpaQTEsTD1QS0k/YXV0aG9yaXR5UmV2b2NhdGlvbkxpc3SG\nJmh0dHA6Ly9jaC5zaWVtZW5zLmNvbS9wa2k/WlpaWlpaQTEuY3JshkhsZGFwOi8v\nY2wuc2llbWVucy5jb20vdWlkPVpaWlpaWkExLG89VHJ1c3RjZW50ZXI/YXV0aG9y\naXR5UmV2b2NhdGlvbkxpc3QwJwYDVR0lBCAwHgYIKwYBBQUHAwIGCCsGAQUFBwME\nBggrBgEFBQcDCTAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPgVXUcMbHd7csQC\nF5Foorb3aglEMA0GCSqGSIb3DQEBCwUAA4ICAQBw+sqMp3SS7DVKcILEmXbdRAg3\nlLO1r457KY+YgCT9uX4VG5EdRKcGfWXK6VHGCi4Dos5eXFV34Mq/p8nu1sqMuoGP\nYjHn604eWDprhGy6GrTYdxzcE/GGHkpkuE3Ir/45UcmZlOU41SJ9SNjuIVrSHMOf\nccSY42BCspR/Q1Z/ykmIqQecdT3/Kkx02GzzSN2+HlW6cEO4GBW5RMqsvd2n0h2d\nfe2zcqOgkLtx7u2JCR/U77zfyxG3qXtcymoz0wgSHcsKIl+GUjITLkHfS9Op8V7C\nGr/dX437sIg5pVHmEAWadjkIzqdHux+EF94Z6kaHywohc1xG0KvPYPX7iSNjkvhz\n4NY53DHmxl4YEMLffZnaS/dqyhe1GTpcpyN8WiR4KuPfxrkVDOsuzWFtMSvNdlOV\ngdI0MXcLMP+EOeANZWX6lGgJ3vWyemo58nzgshKd24MY3w3i6masUkxJH2KvI7UH\n/1Db3SC8oOUjInvSRej6M3ZhYWgugm6gbpUgFoDw/o9Cg6Qm71hY0JtcaPC13rzm\nN8a2Br0+Fa5e2VhwLmAxyfe1JKzqPwuHT0S5u05SQghL5VdzqfA8FCL/j4XC9yI6\ncsZTAQi73xFQYVjZt3+aoSz84lOlTmVo/jgvGMY/JzH9I4mETGgAJRNj34Z/0meh\nM+pKWCojNH/dgyJSwDGCAlIwggJOAgEBMIG/MIG2MQswCQYDVQQGEwJERTEPMA0G\nA1UECAwGQmF5ZXJuMREwDwYDVQQHDAhNdWVuY2hlbjEQMA4GA1UECgwHU2llbWVu\nczERMA8GA1UEBRMIWlpaWlpaQTYxHTAbBgNVBAsMFFNpZW1lbnMgVHJ1c3QgQ2Vu\ndGVyMT8wPQYDVQQDDDZTaWVtZW5zIElzc3VpbmcgQ0EgTWVkaXVtIFN0cmVuZ3Ro\nIEF1dGhlbnRpY2F0aW9uIDIwMTYCBBXXLOIwCwYJYIZIAWUDBAIBoGkwHAYJKoZI\nhvcNAQkFMQ8XDTE5MTEyMDE0NTYyMFowLwYJKoZIhvcNAQkEMSIEIJDnZUpcVLzC\nOdtpkH8gtxwLPIDE0NmAmFC9uM8q2z+OMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0B\nBwEwCwYJKoZIhvcNAQEBBIIBAH/Pqv2xp3a0jSPkwU1K3eGA/1lfoNJMUny4d/PS\nLVWlkgrmedXdLmuBzAGEaaZOJS0lEpNd01pR/reHs7xxZ+RZ0olTs2ufM0CijQSx\nOL9HDl2O3OoD77NWx4tl3Wy1yJCeV3XH/cEI7AkKHCmKY9QMoMYWh16ORBtr+YcS\nYK+gONOjpjgcgTJgZ3HSFgQ50xiD4WT1kFBHsuYsLqaOSbTfTN6Ayyg4edjrPQqa\nVcVf1OQcIrfWA3yMQrnEZfOYfN/D4EPjTfxBV+VCi/F2bdZmMbJ7jNk1FbewSwWO\nSDH1i0K32NyFbnh0BSos7njq7ELqKlYBsoB/sZfaH2vKy5U=\n-----END SIGNED MESSAGE-----"), - MessageSize: 6494, - Tagger: &gitalypb.CommitAuthor{ - Name: []byte("Roger Meier"), - Email: []byte("r.meier@siemens.com"), - Date: ×tamppb.Timestamp{Seconds: 1574261780}, - Timezone: []byte("+0100"), - }, - SignatureType: gitalypb.SignatureType_X509, - }, - { - Name: []byte("v1.2.0"), - Id: annotatedTagID.String(), - Message: []byte("Blob tag"), - MessageSize: 8, - Tagger: &gitalypb.CommitAuthor{ - Name: []byte(gittest.DefaultCommitterName), - Email: []byte(gittest.DefaultCommitterMail), - Date: timestamppb.New(gittest.DefaultCommitTime), - Timezone: []byte("+0100"), - }, - }, - { - Name: []byte("v1.3.0"), - Id: commitID.String(), - TargetCommit: gitCommit, - }, - { - Name: []byte("v1.4.0"), - Id: blobID.String(), - }, - { - Name: []byte("v1.5.0"), - Id: commitID.String(), - TargetCommit: gitCommit, - }, - { - Name: []byte("v1.6.0"), - Id: bigCommitID.String(), - TargetCommit: bigCommit, - }, - { - Name: []byte("v1.7.0"), - Id: bigMessageTag1ID.String(), - Message: []byte(bigMessage[:helper.MaxCommitOrTagMessageSize]), - MessageSize: int64(len(bigMessage)), - TargetCommit: gitCommit, - Tagger: &gitalypb.CommitAuthor{ - Name: []byte(gittest.DefaultCommitterName), - Email: []byte(gittest.DefaultCommitterMail), - Date: timestamppb.New(gittest.DefaultCommitTime), - Timezone: []byte("+0100"), - }, - }, - } - - for _, expectedTag := range expectedTags { - rpcRequest := &gitalypb.FindTagRequest{Repository: repoProto, TagName: expectedTag.Name} - - resp, err := client.FindTag(ctx, rpcRequest) - require.NoError(t, err) - - testhelper.ProtoEqual(t, expectedTag, resp.GetTag()) - } -} - -func TestFindTagNestedTag(t *testing.T) { - ctx := testhelper.Context(t) - cfg, repoProto, repoPath, client := setupRefService(ctx, t) - - repo := localrepo.NewTestRepo(t, cfg, repoProto) - - blobID := git.ObjectID("faaf198af3a36dbf41961466703cc1d47c61d051") - commitID := git.ObjectID("6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9") - - testCases := []struct { - description string - depth int - originalOid git.ObjectID - }{ - { - description: "nested 1 deep, points to a commit", - depth: 1, - originalOid: commitID, - }, - { - description: "nested 4 deep, points to a commit", - depth: 4, - originalOid: commitID, - }, - { - description: "nested 3 deep, points to a blob", - depth: 3, - originalOid: blobID, - }, - { - description: "nested 20 deep, points to a commit", - depth: 20, - originalOid: commitID, - }, - } - - for _, tc := range testCases { - t.Run(tc.description, func(t *testing.T) { - tags, err := repo.GetReferences(ctx, "refs/tags/") - require.NoError(t, err) - - updater, err := updateref.New(ctx, repo) - require.NoError(t, err) - for _, tag := range tags { - require.NoError(t, updater.Delete(tag.Name)) - } - require.NoError(t, updater.Commit()) - - catfileCache := catfile.NewCache(cfg) - defer catfileCache.Stop() - - objectReader, cancel, err := catfileCache.ObjectReader(ctx, repo) - require.NoError(t, err) - defer cancel() - - objectInfoReader, cancel, err := catfileCache.ObjectInfoReader(ctx, repo) - require.NoError(t, err) - defer cancel() - - info, err := objectInfoReader.Info(ctx, git.Revision(tc.originalOid)) - require.NoError(t, err) - - tagID := tc.originalOid - var tagName, tagMessage string - - for depth := 0; depth < tc.depth; depth++ { - tagName = fmt.Sprintf("tag-depth-%d", depth) - tagMessage = fmt.Sprintf("a commit %d deep", depth) - tagID = gittest.WriteTag(t, cfg, repoPath, tagName, tagID.Revision(), gittest.WriteTagConfig{Message: tagMessage}) - } - expectedTag := &gitalypb.Tag{ - Name: []byte(tagName), - Id: tagID.String(), - Message: []byte(tagMessage), - MessageSize: int64(len([]byte(tagMessage))), - Tagger: &gitalypb.CommitAuthor{ - Name: []byte(gittest.DefaultCommitterName), - Email: []byte(gittest.DefaultCommitterMail), - Date: timestamppb.New(gittest.DefaultCommitTime), - Timezone: []byte("+0100"), - }, - } - if info.Type == "commit" { - commit, err := catfile.GetCommit(ctx, objectReader, git.Revision(tc.originalOid)) - require.NoError(t, err) - expectedTag.TargetCommit = commit - } - rpcRequest := &gitalypb.FindTagRequest{Repository: repoProto, TagName: []byte(tagName)} - - resp, err := client.FindTag(ctx, rpcRequest) - require.NoError(t, err) - require.Equal(t, expectedTag, resp.GetTag()) - }) - } -} - -func TestInvalidFindTagRequest(t *testing.T) { - ctx := testhelper.Context(t) - _, repo, _, client := setupRefService(ctx, t) - - testCases := []struct { - desc string - request *gitalypb.FindTagRequest - }{ - { - desc: "empty request", - request: &gitalypb.FindTagRequest{}, - }, - { - desc: "invalid repo", - request: &gitalypb.FindTagRequest{ - Repository: &gitalypb.Repository{ - StorageName: "fake", - RelativePath: "repo", - }, - }, - }, - { - desc: "empty tag name", - request: &gitalypb.FindTagRequest{ - Repository: repo, - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.desc, func(t *testing.T) { - _, err := client.FindTag(ctx, tc.request) - testhelper.RequireGrpcCode(t, err, codes.InvalidArgument) - }) - } -} |