mirror of https://github.com/harness/drone.git
Fix `MOVE` action for Commit API (#1037)
parent
9d8bf25692
commit
40e5b84ba1
|
@ -15,11 +15,9 @@
|
|||
package git
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -35,7 +33,6 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
filePrefix = "file://"
|
||||
defaultFilePermission = "100644" // 0o644 default file permission
|
||||
)
|
||||
|
||||
|
@ -318,8 +315,7 @@ func (s *Service) prepareTreeEmptyRepo(
|
|||
return errors.InvalidArgument("invalid path")
|
||||
}
|
||||
|
||||
reader := bytes.NewReader(action.Payload)
|
||||
if err := createFile(ctx, shared, nil, filePath, defaultFilePermission, reader); err != nil {
|
||||
if err := createFile(ctx, shared, nil, filePath, defaultFilePermission, action.Payload); err != nil {
|
||||
return errors.Internal(err, "failed to create file '%s'", action.Path)
|
||||
}
|
||||
}
|
||||
|
@ -389,15 +385,13 @@ func (s *Service) processAction(
|
|||
return errors.InvalidArgument("path cannot be empty")
|
||||
}
|
||||
|
||||
reader := bytes.NewReader(action.Payload)
|
||||
|
||||
switch action.Action {
|
||||
case CreateAction:
|
||||
err = createFile(ctx, shared, commit, filePath, defaultFilePermission, reader)
|
||||
err = createFile(ctx, shared, commit, filePath, defaultFilePermission, action.Payload)
|
||||
case UpdateAction:
|
||||
err = updateFile(ctx, shared, commit, filePath, action.SHA, defaultFilePermission, reader)
|
||||
err = updateFile(ctx, shared, commit, filePath, action.SHA, defaultFilePermission, action.Payload)
|
||||
case MoveAction:
|
||||
err = moveFile(ctx, shared, commit, filePath, defaultFilePermission, reader)
|
||||
err = moveFile(ctx, shared, commit, filePath, action.SHA, defaultFilePermission, action.Payload)
|
||||
case DeleteAction:
|
||||
err = deleteFile(ctx, shared, filePath)
|
||||
}
|
||||
|
@ -406,7 +400,7 @@ func (s *Service) processAction(
|
|||
}
|
||||
|
||||
func createFile(ctx context.Context, repo SharedRepo, commit *git.Commit,
|
||||
filePath, mode string, reader io.Reader) error {
|
||||
filePath, mode string, payload []byte) error {
|
||||
// only check path availability if a source commit is available (empty repo won't have such a commit)
|
||||
if commit != nil {
|
||||
if err := checkPathAvailability(commit, filePath, true); err != nil {
|
||||
|
@ -414,7 +408,7 @@ func createFile(ctx context.Context, repo SharedRepo, commit *git.Commit,
|
|||
}
|
||||
}
|
||||
|
||||
hash, err := repo.WriteGitObject(ctx, reader)
|
||||
hash, err := repo.WriteGitObject(ctx, bytes.NewReader(payload))
|
||||
if err != nil {
|
||||
return fmt.Errorf("createFile: error hashing object: %w", err)
|
||||
}
|
||||
|
@ -427,7 +421,7 @@ func createFile(ctx context.Context, repo SharedRepo, commit *git.Commit,
|
|||
}
|
||||
|
||||
func updateFile(ctx context.Context, repo SharedRepo, commit *git.Commit, filePath, sha,
|
||||
mode string, reader io.Reader) error {
|
||||
mode string, payload []byte) error {
|
||||
// get file mode from existing file (default unless executable)
|
||||
entry, err := getFileEntry(commit, sha, filePath)
|
||||
if err != nil {
|
||||
|
@ -437,7 +431,7 @@ func updateFile(ctx context.Context, repo SharedRepo, commit *git.Commit, filePa
|
|||
mode = "100755"
|
||||
}
|
||||
|
||||
hash, err := repo.WriteGitObject(ctx, reader)
|
||||
hash, err := repo.WriteGitObject(ctx, bytes.NewReader(payload))
|
||||
if err != nil {
|
||||
return fmt.Errorf("updateFile: error hashing object: %w", err)
|
||||
}
|
||||
|
@ -449,38 +443,42 @@ func updateFile(ctx context.Context, repo SharedRepo, commit *git.Commit, filePa
|
|||
}
|
||||
|
||||
func moveFile(ctx context.Context, repo SharedRepo, commit *git.Commit,
|
||||
filePath, mode string, reader io.Reader) error {
|
||||
buffer := &bytes.Buffer{}
|
||||
newPath, err := parsePayload(reader, buffer)
|
||||
filePath, sha, mode string, payload []byte) error {
|
||||
newPath, newContent, err := parseMovePayload(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if buffer.Len() == 0 && newPath != "" {
|
||||
err = repo.ShowFile(ctx, filePath, commit.ID.String(), buffer)
|
||||
// ensure file exists and matches SHA
|
||||
entry, err := getFileEntry(commit, sha, filePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("moveFile: failed lookup for path '%s': %w", newPath, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// ensure new path is available
|
||||
if err = checkPathAvailability(commit, newPath, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
filesInIndex, err := repo.LsFiles(ctx, filePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("moveFile: listing files error: %w", err)
|
||||
}
|
||||
if !slices.Contains(filesInIndex, filePath) {
|
||||
return errors.NotFound("path %s not found", filePath)
|
||||
}
|
||||
|
||||
hash, err := repo.WriteGitObject(ctx, buffer)
|
||||
var fileHash string
|
||||
var fileMode string
|
||||
if newContent != nil {
|
||||
hash, err := repo.WriteGitObject(ctx, bytes.NewReader(newContent))
|
||||
if err != nil {
|
||||
return fmt.Errorf("moveFile: error hashing object: %w", err)
|
||||
}
|
||||
|
||||
if err = repo.AddObjectToIndex(ctx, mode, hash, newPath); err != nil {
|
||||
fileHash = hash
|
||||
fileMode = mode
|
||||
if entry.IsExecutable() {
|
||||
fileMode = "100755"
|
||||
}
|
||||
} else {
|
||||
fileHash = entry.ID.String()
|
||||
fileMode = entry.Mode().String()
|
||||
}
|
||||
|
||||
if err = repo.AddObjectToIndex(ctx, fileMode, fileHash, newPath); err != nil {
|
||||
return fmt.Errorf("moveFile: add object error: %w", err)
|
||||
}
|
||||
|
||||
|
@ -519,7 +517,7 @@ func getFileEntry(
|
|||
}
|
||||
|
||||
// If a SHA was given and the SHA given doesn't match the SHA of the fromTreePath, throw error
|
||||
if sha == "" || sha != entry.ID.String() {
|
||||
if sha != "" && sha != entry.ID.String() {
|
||||
return nil, errors.InvalidArgument("sha does not match for path %s [given: %s, expected: %s]",
|
||||
path, sha, entry.ID.String())
|
||||
}
|
||||
|
@ -564,29 +562,22 @@ func checkPathAvailability(commit *git.Commit, filePath string, isNewFile bool)
|
|||
return nil
|
||||
}
|
||||
|
||||
func parsePayload(payload io.Reader, content io.Writer) (string, error) {
|
||||
newPath := ""
|
||||
reader := bufio.NewReader(payload)
|
||||
// check for filePrefix
|
||||
prefixBytes := make([]byte, len(filePrefix))
|
||||
if _, err := reader.Read(prefixBytes); err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
return "", nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
// check if payload starts with filePrefix constant
|
||||
if bytes.Equal(prefixBytes, []byte(filePrefix)) {
|
||||
filename, _ := reader.ReadString('\n') // no err handling because next statement will check filename
|
||||
newPath = files.CleanUploadFileName(filename)
|
||||
if newPath == "" {
|
||||
return "", types.ErrInvalidPath
|
||||
}
|
||||
func parseMovePayload(payload []byte) (string, []byte, error) {
|
||||
var newContent []byte
|
||||
var newPath string
|
||||
filePathEnd := bytes.IndexByte(payload, 0)
|
||||
if filePathEnd < 0 {
|
||||
newPath = string(payload)
|
||||
newContent = nil
|
||||
} else {
|
||||
if _, err := content.Write(prefixBytes); err != nil {
|
||||
return "", err
|
||||
newPath = string(payload[:filePathEnd])
|
||||
newContent = payload[filePathEnd+1:]
|
||||
}
|
||||
|
||||
newPath = files.CleanUploadFileName(newPath)
|
||||
if newPath == "" {
|
||||
return "", nil, types.ErrInvalidPath
|
||||
}
|
||||
_, err := io.Copy(content, reader)
|
||||
return newPath, err
|
||||
|
||||
return newPath, newContent, nil
|
||||
}
|
||||
|
|
|
@ -107,7 +107,7 @@ export function useCommitModal({
|
|||
{
|
||||
action: commitAction,
|
||||
path: oldResourcePath || resourcePath,
|
||||
payload: `${oldResourcePath ? `file://${resourcePath}\n` : ''}${payload}`,
|
||||
payload: `${oldResourcePath ? `${resourcePath}\0` : ''}${payload}`,
|
||||
sha
|
||||
// encoding: 'base64',
|
||||
// payload: window.btoa(payload || '')
|
||||
|
@ -153,7 +153,7 @@ export function useCommitModal({
|
|||
{
|
||||
action: commitAction,
|
||||
path: oldResourcePath || resourcePath,
|
||||
payload: `${oldResourcePath ? `file://${resourcePath}\n` : ''}${payload}`,
|
||||
payload: `${oldResourcePath ? `${resourcePath}\0` : ''}${payload}`,
|
||||
sha
|
||||
}
|
||||
],
|
||||
|
|
Loading…
Reference in New Issue