diff options
author | John Cai <jcai@gitlab.com> | 2023-06-28 18:43:48 +0300 |
---|---|---|
committer | John Cai <jcai@gitlab.com> | 2023-07-07 18:37:18 +0300 |
commit | 3a4954a025bab668293aecaa8927ea0a356913e6 (patch) | |
tree | 662188aceaff318085ddc0a5c7c15534fb009a3a | |
parent | 480dc8a814e6bc56a547f8207d4d1f19b812dc2e (diff) |
git2go: Remove Commit codejc/remove-git2go-commit
Now that we no longer create commits with git2go, let's remove all
associated code.
-rw-r--r-- | cmd/gitaly-git2go/commit.go | 21 | ||||
-rw-r--r-- | cmd/gitaly-git2go/commit/change_file_mode.go | 30 | ||||
-rw-r--r-- | cmd/gitaly-git2go/commit/commit.go | 116 | ||||
-rw-r--r-- | cmd/gitaly-git2go/commit/create_directory.go | 30 | ||||
-rw-r--r-- | cmd/gitaly-git2go/commit/create_file.go | 30 | ||||
-rw-r--r-- | cmd/gitaly-git2go/commit/delete_file.go | 16 | ||||
-rw-r--r-- | cmd/gitaly-git2go/commit/move_file.go | 41 | ||||
-rw-r--r-- | cmd/gitaly-git2go/commit/update_file.go | 30 | ||||
-rw-r--r-- | cmd/gitaly-git2go/commit/validate.go | 48 | ||||
-rw-r--r-- | cmd/gitaly-git2go/main.go | 1 | ||||
-rw-r--r-- | internal/git2go/commit.go | 29 | ||||
-rw-r--r-- | internal/git2go/commit_test.go | 623 |
12 files changed, 0 insertions, 1015 deletions
diff --git a/cmd/gitaly-git2go/commit.go b/cmd/gitaly-git2go/commit.go deleted file mode 100644 index f418a864a..000000000 --- a/cmd/gitaly-git2go/commit.go +++ /dev/null @@ -1,21 +0,0 @@ -//go:build static && system_libgit2 - -package main - -import ( - "context" - "encoding/gob" - "flag" - - "gitlab.com/gitlab-org/gitaly/v16/cmd/gitaly-git2go/commit" -) - -type commitSubcommand struct{} - -func (cmd *commitSubcommand) Flags() *flag.FlagSet { - return flag.NewFlagSet("commit", flag.ExitOnError) -} - -func (cmd *commitSubcommand) Run(ctx context.Context, decoder *gob.Decoder, encoder *gob.Encoder) error { - return commit.Run(ctx, decoder, encoder) -} diff --git a/cmd/gitaly-git2go/commit/change_file_mode.go b/cmd/gitaly-git2go/commit/change_file_mode.go deleted file mode 100644 index b36445688..000000000 --- a/cmd/gitaly-git2go/commit/change_file_mode.go +++ /dev/null @@ -1,30 +0,0 @@ -//go:build static && system_libgit2 - -package commit - -import ( - git "github.com/libgit2/git2go/v34" - "gitlab.com/gitlab-org/gitaly/v16/internal/git2go" -) - -func applyChangeFileMode(action git2go.ChangeFileMode, index *git.Index) error { - entry, err := index.EntryByPath(action.Path, 0) - if err != nil { - if git.IsErrorCode(err, git.ErrorCodeNotFound) { - return git2go.IndexError{Type: git2go.ErrFileNotFound, Path: action.Path} - } - - return err - } - - mode := git.FilemodeBlob - if action.ExecutableMode { - mode = git.FilemodeBlobExecutable - } - - return index.Add(&git.IndexEntry{ - Path: action.Path, - Mode: mode, - Id: entry.Id, - }) -} diff --git a/cmd/gitaly-git2go/commit/commit.go b/cmd/gitaly-git2go/commit/commit.go deleted file mode 100644 index a6964692c..000000000 --- a/cmd/gitaly-git2go/commit/commit.go +++ /dev/null @@ -1,116 +0,0 @@ -//go:build static && system_libgit2 - -package commit - -import ( - "context" - "encoding/gob" - "errors" - "fmt" - - git "github.com/libgit2/git2go/v34" - "gitlab.com/gitlab-org/gitaly/v16/cmd/gitaly-git2go/git2goutil" - "gitlab.com/gitlab-org/gitaly/v16/internal/git2go" -) - -// Run runs the commit subcommand. -func Run(ctx context.Context, decoder *gob.Decoder, encoder *gob.Encoder) error { - var params git2go.CommitCommand - if err := decoder.Decode(¶ms); err != nil { - return err - } - - commitID, err := commit(ctx, params) - return encoder.Encode(git2go.Result{ - CommitID: commitID, - Err: git2go.SerializableError(err), - }) -} - -func commit(ctx context.Context, request git2go.CommitCommand) (string, error) { - repo, err := git2goutil.OpenRepository(request.Repository) - if err != nil { - return "", fmt.Errorf("open repository: %w", err) - } - - index, err := git.NewIndex() - if err != nil { - return "", fmt.Errorf("new index: %w", err) - } - - var parents []*git.Commit - if request.Parent != "" { - parentOID, err := git.NewOid(request.Parent) - if err != nil { - return "", fmt.Errorf("parse base commit oid: %w", err) - } - - baseCommit, err := repo.LookupCommit(parentOID) - if err != nil { - return "", fmt.Errorf("lookup commit: %w", err) - } - - parents = []*git.Commit{baseCommit} - - baseTree, err := baseCommit.Tree() - if err != nil { - return "", fmt.Errorf("lookup tree: %w", err) - } - - if err := index.ReadTree(baseTree); err != nil { - return "", fmt.Errorf("read tree: %w", err) - } - } - - for _, action := range request.Actions { - if err := apply(action, repo, index); err != nil { - if git.IsErrorClass(err, git.ErrorClassIndex) { - err = git2go.UnknownIndexError(err.Error()) - } - - return "", fmt.Errorf("apply action %T: %w", action, err) - } - } - - treeOID, err := index.WriteTreeTo(repo) - if err != nil { - return "", fmt.Errorf("write tree: %w", err) - } - tree, err := repo.LookupTree(treeOID) - if err != nil { - return "", fmt.Errorf("lookup tree: %w", err) - } - - author := git.Signature(request.Author) - committer := git.Signature(request.Committer) - commitID, err := git2goutil.NewCommitSubmitter(repo, request.SigningKey). - Commit(&author, &committer, git.MessageEncodingUTF8, request.Message, tree, parents...) - if err != nil { - if git.IsErrorClass(err, git.ErrorClassInvalid) { - return "", git2go.InvalidArgumentError(err.Error()) - } - - return "", fmt.Errorf("create commit: %w", err) - } - - return commitID.String(), nil -} - -func apply(action git2go.Action, repo *git.Repository, index *git.Index) error { - switch action := action.(type) { - case git2go.ChangeFileMode: - return applyChangeFileMode(action, index) - case git2go.CreateDirectory: - return applyCreateDirectory(action, repo, index) - case git2go.CreateFile: - return applyCreateFile(action, index) - case git2go.DeleteFile: - return applyDeleteFile(action, index) - case git2go.MoveFile: - return applyMoveFile(action, index) - case git2go.UpdateFile: - return applyUpdateFile(action, index) - default: - return errors.New("unsupported action") - } -} diff --git a/cmd/gitaly-git2go/commit/create_directory.go b/cmd/gitaly-git2go/commit/create_directory.go deleted file mode 100644 index c990933be..000000000 --- a/cmd/gitaly-git2go/commit/create_directory.go +++ /dev/null @@ -1,30 +0,0 @@ -//go:build static && system_libgit2 - -package commit - -import ( - "fmt" - "path/filepath" - - git "github.com/libgit2/git2go/v34" - "gitlab.com/gitlab-org/gitaly/v16/internal/git2go" -) - -func applyCreateDirectory(action git2go.CreateDirectory, repo *git.Repository, index *git.Index) error { - if err := validateFileDoesNotExist(index, action.Path); err != nil { - return err - } else if err := validateDirectoryDoesNotExist(index, action.Path); err != nil { - return err - } - - emptyBlobOID, err := repo.CreateBlobFromBuffer([]byte{}) - if err != nil { - return fmt.Errorf("create blob from buffer: %w", err) - } - - return index.Add(&git.IndexEntry{ - Path: filepath.Join(action.Path, ".gitkeep"), - Mode: git.FilemodeBlob, - Id: emptyBlobOID, - }) -} diff --git a/cmd/gitaly-git2go/commit/create_file.go b/cmd/gitaly-git2go/commit/create_file.go deleted file mode 100644 index 9862973d0..000000000 --- a/cmd/gitaly-git2go/commit/create_file.go +++ /dev/null @@ -1,30 +0,0 @@ -//go:build static && system_libgit2 - -package commit - -import ( - git "github.com/libgit2/git2go/v34" - "gitlab.com/gitlab-org/gitaly/v16/internal/git2go" -) - -func applyCreateFile(action git2go.CreateFile, index *git.Index) error { - if err := validateFileDoesNotExist(index, action.Path); err != nil { - return err - } - - oid, err := git.NewOid(action.OID) - if err != nil { - return err - } - - mode := git.FilemodeBlob - if action.ExecutableMode { - mode = git.FilemodeBlobExecutable - } - - return index.Add(&git.IndexEntry{ - Path: action.Path, - Mode: mode, - Id: oid, - }) -} diff --git a/cmd/gitaly-git2go/commit/delete_file.go b/cmd/gitaly-git2go/commit/delete_file.go deleted file mode 100644 index 507297266..000000000 --- a/cmd/gitaly-git2go/commit/delete_file.go +++ /dev/null @@ -1,16 +0,0 @@ -//go:build static && system_libgit2 - -package commit - -import ( - git "github.com/libgit2/git2go/v34" - "gitlab.com/gitlab-org/gitaly/v16/internal/git2go" -) - -func applyDeleteFile(action git2go.DeleteFile, index *git.Index) error { - if err := validateFileExists(index, action.Path); err != nil { - return err - } - - return index.RemoveByPath(action.Path) -} diff --git a/cmd/gitaly-git2go/commit/move_file.go b/cmd/gitaly-git2go/commit/move_file.go deleted file mode 100644 index 4c0294c5f..000000000 --- a/cmd/gitaly-git2go/commit/move_file.go +++ /dev/null @@ -1,41 +0,0 @@ -//go:build static && system_libgit2 - -package commit - -import ( - git "github.com/libgit2/git2go/v34" - "gitlab.com/gitlab-org/gitaly/v16/internal/git2go" -) - -func applyMoveFile(action git2go.MoveFile, index *git.Index) error { - entry, err := index.EntryByPath(action.Path, 0) - if err != nil { - if git.IsErrorCode(err, git.ErrorCodeNotFound) { - return git2go.IndexError{Type: git2go.ErrFileNotFound, Path: action.Path} - } - - return err - } - - if err := validateFileDoesNotExist(index, action.NewPath); err != nil { - return err - } - - oid := entry.Id - if action.OID != "" { - oid, err = git.NewOid(action.OID) - if err != nil { - return err - } - } - - if err := index.Add(&git.IndexEntry{ - Path: action.NewPath, - Mode: entry.Mode, - Id: oid, - }); err != nil { - return err - } - - return index.RemoveByPath(entry.Path) -} diff --git a/cmd/gitaly-git2go/commit/update_file.go b/cmd/gitaly-git2go/commit/update_file.go deleted file mode 100644 index d4236a2ab..000000000 --- a/cmd/gitaly-git2go/commit/update_file.go +++ /dev/null @@ -1,30 +0,0 @@ -//go:build static && system_libgit2 - -package commit - -import ( - git "github.com/libgit2/git2go/v34" - "gitlab.com/gitlab-org/gitaly/v16/internal/git2go" -) - -func applyUpdateFile(action git2go.UpdateFile, index *git.Index) error { - entry, err := index.EntryByPath(action.Path, 0) - if err != nil { - if git.IsErrorCode(err, git.ErrorCodeNotFound) { - return git2go.IndexError{Type: git2go.ErrFileNotFound, Path: action.Path} - } - - return err - } - - oid, err := git.NewOid(action.OID) - if err != nil { - return err - } - - return index.Add(&git.IndexEntry{ - Path: action.Path, - Mode: entry.Mode, - Id: oid, - }) -} diff --git a/cmd/gitaly-git2go/commit/validate.go b/cmd/gitaly-git2go/commit/validate.go deleted file mode 100644 index 7dbe43794..000000000 --- a/cmd/gitaly-git2go/commit/validate.go +++ /dev/null @@ -1,48 +0,0 @@ -//go:build static && system_libgit2 - -package commit - -import ( - "os" - - git "github.com/libgit2/git2go/v34" - "gitlab.com/gitlab-org/gitaly/v16/internal/git2go" -) - -func validateFileExists(index *git.Index, path string) error { - if _, err := index.Find(path); err != nil { - if git.IsErrorCode(err, git.ErrorCodeNotFound) { - return git2go.IndexError{Type: git2go.ErrFileNotFound, Path: path} - } - - return err - } - - return nil -} - -func validateFileDoesNotExist(index *git.Index, path string) error { - _, err := index.Find(path) - if err == nil { - return git2go.IndexError{Type: git2go.ErrFileExists, Path: path} - } - - if !git.IsErrorCode(err, git.ErrorCodeNotFound) { - return err - } - - return nil -} - -func validateDirectoryDoesNotExist(index *git.Index, path string) error { - _, err := index.FindPrefix(path + string(os.PathSeparator)) - if err == nil { - return git2go.IndexError{Type: git2go.ErrDirectoryExists, Path: path} - } - - if !git.IsErrorCode(err, git.ErrorCodeNotFound) { - return err - } - - return nil -} diff --git a/cmd/gitaly-git2go/main.go b/cmd/gitaly-git2go/main.go index ac050c427..132c8db1d 100644 --- a/cmd/gitaly-git2go/main.go +++ b/cmd/gitaly-git2go/main.go @@ -27,7 +27,6 @@ type subcmd interface { var subcommands = map[string]subcmd{ "apply": &applySubcommand{}, "cherry-pick": &cherryPickSubcommand{}, - "commit": &commitSubcommand{}, "merge": &mergeSubcommand{}, "rebase": &rebaseSubcommand{}, "revert": &revertSubcommand{}, diff --git a/internal/git2go/commit.go b/internal/git2go/commit.go index 2fb7232ea..4325cd930 100644 --- a/internal/git2go/commit.go +++ b/internal/git2go/commit.go @@ -1,12 +1,9 @@ package git2go import ( - "context" "errors" "fmt" - "gitlab.com/gitlab-org/gitaly/v16/internal/git" - "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage" "gitlab.com/gitlab-org/gitaly/v16/internal/structerr" "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb" ) @@ -104,29 +101,3 @@ func (err IndexError) StructuredError() structerr.Error { type InvalidArgumentError string func (err InvalidArgumentError) Error() string { return string(err) } - -// CommitCommand contains the information and the steps to build a commit. -type CommitCommand struct { - // Repository is the path of the repository to operate on. - Repository string - // Author is the author of the commit. - Author Signature - // Committer is the committer of the commit. - Committer Signature - // Message is message of the commit. - Message string - // Parent is the OID of the commit to use as the parent of this commit. - Parent string - // Actions are the steps to build the commit. - Actions []Action - // SigningKey is a path to the key to sign commit using OpenPGP - SigningKey string -} - -// Commit builds a commit from the actions, writes it to the object database and -// returns its object id. -func (b *Executor) Commit(ctx context.Context, repo storage.Repository, c CommitCommand) (git.ObjectID, error) { - c.SigningKey = b.signingKey - - return b.runWithGob(ctx, repo, "commit", c) -} diff --git a/internal/git2go/commit_test.go b/internal/git2go/commit_test.go deleted file mode 100644 index aff97419e..000000000 --- a/internal/git2go/commit_test.go +++ /dev/null @@ -1,623 +0,0 @@ -//go:build !gitaly_test_sha256 - -package git2go - -import ( - "bytes" - "context" - "errors" - "fmt" - "os" - "testing" - - "github.com/stretchr/testify/require" - "gitlab.com/gitlab-org/gitaly/v16/internal/git" - "gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest" - "gitlab.com/gitlab-org/gitaly/v16/internal/git/localrepo" - "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config" - "gitlab.com/gitlab-org/gitaly/v16/internal/signature" - "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper" - "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg" -) - -func TestMain(m *testing.M) { - testhelper.Run(m) -} - -//go:generate rm testdata/signing_ssh_key_ed25519 -//go:generate ssh-keygen -t ed25519 -f testdata/signing_ssh_key_ed25519 -q -N "" -//go:generate ssh-keygen -Y sign -n git -f testdata/signing_ssh_key_ed25519 testdata/commit -//go:generate mv testdata/commit.sig testdata/signing_ssh_key_ed25519.sig -//go:generate rm testdata/signing_ssh_key_rsa -//go:generate ssh-keygen -t rsa -b 4096 -f testdata/signing_ssh_key_rsa -q -N "" -//go:generate ssh-keygen -Y sign -n git -f testdata/signing_ssh_key_rsa testdata/commit -//go:generate mv testdata/commit.sig testdata/signing_ssh_key_rsa.sig -//go:generate rm testdata/signing_ssh_key_ecdsa -//go:generate ssh-keygen -t ecdsa -f testdata/signing_ssh_key_ecdsa -q -N "" -func TestExecutor_Commit(t *testing.T) { - const ( - DefaultMode = "100644" - ExecutableMode = "100755" - ) - - type signingKey struct { - path string - sigPath string - } - type step struct { - actions []Action - error error - treeEntries []gittest.TreeEntry - testCommit func(testing.TB, git.ObjectID, signingKey) - } - ctx := testhelper.Context(t) - - cfg := testcfg.Build(t) - testcfg.BuildGitalyGit2Go(t, cfg) - - repoProto, repoPath := gittest.CreateRepository(t, ctx, cfg, gittest.CreateRepositoryConfig{ - SkipCreationViaService: true, - }) - - repo := localrepo.NewTestRepo(t, cfg, repoProto) - - originalFile, err := repo.WriteBlob(ctx, "file", bytes.NewBufferString("original")) - require.NoError(t, err) - - updatedFile, err := repo.WriteBlob(ctx, "file", bytes.NewBufferString("updated")) - require.NoError(t, err) - - executor := NewExecutor(cfg, gittest.NewCommandFactory(t, cfg), config.NewLocator(cfg)) - - author := defaultCommitAuthorSignature() - committer := defaultCommitAuthorSignature() - - for _, tc := range []struct { - desc string - steps []step - }{ - { - desc: "create directory", - steps: []step{ - { - actions: []Action{ - CreateDirectory{Path: "directory"}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: DefaultMode, Path: "directory/.gitkeep"}, - }, - }, - }, - }, - { - desc: "create directory created duplicate", - steps: []step{ - { - actions: []Action{ - CreateDirectory{Path: "directory"}, - CreateDirectory{Path: "directory"}, - }, - error: IndexError{Type: ErrDirectoryExists, Path: "directory"}, - }, - }, - }, - { - desc: "create directory existing duplicate", - steps: []step{ - { - actions: []Action{ - CreateDirectory{Path: "directory"}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: DefaultMode, Path: "directory/.gitkeep"}, - }, - }, - { - actions: []Action{ - CreateDirectory{Path: "directory"}, - }, - error: IndexError{Type: ErrDirectoryExists, Path: "directory"}, - }, - }, - }, - { - desc: "create directory with a files name", - steps: []step{ - { - actions: []Action{ - CreateFile{Path: "file", OID: originalFile.String()}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: DefaultMode, Path: "file", Content: "original"}, - }, - }, - { - actions: []Action{ - CreateDirectory{Path: "file"}, - }, - error: IndexError{Type: ErrFileExists, Path: "file"}, - }, - }, - }, - { - desc: "create file", - steps: []step{ - { - actions: []Action{ - CreateFile{Path: "file", OID: originalFile.String()}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: DefaultMode, Path: "file", Content: "original"}, - }, - }, - }, - }, - { - desc: "create duplicate file", - steps: []step{ - { - actions: []Action{ - CreateFile{Path: "file", OID: originalFile.String()}, - CreateFile{Path: "file", OID: updatedFile.String()}, - }, - error: IndexError{Type: ErrFileExists, Path: "file"}, - }, - }, - }, - { - desc: "create file overwrites directory", - steps: []step{ - { - actions: []Action{ - CreateDirectory{Path: "directory"}, - CreateFile{Path: "directory", OID: originalFile.String()}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: DefaultMode, Path: "directory", Content: "original"}, - }, - }, - }, - }, - { - desc: "update created file", - steps: []step{ - { - actions: []Action{ - CreateFile{Path: "file", OID: originalFile.String()}, - UpdateFile{Path: "file", OID: updatedFile.String()}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: DefaultMode, Path: "file", Content: "updated"}, - }, - }, - }, - }, - { - desc: "update existing file", - steps: []step{ - { - actions: []Action{ - CreateFile{Path: "file", OID: originalFile.String()}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: DefaultMode, Path: "file", Content: "original"}, - }, - }, - { - actions: []Action{ - UpdateFile{Path: "file", OID: updatedFile.String()}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: DefaultMode, Path: "file", Content: "updated"}, - }, - }, - }, - }, - { - desc: "update non-existing file", - steps: []step{ - { - actions: []Action{ - UpdateFile{Path: "non-existing", OID: updatedFile.String()}, - }, - error: IndexError{Type: ErrFileNotFound, Path: "non-existing"}, - }, - }, - }, - { - desc: "move created file", - steps: []step{ - { - actions: []Action{ - CreateFile{Path: "original-file", OID: originalFile.String()}, - MoveFile{Path: "original-file", NewPath: "moved-file", OID: originalFile.String()}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: DefaultMode, Path: "moved-file", Content: "original"}, - }, - }, - }, - }, - { - desc: "moving directory fails", - steps: []step{ - { - actions: []Action{ - CreateDirectory{Path: "directory"}, - MoveFile{Path: "directory", NewPath: "moved-directory"}, - }, - error: IndexError{Type: ErrFileNotFound, Path: "directory"}, - }, - }, - }, - { - desc: "move file inferring content", - steps: []step{ - { - actions: []Action{ - CreateFile{Path: "original-file", OID: originalFile.String()}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: DefaultMode, Path: "original-file", Content: "original"}, - }, - }, - { - actions: []Action{ - MoveFile{Path: "original-file", NewPath: "moved-file"}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: DefaultMode, Path: "moved-file", Content: "original"}, - }, - }, - }, - }, - { - desc: "move file with non-existing source", - steps: []step{ - { - actions: []Action{ - MoveFile{Path: "non-existing", NewPath: "destination-file"}, - }, - error: IndexError{Type: ErrFileNotFound, Path: "non-existing"}, - }, - }, - }, - { - desc: "move file with already existing destination file", - steps: []step{ - { - actions: []Action{ - CreateFile{Path: "source-file", OID: originalFile.String()}, - CreateFile{Path: "already-existing", OID: updatedFile.String()}, - MoveFile{Path: "source-file", NewPath: "already-existing"}, - }, - error: IndexError{Type: ErrFileExists, Path: "already-existing"}, - }, - }, - }, - { - // seems like a bug in the original implementation to allow overwriting a - // directory - desc: "move file with already existing destination directory", - steps: []step{ - { - actions: []Action{ - CreateFile{Path: "file", OID: originalFile.String()}, - CreateDirectory{Path: "already-existing"}, - MoveFile{Path: "file", NewPath: "already-existing"}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: DefaultMode, Path: "already-existing", Content: "original"}, - }, - }, - }, - }, - { - desc: "move file providing content", - steps: []step{ - { - actions: []Action{ - CreateFile{Path: "original-file", OID: originalFile.String()}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: DefaultMode, Path: "original-file", Content: "original"}, - }, - }, - { - actions: []Action{ - MoveFile{Path: "original-file", NewPath: "moved-file", OID: updatedFile.String()}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: DefaultMode, Path: "moved-file", Content: "updated"}, - }, - }, - }, - }, - { - desc: "mark non-existing file executable", - steps: []step{ - { - actions: []Action{ - ChangeFileMode{Path: "non-existing"}, - }, - error: IndexError{Type: ErrFileNotFound, Path: "non-existing"}, - }, - }, - }, - { - desc: "mark executable file executable", - steps: []step{ - { - actions: []Action{ - CreateFile{Path: "file-1", OID: originalFile.String()}, - ChangeFileMode{Path: "file-1", ExecutableMode: true}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: ExecutableMode, Path: "file-1", Content: "original"}, - }, - }, - { - actions: []Action{ - ChangeFileMode{Path: "file-1", ExecutableMode: true}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: ExecutableMode, Path: "file-1", Content: "original"}, - }, - }, - }, - }, - { - desc: "mark created file executable", - steps: []step{ - { - actions: []Action{ - CreateFile{Path: "file-1", OID: originalFile.String()}, - ChangeFileMode{Path: "file-1", ExecutableMode: true}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: ExecutableMode, Path: "file-1", Content: "original"}, - }, - }, - }, - }, - { - desc: "mark existing file executable", - steps: []step{ - { - actions: []Action{ - CreateFile{Path: "file-1", OID: originalFile.String()}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: DefaultMode, Path: "file-1", Content: "original"}, - }, - }, - { - actions: []Action{ - ChangeFileMode{Path: "file-1", ExecutableMode: true}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: ExecutableMode, Path: "file-1", Content: "original"}, - }, - }, - }, - }, - { - desc: "move non-existing file", - steps: []step{ - { - actions: []Action{ - MoveFile{Path: "non-existing", NewPath: "destination"}, - }, - error: IndexError{Type: ErrFileNotFound, Path: "non-existing"}, - }, - }, - }, - { - desc: "move doesn't overwrite a file", - steps: []step{ - { - actions: []Action{ - CreateFile{Path: "file-1", OID: originalFile.String()}, - CreateFile{Path: "file-2", OID: updatedFile.String()}, - MoveFile{Path: "file-1", NewPath: "file-2"}, - }, - error: IndexError{Type: ErrFileExists, Path: "file-2"}, - }, - }, - }, - { - desc: "delete non-existing file", - steps: []step{ - { - actions: []Action{ - DeleteFile{Path: "non-existing"}, - }, - error: IndexError{Type: ErrFileNotFound, Path: "non-existing"}, - }, - }, - }, - { - desc: "delete created file", - steps: []step{ - { - actions: []Action{ - CreateFile{Path: "file-1", OID: originalFile.String()}, - DeleteFile{Path: "file-1"}, - }, - }, - }, - }, - { - desc: "delete existing file", - steps: []step{ - { - actions: []Action{ - CreateFile{Path: "file-1", OID: originalFile.String()}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: DefaultMode, Path: "file-1", Content: "original"}, - }, - }, - { - actions: []Action{ - DeleteFile{Path: "file-1"}, - }, - }, - }, - }, - } { - t.Run(tc.desc, func(t *testing.T) { - var parentCommit git.ObjectID - var parentIds []string - for i, step := range tc.steps { - message := fmt.Sprintf("commit %d", i+1) - commitID, err := executor.Commit(ctx, repo, CommitCommand{ - Repository: repoPath, - Author: author, - Committer: committer, - Message: message, - Parent: parentCommit.String(), - Actions: step.actions, - }) - - if step.error != nil { - require.True(t, errors.Is(err, step.error), "expected: %q, actual: %q", step.error, err) - continue - } else { - require.NoError(t, err) - } - - commit, err := repo.ReadCommit(ctx, commitID.Revision()) - require.NoError(t, err) - - require.Equal(t, parentIds, commit.ParentIds) - require.Equal(t, gittest.DefaultCommitAuthor, commit.Author) - require.Equal(t, gittest.DefaultCommitAuthor, commit.Committer) - require.Equal(t, []byte(message), commit.Body) - - gittest.RequireTree(t, cfg, repoPath, commitID.String(), step.treeEntries) - parentCommit = commitID - parentIds = []string{string(commitID)} - } - }) - } - - for _, tc := range []struct { - desc string - steps []step - signingKeys []signingKey - }{ - { - desc: "update created file, sign commit and verify signature using SSH signing key", - steps: []step{ - { - actions: []Action{ - CreateFile{Path: "file", OID: originalFile.String()}, - UpdateFile{Path: "file", OID: updatedFile.String()}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: DefaultMode, Path: "file", Content: "updated"}, - }, - testCommit: func(tb testing.TB, commitID git.ObjectID, key signingKey) { - sshsig, dataWithoutSSHSig := extractSignature(t, ctx, repo, commitID) - - signingKey, err := signature.ParseSigningKey(key.path) - require.NoError(tb, err) - require.NoError(tb, signingKey.Verify([]byte(sshsig), []byte(dataWithoutSSHSig))) - - // Verify that the generated signature equals the one generated by Git for the identical content. - if key.sigPath != "" { - expectedSig, err := os.ReadFile(key.sigPath) - require.NoError(tb, err) - require.Equal(tb, string(expectedSig), sshsig) - } - }, - }, - }, - // Keys that are used to sign commits using SSH - signingKeys: []signingKey{ - { - path: "testdata/signing_ssh_key_ed25519", - sigPath: "testdata/signing_ssh_key_ed25519.sig", - }, { - path: "testdata/signing_ssh_key_rsa", - sigPath: "testdata/signing_ssh_key_rsa.sig", - }, { - path: "testdata/signing_ssh_key_ecdsa", - }, - }, - }, - { - desc: "update created file, sign commit and verify signature using GPG signing key", - steps: []step{ - { - actions: []Action{ - CreateFile{Path: "file", OID: originalFile.String()}, - UpdateFile{Path: "file", OID: updatedFile.String()}, - }, - treeEntries: []gittest.TreeEntry{ - {Mode: DefaultMode, Path: "file", Content: "updated"}, - }, - testCommit: func(tb testing.TB, commitID git.ObjectID, key signingKey) { - gpgsig, dataWithoutGpgSig := extractSignature(t, ctx, repo, commitID) - - signingKey, err := signature.ParseSigningKey(key.path) - require.NoError(tb, err) - require.NoError(tb, signingKey.Verify([]byte(gpgsig), []byte(dataWithoutGpgSig))) - }, - }, - }, - // Keys that are used to sign commits using GPG - // Can be generated by the following command: gpg --gen-key - signingKeys: []signingKey{ - { - path: "testdata/signing_gpg_key", - }, - }, - }, - } { - for _, signingKey := range tc.signingKeys { - t.Run(tc.desc+" with "+signingKey.path, func(t *testing.T) { - executor.signingKey = signingKey.path - - for i, step := range tc.steps { - message := fmt.Sprintf("commit %d", i+1) - commitID, err := executor.Commit(ctx, repo, CommitCommand{ - Repository: repoPath, - Author: author, - Committer: committer, - Message: message, - Actions: step.actions, - }) - require.NoError(t, err) - - commit, err := repo.ReadCommit(ctx, commitID.Revision()) - require.NoError(t, err) - - require.Equal(t, gittest.DefaultCommitAuthor, commit.Author) - require.Equal(t, gittest.DefaultCommitAuthor, commit.Committer) - require.Equal(t, []byte(message), commit.Body) - - step.testCommit(t, commitID, signingKey) - - gittest.RequireTree(t, cfg, repoPath, commitID.String(), step.treeEntries) - } - }) - } - } -} - -func extractSignature(tb testing.TB, ctx context.Context, repo *localrepo.Repo, oid git.ObjectID) (string, string) { - data, err := repo.ReadObject(ctx, oid) - require.NoError(tb, err) - - return signature.ExtractSignature(tb, ctx, data) -} - -func defaultCommitAuthorSignature() Signature { - return NewSignature( - gittest.DefaultCommitterName, - gittest.DefaultCommitterMail, - gittest.DefaultCommitTime, - ) -} |