mirror of https://github.com/harness/drone.git
157 lines
4.5 KiB
Go
157 lines
4.5 KiB
Go
// Copyright 2022 Harness Inc. All rights reserved.
|
|
// Use of this source code is governed by the Polyform Free Trial License
|
|
// that can be found in the LICENSE.md file for this repository.
|
|
|
|
package gitea
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/harness/gitness/gitrpc/internal/types"
|
|
|
|
gitea "code.gitea.io/gitea/modules/git"
|
|
)
|
|
|
|
func cleanTreePath(treePath string) string {
|
|
return strings.Trim(path.Clean("/"+treePath), "/")
|
|
}
|
|
|
|
// GetTreeNode returns the tree node at the given path as found for the provided reference.
|
|
// Note: ref can be Branch / Tag / CommitSHA.
|
|
func (g Adapter) GetTreeNode(ctx context.Context, repoPath string,
|
|
ref string, treePath string) (*types.TreeNode, error) {
|
|
treePath = cleanTreePath(treePath)
|
|
|
|
giteaRepo, err := gitea.OpenRepository(ctx, repoPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer giteaRepo.Close()
|
|
|
|
// Get the giteaCommit object for the ref
|
|
giteaCommit, err := giteaRepo.GetCommit(ref)
|
|
if err != nil {
|
|
return nil, processGiteaErrorf(err, "error getting commit for ref '%s'", ref)
|
|
}
|
|
|
|
// TODO: handle ErrNotExist :)
|
|
giteaTreeEntry, err := giteaCommit.GetTreeEntryByPath(treePath)
|
|
if err != nil {
|
|
return nil, processGiteaErrorf(err, "failed to get tree entry for commit '%s' at path '%s'",
|
|
giteaCommit.ID.String(), treePath)
|
|
}
|
|
|
|
nodeType, mode, err := mapGiteaNodeToTreeNodeModeAndType(giteaTreeEntry.Mode())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &types.TreeNode{
|
|
Mode: mode,
|
|
NodeType: nodeType,
|
|
Sha: giteaTreeEntry.ID.String(),
|
|
Name: giteaTreeEntry.Name(),
|
|
Path: treePath,
|
|
}, nil
|
|
}
|
|
|
|
// ListTreeNodes lists the child nodes of a tree reachable from ref via the specified path
|
|
// and includes the latest commit for all nodes if requested.
|
|
// IMPORTANT: recursive and includeLatestCommit can't be used together.
|
|
// Note: ref can be Branch / Tag / CommitSHA.
|
|
//
|
|
//nolint:gocognit // refactor if needed
|
|
func (g Adapter) ListTreeNodes(ctx context.Context, repoPath string,
|
|
ref string, treePath string, recursive bool, includeLatestCommit bool) ([]types.TreeNodeWithCommit, error) {
|
|
if recursive && includeLatestCommit {
|
|
// To avoid potential performance catastrophies, block recursive with includeLatestCommit
|
|
// TODO: this should return bad error to caller if needed?
|
|
// TODO: should this be refactored in two methods?
|
|
return nil, fmt.Errorf("latest commit with recursive query is not supported")
|
|
}
|
|
|
|
treePath = cleanTreePath(treePath)
|
|
|
|
giteaRepo, err := gitea.OpenRepository(ctx, repoPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer giteaRepo.Close()
|
|
|
|
// Get the giteaCommit object for the ref
|
|
giteaCommit, err := giteaRepo.GetCommit(ref)
|
|
if err != nil {
|
|
return nil, processGiteaErrorf(err, "error getting commit for ref '%s'", ref)
|
|
}
|
|
|
|
// Get the giteaTree object for the ref
|
|
giteaTree, err := giteaCommit.SubTree(treePath)
|
|
if err != nil {
|
|
return nil, processGiteaErrorf(err, "error getting tree for '%s'", treePath)
|
|
}
|
|
|
|
var giteaEntries gitea.Entries
|
|
if recursive {
|
|
giteaEntries, err = giteaTree.ListEntriesRecursive()
|
|
} else {
|
|
giteaEntries, err = giteaTree.ListEntries()
|
|
}
|
|
if err != nil {
|
|
return nil, processGiteaErrorf(err, "failed to list entries for tree '%s'", treePath)
|
|
}
|
|
|
|
var latestCommits []gitea.CommitInfo
|
|
if includeLatestCommit {
|
|
// TODO: can be speed up with latestCommitCache (currently nil)
|
|
latestCommits, _, err = giteaEntries.GetCommitsInfo(ctx, giteaCommit, treePath, nil)
|
|
if err != nil {
|
|
return nil, processGiteaErrorf(err, "failed to get latest commits for entries")
|
|
}
|
|
|
|
if len(latestCommits) != len(giteaEntries) {
|
|
return nil, fmt.Errorf("latest commit info doesn't match tree node info - count differs")
|
|
}
|
|
}
|
|
|
|
nodes := make([]types.TreeNodeWithCommit, len(giteaEntries))
|
|
for i := range giteaEntries {
|
|
giteaEntry := giteaEntries[i]
|
|
|
|
var nodeType types.TreeNodeType
|
|
var mode types.TreeNodeMode
|
|
nodeType, mode, err = mapGiteaNodeToTreeNodeModeAndType(giteaEntry.Mode())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// giteaNode.Name() returns the path of the node relative to the tree.
|
|
relPath := giteaEntry.Name()
|
|
name := filepath.Base(relPath)
|
|
|
|
var commit *types.Commit
|
|
if includeLatestCommit {
|
|
commit, err = mapGiteaCommit(latestCommits[i].Commit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
nodes[i] = types.TreeNodeWithCommit{
|
|
TreeNode: types.TreeNode{
|
|
NodeType: nodeType,
|
|
Mode: mode,
|
|
Sha: giteaEntry.ID.String(),
|
|
Name: name,
|
|
Path: filepath.Join(treePath, relPath),
|
|
},
|
|
Commit: commit,
|
|
}
|
|
}
|
|
|
|
return nodes, nil
|
|
}
|