diff options
author | Zeger-Jan van de Weg <git@zjvandeweg.nl> | 2020-10-16 11:41:27 +0300 |
---|---|---|
committer | Zeger-Jan van de Weg <git@zjvandeweg.nl> | 2020-10-16 11:41:27 +0300 |
commit | fe716289d7ab396ea8a7675233983dac9477ac06 (patch) | |
tree | 778fc72aef92d65c897ca204d4ed79305018db1a /internal/git2go | |
parent | e21d4f1e9ab1966581d46ec7de2f3089c55e7088 (diff) | |
parent | e911e73f30fa06b80d3b6d3670c7c476fea84e37 (diff) |
Merge branch 'git2go_revert' into 'master'
gitaly-git2go revert command
See merge request gitlab-org/gitaly!2625
Diffstat (limited to 'internal/git2go')
-rw-r--r-- | internal/git2go/merge_test.go | 1 | ||||
-rw-r--r-- | internal/git2go/revert.go | 100 | ||||
-rw-r--r-- | internal/git2go/revert_test.go | 160 |
3 files changed, 261 insertions, 0 deletions
diff --git a/internal/git2go/merge_test.go b/internal/git2go/merge_test.go index 5f0bc60c4..227475471 100644 --- a/internal/git2go/merge_test.go +++ b/internal/git2go/merge_test.go @@ -109,6 +109,7 @@ func TestGit2Go_MergeCommandSerialization(t *testing.T) { func TestGit2Go_MergeResultSerialization(t *testing.T) { serializeResult := func(t *testing.T, result MergeResult) string { + t.Helper() var buf bytes.Buffer err := result.SerializeTo(&buf) require.NoError(t, err) diff --git a/internal/git2go/revert.go b/internal/git2go/revert.go new file mode 100644 index 000000000..ca11169bf --- /dev/null +++ b/internal/git2go/revert.go @@ -0,0 +1,100 @@ +package git2go + +import ( + "context" + "errors" + "fmt" + "io" + "time" + + "gitlab.com/gitlab-org/gitaly/internal/gitaly/config" +) + +// RevertResult contains results from a revert. +type RevertResult struct { + // CommitID is the object ID of the generated revert commit. + CommitID string `json:"commit_id"` +} + +// SerializeTo serializes the revert result and writes it into the writer. +func (r RevertResult) SerializeTo(w io.Writer) error { + return serializeTo(w, r) +} + +type RevertCommand struct { + // Repository is the path to execute the revert in. + Repository string `json:"repository"` + // AuthorName is the author name of revert commit. + AuthorName string `json:"author_name"` + // AuthorMail is the author mail of revert commit. + AuthorMail string `json:"author_mail"` + // AuthorDate is the author date of revert commit. + AuthorDate time.Time `json:"author_date"` + // Message is the message to be used for the revert commit. + Message string `json:"message"` + // Ours is the commit that the revert is applied to. + Ours string `json:"ours"` + // Revert is the commit to be reverted. + Revert string `json:"revert"` + // Mainline is the parent to be considered the mainline + Mainline uint `json:"mainline"` +} + +func (r RevertCommand) Run(ctx context.Context, cfg config.Cfg) (RevertResult, error) { + if err := r.verify(); err != nil { + return RevertResult{}, fmt.Errorf("revert: %w: %s", ErrInvalidArgument, err.Error()) + } + + serialized, err := serialize(r) + if err != nil { + return RevertResult{}, err + } + + stdout, err := run(ctx, cfg, "revert", serialized) + if err != nil { + return RevertResult{}, err + } + + var response RevertResult + if err := deserialize(stdout, &response); err != nil { + return RevertResult{}, err + } + + return response, nil +} + +func (r RevertCommand) verify() error { + if r.Repository == "" { + return errors.New("missing repository") + } + if r.AuthorName == "" { + return errors.New("missing author name") + } + if r.AuthorMail == "" { + return errors.New("missing author mail") + } + if r.Message == "" { + return errors.New("missing message") + } + if r.Ours == "" { + return errors.New("missing ours") + } + if r.Revert == "" { + return errors.New("missing revert") + } + return nil +} + +// RevertCommandFromSerialized deserializes the revert request from its JSON representation encoded with base64. +func RevertCommandFromSerialized(serialized string) (RevertCommand, error) { + var request RevertCommand + if err := deserialize(serialized, &request); err != nil { + return RevertCommand{}, err + } + + if err := request.verify(); err != nil { + return RevertCommand{}, fmt.Errorf("revert: %w: %s", ErrInvalidArgument, err.Error()) + } + + return request, nil +} diff --git a/internal/git2go/revert_test.go b/internal/git2go/revert_test.go new file mode 100644 index 000000000..c56e4da4e --- /dev/null +++ b/internal/git2go/revert_test.go @@ -0,0 +1,160 @@ +package git2go + +import ( + "bytes" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestGit2Go_RevertCommandSerialization(t *testing.T) { + testcases := []struct { + desc string + cmd RevertCommand + err string + }{ + { + desc: "missing repository", + cmd: RevertCommand{}, + err: "missing repository", + }, + { + desc: "missing author name", + cmd: RevertCommand{ + Repository: "foo", + }, + err: "missing author name", + }, + { + desc: "missing author mail", + cmd: RevertCommand{ + Repository: "foo", + AuthorName: "Au Thor", + }, + err: "missing author mail", + }, + { + desc: "missing author message", + cmd: RevertCommand{ + Repository: "foo", + AuthorName: "Au Thor", + AuthorMail: "au@thor.com", + }, + err: "missing message", + }, + { + desc: "missing author ours", + cmd: RevertCommand{ + Repository: "foo", + AuthorName: "Au Thor", + AuthorMail: "au@thor.com", + Message: "Message", + }, + err: "missing ours", + }, + { + desc: "missing revert", + cmd: RevertCommand{ + Repository: "foo", + AuthorName: "Au Thor", + AuthorMail: "au@thor.com", + Message: "Message", + Ours: "refs/heads/master", + }, + err: "missing revert", + }, + { + desc: "valid command", + cmd: RevertCommand{ + Repository: "foo", + AuthorName: "Au Thor", + AuthorMail: "au@thor.com", + Message: "Message", + Ours: "refs/heads/master", + Revert: "refs/heads/master", + }, + }, + { + desc: "valid command with date", + cmd: RevertCommand{ + Repository: "foo", + AuthorName: "Au Thor", + AuthorMail: "au@thor.com", + AuthorDate: time.Now().UTC(), + Message: "Message", + Ours: "refs/heads/master", + Revert: "refs/heads/master", + }, + }, + } + + for _, tc := range testcases { + t.Run(tc.desc, func(t *testing.T) { + serialized, err := serialize(tc.cmd) + require.NoError(t, err) + + deserialized, err := RevertCommandFromSerialized(serialized) + + if tc.err != "" { + require.Error(t, err) + require.Contains(t, err.Error(), tc.err) + } else { + require.NoError(t, err) + require.Equal(t, tc.cmd, deserialized) + } + }) + } +} + +func TestGit2Go_RevertResultSerialization(t *testing.T) { + serializeResult := func(t *testing.T, result RevertResult) string { + t.Helper() + var buf bytes.Buffer + err := result.SerializeTo(&buf) + require.NoError(t, err) + return buf.String() + } + + testcases := []struct { + desc string + serialized string + expected RevertResult + err string + }{ + { + desc: "empty revert result", + serialized: serializeResult(t, RevertResult{}), + expected: RevertResult{}, + }, + { + desc: "revert result with commit", + serialized: serializeResult(t, RevertResult{ + CommitID: "1234", + }), + expected: RevertResult{ + CommitID: "1234", + }, + }, + { + desc: "invalid serialized representation", + serialized: "xvlc", + err: "invalid character", + }, + } + + for _, tc := range testcases { + t.Run(tc.desc, func(t *testing.T) { + var deserialized RevertResult + err := deserialize(tc.serialized, &deserialized) + + if tc.err != "" { + require.Error(t, err) + require.Contains(t, err.Error(), tc.err) + } else { + require.NoError(t, err) + require.Equal(t, tc.expected, deserialized) + } + }) + } +} |