diff options
author | Patrick Steinhardt <psteinhardt@gitlab.com> | 2021-07-01 09:24:18 +0300 |
---|---|---|
committer | Patrick Steinhardt <psteinhardt@gitlab.com> | 2021-07-01 09:24:18 +0300 |
commit | 9924b3263079fb507525d5c164741bb733ebfcde (patch) | |
tree | 708773345790f5a399d9dd640275f2a661b08306 | |
parent | 152db141420ac08ff6dd322c3fe9b8ccb83c48ab (diff) | |
parent | 78c38deaa1c6d43c02c3d5ada735fcfd1296f8db (diff) |
Merge branch 'fix/operations_lose_timezone' into 'master'
Fix Web GUI operations timezone
See merge request gitlab-org/gitaly!3586
-rw-r--r-- | internal/git/gittest/user.go | 6 | ||||
-rw-r--r-- | internal/gitaly/service/operations/commit_files.go | 11 | ||||
-rw-r--r-- | internal/gitaly/service/operations/commit_files_test.go | 11 | ||||
-rw-r--r-- | internal/gitaly/service/operations/merge.go | 20 | ||||
-rw-r--r-- | internal/gitaly/service/operations/merge_test.go | 18 | ||||
-rw-r--r-- | internal/gitaly/service/operations/revert.go | 11 | ||||
-rw-r--r-- | internal/gitaly/service/operations/revert_test.go | 10 | ||||
-rw-r--r-- | internal/gitaly/service/operations/squash.go | 15 | ||||
-rw-r--r-- | internal/gitaly/service/operations/squash_test.go | 17 | ||||
-rw-r--r-- | internal/gitaly/service/operations/submodules.go | 11 | ||||
-rw-r--r-- | internal/gitaly/service/operations/submodules_test.go | 13 | ||||
-rw-r--r-- | internal/gitaly/service/operations/utils.go | 30 | ||||
-rw-r--r-- | internal/gitaly/service/operations/utils_test.go | 44 | ||||
-rw-r--r-- | proto/go/gitalypb/shared.pb.go | 74 | ||||
-rw-r--r-- | proto/shared.proto | 3 | ||||
-rw-r--r-- | ruby/proto/gitaly/shared_pb.rb | 1 |
16 files changed, 189 insertions, 106 deletions
diff --git a/internal/git/gittest/user.go b/internal/git/gittest/user.go index 94cfc522d..5d3b54094 100644 --- a/internal/git/gittest/user.go +++ b/internal/git/gittest/user.go @@ -7,6 +7,11 @@ import ( const ( // GlID is the ID of the default user. GlID = "user-123" + + // Timezone is the Timezone of the default user. + Timezone = "Asia/Shanghai" + // TimezoneOffset is ISO 8601-like format of the default user Timezone. + TimezoneOffset = "+0800" ) var ( @@ -16,5 +21,6 @@ var ( Email: []byte("janedoe@gitlab.com"), GlId: GlID, GlUsername: "janedoe", + Timezone: Timezone, } ) diff --git a/internal/gitaly/service/operations/commit_files.go b/internal/gitaly/service/operations/commit_files.go index 33011e2f3..9b819c861 100644 --- a/internal/gitaly/service/operations/commit_files.go +++ b/internal/gitaly/service/operations/commit_files.go @@ -8,9 +8,7 @@ import ( "fmt" "io" "strings" - "time" - "github.com/golang/protobuf/ptypes" "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus" "github.com/sirupsen/logrus" "gitlab.com/gitlab-org/gitaly/v14/internal/git" @@ -284,12 +282,9 @@ func (s *Server) userCommitFiles(ctx context.Context, header *gitalypb.UserCommi } } - now := time.Now() - if header.Timestamp != nil { - now, err = ptypes.Timestamp(header.Timestamp) - if err != nil { - return helper.ErrInvalidArgument(err) - } + now, err := dateFromProto(header) + if err != nil { + return helper.ErrInvalidArgument(err) } committer := git2go.NewSignature(string(header.User.Name), string(header.User.Email), now) diff --git a/internal/gitaly/service/operations/commit_files_test.go b/internal/gitaly/service/operations/commit_files_test.go index d4838a4d3..93b2a0d49 100644 --- a/internal/gitaly/service/operations/commit_files_test.go +++ b/internal/gitaly/service/operations/commit_files_test.go @@ -932,6 +932,9 @@ func TestUserCommitFiles(t *testing.T) { require.Equal(t, step.branchCreated, resp.BranchUpdate.BranchCreated, "step %d", i+1) require.Equal(t, step.repoCreated, resp.BranchUpdate.RepoCreated, "step %d", i+1) gittest.RequireTree(t, cfg, repoPath, branch, step.treeEntries) + + authorDate := gittest.Exec(t, cfg, "-C", repoPath, "log", "--pretty='format:%ai'", "-1") + require.Contains(t, string(authorDate), gittest.TimezoneOffset) } }) } @@ -966,7 +969,7 @@ func TestUserCommitFilesStableCommitID(t *testing.T) { resp, err := stream.CloseAndRecv() require.NoError(t, err) - require.Equal(t, resp.BranchUpdate.CommitId, "4f0ca1fbf05e04dbd5f68d14677034e0afee58ff") + require.Equal(t, resp.BranchUpdate.CommitId, "23ec4ccd7fcc6ecf39431805bbff1cbcb6c23b9d") require.True(t, resp.BranchUpdate.BranchCreated) require.True(t, resp.BranchUpdate.RepoCreated) gittest.RequireTree(t, cfg, repoPath, "refs/heads/master", []gittest.TreeEntry{ @@ -976,7 +979,7 @@ func TestUserCommitFilesStableCommitID(t *testing.T) { commit, err := repo.ReadCommit(ctx, "refs/heads/master") require.NoError(t, err) require.Equal(t, &gitalypb.GitCommit{ - Id: "4f0ca1fbf05e04dbd5f68d14677034e0afee58ff", + Id: "23ec4ccd7fcc6ecf39431805bbff1cbcb6c23b9d", TreeId: "541550ddcf8a29bcd80b0800a142a7d47890cfd6", Subject: []byte("commit message"), Body: []byte("commit message"), @@ -985,13 +988,13 @@ func TestUserCommitFilesStableCommitID(t *testing.T) { Name: []byte("Author Name"), Email: []byte("author.email@example.com"), Date: ×tamp.Timestamp{Seconds: 12345}, - Timezone: []byte("+0000"), + Timezone: []byte(gittest.TimezoneOffset), }, Committer: &gitalypb.CommitAuthor{ Name: gittest.TestUser.Name, Email: gittest.TestUser.Email, Date: ×tamp.Timestamp{Seconds: 12345}, - Timezone: []byte("+0000"), + Timezone: []byte(gittest.TimezoneOffset), }, }, commit) } diff --git a/internal/gitaly/service/operations/merge.go b/internal/gitaly/service/operations/merge.go index ff9c3f42a..7c70360c4 100644 --- a/internal/gitaly/service/operations/merge.go +++ b/internal/gitaly/service/operations/merge.go @@ -5,9 +5,7 @@ import ( "errors" "fmt" "strings" - "time" - "github.com/golang/protobuf/ptypes" "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus" "github.com/sirupsen/logrus" "gitlab.com/gitlab-org/gitaly/v14/internal/git" @@ -62,12 +60,9 @@ func (s *Server) UserMergeBranch(stream gitalypb.OperationService_UserMergeBranc return err } - authorDate := time.Now() - if firstRequest.Timestamp != nil { - authorDate, err = ptypes.Timestamp(firstRequest.Timestamp) - if err != nil { - return helper.ErrInvalidArgument(err) - } + authorDate, err := dateFromProto(firstRequest) + if err != nil { + return helper.ErrInvalidArgument(err) } merge, err := git2go.MergeCommand{ @@ -260,12 +255,9 @@ func (s *Server) UserMergeToRef(ctx context.Context, request *gitalypb.UserMerge return nil, helper.ErrInvalidArgument(errors.New("Invalid merge source")) } - authorDate := time.Now() - if request.Timestamp != nil { - authorDate, err = ptypes.Timestamp(request.Timestamp) - if err != nil { - return nil, helper.ErrInvalidArgument(err) - } + authorDate, err := dateFromProto(request) + if err != nil { + return nil, helper.ErrInvalidArgument(err) } // Resolve the current state of the target reference. We do not care whether it diff --git a/internal/gitaly/service/operations/merge_test.go b/internal/gitaly/service/operations/merge_test.go index d3abca08a..65253b68c 100644 --- a/internal/gitaly/service/operations/merge_test.go +++ b/internal/gitaly/service/operations/merge_test.go @@ -96,6 +96,7 @@ func TestSuccessfulMerge(t *testing.T) { author := commit.Author require.Equal(t, gittest.TestUser.Name, author.Name) require.Equal(t, gittest.TestUser.Email, author.Email) + require.Equal(t, gittest.TimezoneOffset, string(author.Timezone)) expectedGlID := "GL_ID=" + gittest.TestUser.GlId for i, h := range hooks { @@ -134,7 +135,7 @@ func TestSuccessfulMerge_stableMergeIDs(t *testing.T) { } // Because the timestamp is - expectedMergeID := "cd66941816adc76cc31fc6620d7b36a3dcb045e5" + expectedMergeID := "f0165798887392f9148b55d54a832b005f93a38c" require.NoError(t, mergeBidi.Send(firstRequest), "send first request") response, err := mergeBidi.Recv() @@ -144,7 +145,7 @@ func TestSuccessfulMerge_stableMergeIDs(t *testing.T) { require.NoError(t, mergeBidi.Send(&gitalypb.UserMergeBranchRequest{Apply: true}), "apply merge") response, err = mergeBidi.Recv() require.NoError(t, err, "receive second response") - require.Equal(t, response.BranchUpdate.CommitId, expectedMergeID) + require.Equal(t, expectedMergeID, response.BranchUpdate.CommitId) testhelper.ReceiveEOFWithTimeout(t, func() error { _, err = mergeBidi.Recv() @@ -168,14 +169,14 @@ func TestSuccessfulMerge_stableMergeIDs(t *testing.T) { Email: gittest.TestUser.Email, // Nanoseconds get ignored because commit timestamps aren't that granular. Date: ×tamp.Timestamp{Seconds: 12}, - Timezone: []byte("+0000"), + Timezone: []byte(gittest.TimezoneOffset), }, Committer: &gitalypb.CommitAuthor{ Name: gittest.TestUser.Name, Email: gittest.TestUser.Email, // Nanoseconds get ignored because commit timestamps aren't that granular. Date: ×tamp.Timestamp{Seconds: 12}, - Timezone: []byte("+0000"), + Timezone: []byte(gittest.TimezoneOffset), }, }) } @@ -682,6 +683,7 @@ func TestSuccessfulUserMergeToRefRequest(t *testing.T) { author := commit.Author require.Equal(t, gittest.TestUser.Name, author.Name) require.Equal(t, gittest.TestUser.Email, author.Email) + require.Equal(t, gittest.TimezoneOffset, string(author.Timezone)) require.Equal(t, resp.CommitId, commit.Id) @@ -850,7 +852,7 @@ func TestUserMergeToRef_stableMergeID(t *testing.T) { Timestamp: ×tamp.Timestamp{Seconds: 12, Nanos: 34}, }) require.NoError(t, err) - require.Equal(t, "a04514f4e6b4e272989b39cca1ebdbb670abdfd6", response.CommitId) + require.Equal(t, "c7b65194ce2da804557582408ab94713983d0b70", response.CommitId) commit, err := repo.ReadCommit(ctx, git.Revision("refs/merge-requests/x/written")) require.NoError(t, err, "look up git commit after call has finished") @@ -858,7 +860,7 @@ func TestUserMergeToRef_stableMergeID(t *testing.T) { Subject: []byte("Merge message"), Body: []byte("Merge message"), BodySize: 13, - Id: "a04514f4e6b4e272989b39cca1ebdbb670abdfd6", + Id: "c7b65194ce2da804557582408ab94713983d0b70", ParentIds: []string{ "281d3a76f31c812dbf48abce82ccf6860adedd81", "1450cd639e0bc6721eb02800169e464f212cde06", @@ -869,14 +871,14 @@ func TestUserMergeToRef_stableMergeID(t *testing.T) { Email: gittest.TestUser.Email, // Nanoseconds get ignored because commit timestamps aren't that granular. Date: ×tamp.Timestamp{Seconds: 12}, - Timezone: []byte("+0000"), + Timezone: []byte(gittest.TimezoneOffset), }, Committer: &gitalypb.CommitAuthor{ Name: gittest.TestUser.Name, Email: gittest.TestUser.Email, // Nanoseconds get ignored because commit timestamps aren't that granular. Date: ×tamp.Timestamp{Seconds: 12}, - Timezone: []byte("+0000"), + Timezone: []byte(gittest.TimezoneOffset), }, }, commit) } diff --git a/internal/gitaly/service/operations/revert.go b/internal/gitaly/service/operations/revert.go index 715e7b0c1..7f84266a9 100644 --- a/internal/gitaly/service/operations/revert.go +++ b/internal/gitaly/service/operations/revert.go @@ -4,9 +4,7 @@ import ( "context" "errors" "fmt" - "time" - "github.com/golang/protobuf/ptypes" "gitlab.com/gitlab-org/gitaly/v14/internal/git" "gitlab.com/gitlab-org/gitaly/v14/internal/git/remoterepo" "gitlab.com/gitlab-org/gitaly/v14/internal/git/updateref" @@ -41,12 +39,9 @@ func (s *Server) UserRevert(ctx context.Context, req *gitalypb.UserRevertRequest mainline = 1 } - authorDate := time.Now() - if req.Timestamp != nil { - authorDate, err = ptypes.Timestamp(req.Timestamp) - if err != nil { - return nil, helper.ErrInvalidArgument(err) - } + authorDate, err := dateFromProto(req) + if err != nil { + return nil, helper.ErrInvalidArgument(err) } newrev, err := git2go.RevertCommand{ diff --git a/internal/gitaly/service/operations/revert_test.go b/internal/gitaly/service/operations/revert_test.go index 69d95818e..4eb491b12 100644 --- a/internal/gitaly/service/operations/revert_test.go +++ b/internal/gitaly/service/operations/revert_test.go @@ -164,6 +164,8 @@ func TestServer_UserRevert_successful(t *testing.T) { } else { require.Equal(t, testCase.request.Message, headCommit.Subject) require.Equal(t, masterHeadCommit.Id, headCommit.ParentIds[0]) + require.Equal(t, gittest.TimezoneOffset, string(headCommit.Committer.Timezone)) + require.Equal(t, gittest.TimezoneOffset, string(headCommit.Author.Timezone)) } }) } @@ -191,7 +193,7 @@ func TestServer_UserRevert_stableID(t *testing.T) { require.NoError(t, err) require.Equal(t, &gitalypb.OperationBranchUpdate{ - CommitId: "9ebfd44039a9e36d88dcdfe11550399ec6a212f7", + CommitId: "9c15289b0a129c562dddf7b364eb979d41173b41", }, response.BranchUpdate) require.Empty(t, response.CreateTreeError) require.Empty(t, response.CreateTreeErrorCode) @@ -200,7 +202,7 @@ func TestServer_UserRevert_stableID(t *testing.T) { require.NoError(t, err) require.Equal(t, &gitalypb.GitCommit{ - Id: "9ebfd44039a9e36d88dcdfe11550399ec6a212f7", + Id: "9c15289b0a129c562dddf7b364eb979d41173b41", ParentIds: []string{ "1e292f8fedd741b75372e19097c76d327140c312", }, @@ -212,13 +214,13 @@ func TestServer_UserRevert_stableID(t *testing.T) { Name: []byte("Jane Doe"), Email: []byte("janedoe@gitlab.com"), Date: ×tamp.Timestamp{Seconds: 12345}, - Timezone: []byte("+0000"), + Timezone: []byte(gittest.TimezoneOffset), }, Committer: &gitalypb.CommitAuthor{ Name: []byte("Jane Doe"), Email: []byte("janedoe@gitlab.com"), Date: ×tamp.Timestamp{Seconds: 12345}, - Timezone: []byte("+0000"), + Timezone: []byte(gittest.TimezoneOffset), }, }, revertedCommit) } diff --git a/internal/gitaly/service/operations/squash.go b/internal/gitaly/service/operations/squash.go index 53e3cb117..824aa6515 100644 --- a/internal/gitaly/service/operations/squash.go +++ b/internal/gitaly/service/operations/squash.go @@ -11,9 +11,7 @@ import ( "os" "path/filepath" "strings" - "time" - "github.com/golang/protobuf/ptypes" "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus" "gitlab.com/gitlab-org/gitaly/v14/internal/command" "gitlab.com/gitlab-org/gitaly/v14/internal/git" @@ -383,21 +381,18 @@ func (s *Server) applyDiff(ctx context.Context, repo *gitalypb.Repository, req * return "", fmt.Errorf("wait for 'git apply' for range %q: %w", diffRange, gitError{ErrMsg: applyStderr.String(), Err: err}) } - commitDate := time.Now() - if req.Timestamp != nil { - commitDate, err = ptypes.Timestamp(req.Timestamp) - if err != nil { - return "", helper.ErrInvalidArgument(err) - } + commitDate, err := dateFromProto(req) + if err != nil { + return "", helper.ErrInvalidArgument(err) } commitEnv := append(env, "GIT_COMMITTER_NAME="+string(req.GetUser().Name), "GIT_COMMITTER_EMAIL="+string(req.GetUser().Email), - fmt.Sprintf("GIT_COMMITTER_DATE=%d +0000", commitDate.Unix()), + fmt.Sprintf("GIT_COMMITTER_DATE=%d %s", commitDate.Unix(), commitDate.Format("-0700")), "GIT_AUTHOR_NAME="+string(req.GetAuthor().Name), "GIT_AUTHOR_EMAIL="+string(req.GetAuthor().Email), - fmt.Sprintf("GIT_AUTHOR_DATE=%d +0000", commitDate.Unix()), + fmt.Sprintf("GIT_AUTHOR_DATE=%d %s", commitDate.Unix(), commitDate.Format("-0700")), ) var commitStderr bytes.Buffer diff --git a/internal/gitaly/service/operations/squash_test.go b/internal/gitaly/service/operations/squash_test.go index e300fad33..af94f8beb 100644 --- a/internal/gitaly/service/operations/squash_test.go +++ b/internal/gitaly/service/operations/squash_test.go @@ -24,8 +24,9 @@ import ( var ( author = &gitalypb.User{ - Name: []byte("John Doe"), - Email: []byte("johndoe@gitlab.com"), + Name: []byte("John Doe"), + Email: []byte("johndoe@gitlab.com"), + Timezone: gittest.Timezone, } branchName = "not-merged-branch" startSha = "b83d6e391c22777fca1ed3012fce84f633d7fed0" @@ -73,6 +74,8 @@ func testSuccessfulUserSquashRequest(t *testing.T, ctx context.Context, start, e require.Equal(t, author.Email, commit.Author.Email) require.Equal(t, gittest.TestUser.Name, commit.Committer.Name) require.Equal(t, gittest.TestUser.Email, commit.Committer.Email) + require.Equal(t, gittest.TimezoneOffset, string(commit.Committer.Timezone)) + require.Equal(t, gittest.TimezoneOffset, string(commit.Author.Timezone)) require.Equal(t, commitMessage, commit.Subject) treeData := gittest.Exec(t, cfg, "-C", repoPath, "ls-tree", "--name-only", response.SquashSha) @@ -104,7 +107,7 @@ func TestUserSquash_stableID(t *testing.T) { commit, err := repo.ReadCommit(ctx, git.Revision(response.SquashSha)) require.NoError(t, err) require.Equal(t, &gitalypb.GitCommit{ - Id: "2773b7aee7d81ea96d2f48aa080cae08eaae26d5", + Id: "c653dc8f98dba7f7a42c2e3c4b8d850d195e60b6", TreeId: "324242f415a3cdbfc088103b496379fd91965854", ParentIds: []string{ "b83d6e391c22777fca1ed3012fce84f633d7fed0", @@ -116,13 +119,13 @@ func TestUserSquash_stableID(t *testing.T) { Name: author.Name, Email: author.Email, Date: ×tamp.Timestamp{Seconds: 1234512345}, - Timezone: []byte("+0000"), + Timezone: []byte(gittest.TimezoneOffset), }, Committer: &gitalypb.CommitAuthor{ Name: gittest.TestUser.Name, Email: gittest.TestUser.Email, Date: ×tamp.Timestamp{Seconds: 1234512345}, - Timezone: []byte("+0000"), + Timezone: []byte(gittest.TimezoneOffset), }, }, commit) } @@ -169,6 +172,8 @@ func TestSuccessfulUserSquashRequestWith3wayMerge(t *testing.T) { require.Equal(t, author.Name, commit.Author.Name) require.Equal(t, author.Email, commit.Author.Email) require.Equal(t, gittest.TestUser.Name, commit.Committer.Name) + require.Equal(t, gittest.TimezoneOffset, string(commit.Committer.Timezone)) + require.Equal(t, gittest.TimezoneOffset, string(commit.Author.Timezone)) require.Equal(t, gittest.TestUser.Email, commit.Committer.Email) require.Equal(t, commitMessage, commit.Subject) @@ -266,6 +271,8 @@ func TestSquashRequestWithRenamedFiles(t *testing.T) { require.Equal(t, author.Email, commit.Author.Email) require.Equal(t, gittest.TestUser.Name, commit.Committer.Name) require.Equal(t, gittest.TestUser.Email, commit.Committer.Email) + require.Equal(t, gittest.TimezoneOffset, string(commit.Committer.Timezone)) + require.Equal(t, gittest.TimezoneOffset, string(commit.Author.Timezone)) require.Equal(t, commitMessage, commit.Subject) } diff --git a/internal/gitaly/service/operations/submodules.go b/internal/gitaly/service/operations/submodules.go index 2d7117450..c595f7c44 100644 --- a/internal/gitaly/service/operations/submodules.go +++ b/internal/gitaly/service/operations/submodules.go @@ -6,9 +6,7 @@ import ( "fmt" "regexp" "strings" - "time" - "github.com/golang/protobuf/ptypes" "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus" "gitlab.com/gitlab-org/gitaly/v14/internal/git" "gitlab.com/gitlab-org/gitaly/v14/internal/git/updateref" @@ -88,12 +86,9 @@ func (s *Server) userUpdateSubmodule(ctx context.Context, req *gitalypb.UserUpda return nil, fmt.Errorf("%s: locate repo: %w", userUpdateSubmoduleName, err) } - authorDate := time.Now() - if req.Timestamp != nil { - authorDate, err = ptypes.Timestamp(req.Timestamp) - if err != nil { - return nil, helper.ErrInvalidArgument(err) - } + authorDate, err := dateFromProto(req) + if err != nil { + return nil, helper.ErrInvalidArgument(err) } result, err := git2go.SubmoduleCommand{ diff --git a/internal/gitaly/service/operations/submodules_test.go b/internal/gitaly/service/operations/submodules_test.go index d993b041e..49c2fe20e 100644 --- a/internal/gitaly/service/operations/submodules_test.go +++ b/internal/gitaly/service/operations/submodules_test.go @@ -83,9 +83,10 @@ func TestSuccessfulUserUpdateSubmoduleRequest(t *testing.T) { commit, err := repo.ReadCommit(ctx, git.Revision(response.BranchUpdate.CommitId)) require.NoError(t, err) - require.Equal(t, commit.Author.Email, gittest.TestUser.Email) - require.Equal(t, commit.Committer.Email, gittest.TestUser.Email) - require.Equal(t, commit.Subject, commitMessage) + require.Equal(t, gittest.TestUser.Email, commit.Author.Email) + require.Equal(t, gittest.TimezoneOffset, string(commit.Author.Timezone)) + require.Equal(t, gittest.TestUser.Email, commit.Committer.Email) + require.Equal(t, commitMessage, commit.Subject) entry := gittest.Exec(t, cfg, "-C", repoPath, "ls-tree", "-z", fmt.Sprintf("%s^{tree}:", response.BranchUpdate.CommitId), testCase.submodule) parser := lstree.NewParser(bytes.NewReader(entry)) @@ -120,7 +121,7 @@ func TestUserUpdateSubmoduleStableID(t *testing.T) { commit, err := repo.ReadCommit(ctx, git.Revision(response.BranchUpdate.CommitId)) require.NoError(t, err) require.Equal(t, &gitalypb.GitCommit{ - Id: "e7752dfc2105bc830f8fa59b19dd4f3e49c8c44e", + Id: "928a79b1c5bbe64759f540aad8b339d281719118", ParentIds: []string{ "1e292f8fedd741b75372e19097c76d327140c312", }, @@ -132,13 +133,13 @@ func TestUserUpdateSubmoduleStableID(t *testing.T) { Name: gittest.TestUser.Name, Email: gittest.TestUser.Email, Date: ×tamp.Timestamp{Seconds: 12345}, - Timezone: []byte("+0000"), + Timezone: []byte(gittest.TimezoneOffset), }, Committer: &gitalypb.CommitAuthor{ Name: gittest.TestUser.Name, Email: gittest.TestUser.Email, Date: ×tamp.Timestamp{Seconds: 12345}, - Timezone: []byte("+0000"), + Timezone: []byte(gittest.TimezoneOffset), }, }, commit) } diff --git a/internal/gitaly/service/operations/utils.go b/internal/gitaly/service/operations/utils.go index 3ec79cb05..63d95ddc7 100644 --- a/internal/gitaly/service/operations/utils.go +++ b/internal/gitaly/service/operations/utils.go @@ -2,8 +2,11 @@ package operations import ( "fmt" + "time" + "github.com/golang/protobuf/ptypes" "gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb" + "google.golang.org/protobuf/types/known/timestamppb" ) type cherryPickOrRevertRequest interface { @@ -32,3 +35,30 @@ func validateCherryPickOrRevertRequest(req cherryPickOrRevertRequest) error { return nil } + +type userTimestampProto interface { + GetUser() *gitalypb.User + GetTimestamp() *timestamppb.Timestamp +} + +func dateFromProto(p userTimestampProto) (time.Time, error) { + date := time.Now() + + if timestamp := p.GetTimestamp(); timestamp != nil { + var err error + date, err = ptypes.Timestamp(timestamp) + if err != nil { + return time.Time{}, err + } + } + + if user := p.GetUser(); user != nil { + location, err := time.LoadLocation(user.GetTimezone()) + if err != nil { + return time.Time{}, err + } + date = date.In(location) + } + + return date, nil +} diff --git a/internal/gitaly/service/operations/utils_test.go b/internal/gitaly/service/operations/utils_test.go new file mode 100644 index 000000000..2745ccabf --- /dev/null +++ b/internal/gitaly/service/operations/utils_test.go @@ -0,0 +1,44 @@ +package operations + +import ( + "errors" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb" + "google.golang.org/protobuf/types/known/timestamppb" +) + +func TestDateFromProto(t *testing.T) { + locUtc, _ := time.LoadLocation("UTC") + locShanghai, _ := time.LoadLocation("Asia/Shanghai") + staticNow := time.Now() + + testCases := []struct { + timezone string + want *time.Location + err error + }{ + {"UTC", locUtc, nil}, + {"Asia/Shanghai", locShanghai, nil}, + {"Illegal/Format", locUtc, errors.New("unknown time zone Illegal/Format")}, + {"", locUtc, nil}, + } + for _, testCase := range testCases { + t.Run(testCase.timezone, func(t *testing.T) { + req := &gitalypb.UserSquashRequest{ + User: &gitalypb.User{Timezone: testCase.timezone}, + Timestamp: timestamppb.New(staticNow), + } + got, err := dateFromProto(req) + + if testCase.err != nil { + assert.Equal(t, testCase.err.Error(), err.Error()) + } else { + assert.Equal(t, staticNow.UnixNano(), got.UnixNano()) + } + assert.Equal(t, testCase.want, got.Location()) + }) + } +} diff --git a/proto/go/gitalypb/shared.pb.go b/proto/go/gitalypb/shared.pb.go index e1d040014..192d33976 100644 --- a/proto/go/gitalypb/shared.pb.go +++ b/proto/go/gitalypb/shared.pb.go @@ -694,6 +694,9 @@ type User struct { Name []byte `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` Email []byte `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` GlUsername string `protobuf:"bytes,4,opt,name=gl_username,json=glUsername,proto3" json:"gl_username,omitempty"` + // Timezone is the timezone as configured by the user in the web interface. This + // timezone may be used when new commits are created via RPC calls. + Timezone string `protobuf:"bytes,5,opt,name=timezone,proto3" json:"timezone,omitempty"` } func (x *User) Reset() { @@ -756,6 +759,13 @@ func (x *User) GetGlUsername() string { return "" } +func (x *User) GetTimezone() string { + if x != nil { + return x.Timezone + } + return "" +} + type ObjectPool struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1004,37 +1014,39 @@ var file_shared_proto_rawDesc = []byte{ 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0d, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, - 0x66, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x13, 0x0a, 0x05, 0x67, 0x6c, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x67, 0x6c, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x67, 0x6c, 0x5f, 0x75, 0x73, 0x65, - 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x67, 0x6c, 0x55, - 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x46, 0x0a, 0x0a, 0x4f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x50, 0x6f, 0x6f, 0x6c, 0x12, 0x38, 0x0a, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, - 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x69, 0x74, 0x61, - 0x6c, 0x79, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x42, 0x04, 0x90, - 0xc6, 0x2c, 0x01, 0x52, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x22, - 0x4a, 0x0a, 0x13, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x72, - 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, - 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x3c, 0x0a, 0x0d, 0x47, - 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2b, 0x0a, 0x11, - 0x6c, 0x69, 0x74, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x70, 0x65, 0x63, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x6c, 0x69, 0x74, 0x65, 0x72, 0x61, 0x6c, - 0x50, 0x61, 0x74, 0x68, 0x73, 0x70, 0x65, 0x63, 0x73, 0x2a, 0x42, 0x0a, 0x0a, 0x4f, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, - 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x10, 0x01, - 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4c, 0x4f, 0x42, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x54, 0x52, - 0x45, 0x45, 0x10, 0x03, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x41, 0x47, 0x10, 0x04, 0x2a, 0x2c, 0x0a, - 0x0d, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, - 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x50, 0x47, 0x50, 0x10, - 0x01, 0x12, 0x08, 0x0a, 0x04, 0x58, 0x35, 0x30, 0x39, 0x10, 0x02, 0x42, 0x34, 0x5a, 0x32, 0x67, - 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, - 0x2d, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2f, 0x76, 0x31, 0x34, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x70, - 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x82, 0x01, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x13, 0x0a, 0x05, 0x67, 0x6c, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x67, 0x6c, 0x49, 0x64, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x67, 0x6c, 0x5f, 0x75, 0x73, + 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x67, 0x6c, + 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x69, 0x6d, 0x65, + 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, + 0x7a, 0x6f, 0x6e, 0x65, 0x22, 0x46, 0x0a, 0x0a, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x50, 0x6f, + 0x6f, 0x6c, 0x12, 0x38, 0x0a, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, + 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x42, 0x04, 0x90, 0xc6, 0x2c, 0x01, + 0x52, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x22, 0x4a, 0x0a, 0x13, + 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, + 0x74, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x3c, 0x0a, 0x0d, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x6c, 0x69, 0x74, + 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x70, 0x65, 0x63, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x6c, 0x69, 0x74, 0x65, 0x72, 0x61, 0x6c, 0x50, 0x61, 0x74, + 0x68, 0x73, 0x70, 0x65, 0x63, 0x73, 0x2a, 0x42, 0x0a, 0x0a, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, + 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x10, 0x01, 0x12, 0x08, 0x0a, + 0x04, 0x42, 0x4c, 0x4f, 0x42, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x54, 0x52, 0x45, 0x45, 0x10, + 0x03, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x41, 0x47, 0x10, 0x04, 0x2a, 0x2c, 0x0a, 0x0d, 0x53, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x4e, + 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x50, 0x47, 0x50, 0x10, 0x01, 0x12, 0x08, + 0x0a, 0x04, 0x58, 0x35, 0x30, 0x39, 0x10, 0x02, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x6c, + 0x61, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2d, 0x6f, 0x72, + 0x67, 0x2f, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2f, 0x76, 0x31, 0x34, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x70, 0x62, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/shared.proto b/proto/shared.proto index 4d357a3fe..dd69882fc 100644 --- a/proto/shared.proto +++ b/proto/shared.proto @@ -117,6 +117,9 @@ message User { bytes name = 2; bytes email = 3; string gl_username = 4; + // Timezone is the timezone as configured by the user in the web interface. This + // timezone may be used when new commits are created via RPC calls. + string timezone = 5; } message ObjectPool { diff --git a/ruby/proto/gitaly/shared_pb.rb b/ruby/proto/gitaly/shared_pb.rb index d20479f96..0a9853223 100644 --- a/ruby/proto/gitaly/shared_pb.rb +++ b/ruby/proto/gitaly/shared_pb.rb @@ -58,6 +58,7 @@ Google::Protobuf::DescriptorPool.generated_pool.build do optional :name, :bytes, 2 optional :email, :bytes, 3 optional :gl_username, :string, 4 + optional :timezone, :string, 5 end add_message "gitaly.ObjectPool" do optional :repository, :message, 1, "gitaly.Repository" |