1package git2go
2
3import (
4	"context"
5	"fmt"
6	"io"
7	"time"
8
9	"gitlab.com/gitlab-org/gitaly/v14/internal/git/repository"
10)
11
12// Error strings present in the legacy Ruby implementation
13const (
14	LegacyErrPrefixInvalidBranch        = "Invalid branch"
15	LegacyErrPrefixInvalidSubmodulePath = "Invalid submodule path"
16	LegacyErrPrefixFailedCommit         = "Failed to create commit"
17)
18
19// SubmoduleCommand instructs how to commit a submodule update to a repo
20type SubmoduleCommand struct {
21	// Repository is the path to commit the submodule change
22	Repository string `json:"repository"`
23
24	// AuthorName is the author name of submodule commit.
25	AuthorName string `json:"author_name"`
26	// AuthorMail is the author mail of submodule commit.
27	AuthorMail string `json:"author_mail"`
28	// AuthorDate is the auithor date of submodule commit.
29	AuthorDate time.Time `json:"author_date"`
30	// Message is the message to be used for the submodule commit.
31	Message string `json:"message"`
32
33	// CommitSHA is where the submodule should point
34	CommitSHA string `json:"commit_sha"`
35	// Submodule is the actual submodule string to commit to the tree
36	Submodule string `json:"submodule"`
37	// Branch where to commit submodule update
38	Branch string `json:"branch"`
39}
40
41// SubmoduleResult contains results from a committing a submodule update
42type SubmoduleResult struct {
43	// CommitID is the object ID of the generated submodule commit.
44	CommitID string `json:"commit_id"`
45}
46
47// SubmoduleCommandFromSerialized deserializes the submodule request from its JSON representation encoded with base64.
48func SubmoduleCommandFromSerialized(serialized string) (SubmoduleCommand, error) {
49	var request SubmoduleCommand
50	if err := deserialize(serialized, &request); err != nil {
51		return SubmoduleCommand{}, err
52	}
53
54	if err := request.verify(); err != nil {
55		return SubmoduleCommand{}, fmt.Errorf("submodule: %w", err)
56	}
57
58	return request, nil
59}
60
61// SerializeTo serializes the submodule result and writes it into the writer.
62func (s SubmoduleResult) SerializeTo(w io.Writer) error {
63	return serializeTo(w, s)
64}
65
66// Submodule attempts to commit the request submodule change
67func (b Executor) Submodule(ctx context.Context, repo repository.GitRepo, s SubmoduleCommand) (SubmoduleResult, error) {
68	if err := s.verify(); err != nil {
69		return SubmoduleResult{}, fmt.Errorf("submodule: %w", err)
70	}
71
72	serialized, err := serialize(s)
73	if err != nil {
74		return SubmoduleResult{}, err
75	}
76
77	stdout, err := b.run(ctx, repo, nil, "submodule", "-request", serialized)
78	if err != nil {
79		return SubmoduleResult{}, err
80	}
81
82	var response SubmoduleResult
83	if err := deserialize(stdout.String(), &response); err != nil {
84		return SubmoduleResult{}, err
85	}
86
87	return response, nil
88}
89
90func (s SubmoduleCommand) verify() (err error) {
91	if s.Repository == "" {
92		return InvalidArgumentError("missing repository")
93	}
94	if s.AuthorName == "" {
95		return InvalidArgumentError("missing author name")
96	}
97	if s.AuthorMail == "" {
98		return InvalidArgumentError("missing author mail")
99	}
100	if s.CommitSHA == "" {
101		return InvalidArgumentError("missing commit SHA")
102	}
103	if s.Branch == "" {
104		return InvalidArgumentError("missing branch name")
105	}
106	if s.Submodule == "" {
107		return InvalidArgumentError("missing submodule")
108	}
109	return nil
110}
111