mirror of
https://github.com/harness/drone.git
synced 2025-05-07 20:34:04 +08:00
[API] Add Create + Delete Branch API (+ Basic GIT Error Propagation) (#70)
This change adds the following: - create / delete branch - basic error propagation from git to user (notfound, conflict, invalidinput) - create repo root folder in server instead of service constructor
This commit is contained in:
parent
81040d0453
commit
c55c53deab
@ -39,7 +39,7 @@ func (c *Client) GetBlob(ctx context.Context, params *GetBlobParams) (*GetBlobOu
|
|||||||
SizeLimit: params.SizeLimit,
|
SizeLimit: params.SizeLimit,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, processRPCErrorf(err, "failed to get blob from server")
|
||||||
}
|
}
|
||||||
|
|
||||||
blob := resp.GetBlob()
|
blob := resp.GetBlob()
|
||||||
|
@ -22,6 +22,26 @@ const (
|
|||||||
BranchSortOptionDate
|
BranchSortOptionDate
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type CreateBranchParams struct {
|
||||||
|
// RepoUID is the uid of the git repository
|
||||||
|
RepoUID string
|
||||||
|
// BranchName is the name of the branch
|
||||||
|
BranchName string
|
||||||
|
// Target is a git reference (branch / tag / commit SHA)
|
||||||
|
Target string
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateBranchOutput struct {
|
||||||
|
Branch Branch
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeleteBranchParams struct {
|
||||||
|
// RepoUID is the uid of the git repository
|
||||||
|
RepoUID string
|
||||||
|
// Name is the name of the branch
|
||||||
|
BranchName string
|
||||||
|
}
|
||||||
|
|
||||||
type ListBranchesParams struct {
|
type ListBranchesParams struct {
|
||||||
// RepoUID is the uid of the git repository
|
// RepoUID is the uid of the git repository
|
||||||
RepoUID string
|
RepoUID string
|
||||||
@ -43,12 +63,54 @@ type Branch struct {
|
|||||||
Commit *Commit
|
Commit *Commit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateBranch(ctx context.Context, params *CreateBranchParams) (*CreateBranchOutput, error) {
|
||||||
|
if params == nil {
|
||||||
|
return nil, ErrNoParamsProvided
|
||||||
|
}
|
||||||
|
resp, err := c.refService.CreateBranch(ctx, &rpc.CreateBranchRequest{
|
||||||
|
RepoUid: params.RepoUID,
|
||||||
|
Target: params.Target,
|
||||||
|
BranchName: params.BranchName,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, processRPCErrorf(err, "failed to create branch on server")
|
||||||
|
}
|
||||||
|
|
||||||
|
var branch *Branch
|
||||||
|
branch, err = mapRPCBranch(resp.GetBranch())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to map rpc branch: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &CreateBranchOutput{
|
||||||
|
Branch: *branch,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteBranch(ctx context.Context, params *DeleteBranchParams) error {
|
||||||
|
if params == nil {
|
||||||
|
return ErrNoParamsProvided
|
||||||
|
}
|
||||||
|
_, err := c.refService.DeleteBranch(ctx, &rpc.DeleteBranchRequest{
|
||||||
|
RepoUid: params.RepoUID,
|
||||||
|
BranchName: params.BranchName,
|
||||||
|
// TODO: what are scenarios where we wouldn't want to force delete?
|
||||||
|
// Branch protection is a different story, and build on top application layer.
|
||||||
|
Force: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return processRPCErrorf(err, "failed to delete branch on server")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) ListBranches(ctx context.Context, params *ListBranchesParams) (*ListBranchesOutput, error) {
|
func (c *Client) ListBranches(ctx context.Context, params *ListBranchesParams) (*ListBranchesOutput, error) {
|
||||||
if params == nil {
|
if params == nil {
|
||||||
return nil, ErrNoParamsProvided
|
return nil, ErrNoParamsProvided
|
||||||
}
|
}
|
||||||
|
|
||||||
stream, err := c.repoService.ListBranches(ctx, &rpc.ListBranchesRequest{
|
stream, err := c.refService.ListBranches(ctx, &rpc.ListBranchesRequest{
|
||||||
RepoUid: params.RepoUID,
|
RepoUid: params.RepoUID,
|
||||||
IncludeCommit: params.IncludeCommit,
|
IncludeCommit: params.IncludeCommit,
|
||||||
Query: params.Query,
|
Query: params.Query,
|
||||||
@ -73,7 +135,7 @@ func (c *Client) ListBranches(ctx context.Context, params *ListBranchesParams) (
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("received unexpected error from rpc: %w", err)
|
return nil, processRPCErrorf(err, "received unexpected error from rpc")
|
||||||
}
|
}
|
||||||
if next.GetBranch() == nil {
|
if next.GetBranch() == nil {
|
||||||
return nil, fmt.Errorf("expected branch message")
|
return nil, fmt.Errorf("expected branch message")
|
||||||
|
@ -18,6 +18,7 @@ type Config struct {
|
|||||||
type Client struct {
|
type Client struct {
|
||||||
conn *grpc.ClientConn
|
conn *grpc.ClientConn
|
||||||
repoService rpc.RepositoryServiceClient
|
repoService rpc.RepositoryServiceClient
|
||||||
|
refService rpc.ReferenceServiceClient
|
||||||
httpService rpc.SmartHTTPServiceClient
|
httpService rpc.SmartHTTPServiceClient
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,6 +31,7 @@ func New(remoteAddr string) (*Client, error) {
|
|||||||
return &Client{
|
return &Client{
|
||||||
conn: conn,
|
conn: conn,
|
||||||
repoService: rpc.NewRepositoryServiceClient(conn),
|
repoService: rpc.NewRepositoryServiceClient(conn),
|
||||||
|
refService: rpc.NewReferenceServiceClient(conn),
|
||||||
httpService: rpc.NewSmartHTTPServiceClient(conn),
|
httpService: rpc.NewSmartHTTPServiceClient(conn),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ func (c *Client) ListCommits(ctx context.Context, params *ListCommitsParams) (*L
|
|||||||
// get header first
|
// get header first
|
||||||
header, err := stream.Recv()
|
header, err := stream.Recv()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error occured while receiving header: %w", err)
|
return nil, processRPCErrorf(err, "error occured while receiving header")
|
||||||
}
|
}
|
||||||
if header.GetHeader() == nil {
|
if header.GetHeader() == nil {
|
||||||
return nil, fmt.Errorf("header missing")
|
return nil, fmt.Errorf("header missing")
|
||||||
@ -84,7 +84,7 @@ func (c *Client) ListCommits(ctx context.Context, params *ListCommitsParams) (*L
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("received unexpected error from rpc: %w", err)
|
return nil, processRPCErrorf(err, "received unexpected error from server")
|
||||||
}
|
}
|
||||||
if next.GetCommit() == nil {
|
if next.GetCommit() == nil {
|
||||||
return nil, fmt.Errorf("expected commit message")
|
return nil, fmt.Errorf("expected commit message")
|
||||||
|
@ -7,3 +7,6 @@ package gitrpc
|
|||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
var ErrNoParamsProvided = errors.New("no params provided")
|
var ErrNoParamsProvided = errors.New("no params provided")
|
||||||
|
var ErrAlreadyExists = errors.New("already exists")
|
||||||
|
var ErrInvalidArgument = errors.New("invalid argument")
|
||||||
|
var ErrNotFound = errors.New("not found")
|
@ -16,6 +16,8 @@ type Interface interface {
|
|||||||
GetSubmodule(ctx context.Context, params *GetSubmoduleParams) (*GetSubmoduleOutput, error)
|
GetSubmodule(ctx context.Context, params *GetSubmoduleParams) (*GetSubmoduleOutput, error)
|
||||||
GetBlob(ctx context.Context, params *GetBlobParams) (*GetBlobOutput, error)
|
GetBlob(ctx context.Context, params *GetBlobParams) (*GetBlobOutput, error)
|
||||||
ListCommits(ctx context.Context, params *ListCommitsParams) (*ListCommitsOutput, error)
|
ListCommits(ctx context.Context, params *ListCommitsParams) (*ListCommitsOutput, error)
|
||||||
|
CreateBranch(ctx context.Context, params *CreateBranchParams) (*CreateBranchOutput, error)
|
||||||
|
DeleteBranch(ctx context.Context, params *DeleteBranchParams) error
|
||||||
ListBranches(ctx context.Context, params *ListBranchesParams) (*ListBranchesOutput, error)
|
ListBranches(ctx context.Context, params *ListBranchesParams) (*ListBranchesOutput, error)
|
||||||
ListCommitTags(ctx context.Context, params *ListCommitTagsParams) (*ListCommitTagsOutput, error)
|
ListCommitTags(ctx context.Context, params *ListCommitTagsParams) (*ListCommitTagsOutput, error)
|
||||||
|
|
||||||
|
@ -24,12 +24,12 @@ func (g Adapter) GetBlob(ctx context.Context, repoPath string, sha string, sizeL
|
|||||||
|
|
||||||
giteaBlob, err := giteaRepo.GetBlob(sha)
|
giteaBlob, err := giteaRepo.GetBlob(sha)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error getting blob '%s': %w", sha, err)
|
return nil, processGiteaErrorf(err, "error getting blob '%s'", sha)
|
||||||
}
|
}
|
||||||
|
|
||||||
reader, err := giteaBlob.DataAsync()
|
reader, err := giteaBlob.DataAsync()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error opening data for blob '%s': %w", sha, err)
|
return nil, processGiteaErrorf(err, "error opening data for blob '%s'", sha)
|
||||||
}
|
}
|
||||||
|
|
||||||
returnSize := giteaBlob.Size()
|
returnSize := giteaBlob.Size()
|
||||||
|
75
gitrpc/internal/gitea/branch.go
Normal file
75
gitrpc/internal/gitea/branch.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
// 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"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
gitea "code.gitea.io/gitea/modules/git"
|
||||||
|
"github.com/harness/gitness/gitrpc/internal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateBranch creates a new branch.
|
||||||
|
// Note: target is the commit (or points to the commit) the branch will be pointing to.
|
||||||
|
func (g Adapter) CreateBranch(ctx context.Context, repoPath string,
|
||||||
|
branchName string, target string) (*types.Branch, error) {
|
||||||
|
giteaRepo, err := gitea.OpenRepository(ctx, repoPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer giteaRepo.Close()
|
||||||
|
|
||||||
|
// Get the commit object for the ref
|
||||||
|
giteaCommit, err := giteaRepo.GetCommit(target)
|
||||||
|
if err != nil {
|
||||||
|
return nil, processGiteaErrorf(err, "error getting commit for ref '%s'", target)
|
||||||
|
}
|
||||||
|
|
||||||
|
// In case of target being an annotated tag, gitea is overwriting the commit message with the tag message.
|
||||||
|
// Reload the commit explicitly in case it's a tag (independent of whether it's annotated or not to simplify code)
|
||||||
|
// NOTE: we also allow passing refs/tags/tagName or tags/tagName, which is not covered by IsTagExist.
|
||||||
|
// Worst case we have a false positive and reload the same commit, we don't want false negatives though!
|
||||||
|
if strings.HasPrefix(target, gitea.TagPrefix) || strings.HasPrefix(target, "tags") || giteaRepo.IsTagExist(target) {
|
||||||
|
giteaCommit, err = giteaRepo.GetCommit(giteaCommit.ID.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, processGiteaErrorf(err, "error getting commit for annotated tag '%s' (commitId '%s')",
|
||||||
|
target, giteaCommit.ID.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = giteaRepo.CreateBranch(branchName, giteaCommit.ID.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, processGiteaErrorf(err, "failed to create branch '%s'", branchName)
|
||||||
|
}
|
||||||
|
|
||||||
|
commit, err := mapGiteaCommit(giteaCommit)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to map gitea commit: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.Branch{
|
||||||
|
Name: branchName,
|
||||||
|
SHA: giteaCommit.ID.String(),
|
||||||
|
Commit: commit,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteBranch deletes an existing branch.
|
||||||
|
func (g Adapter) DeleteBranch(ctx context.Context, repoPath string, branchName string, force bool) error {
|
||||||
|
giteaRepo, err := gitea.OpenRepository(ctx, repoPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer giteaRepo.Close()
|
||||||
|
|
||||||
|
err = giteaRepo.DeleteBranch(branchName, gitea.DeleteBranchOptions{Force: force})
|
||||||
|
if err != nil {
|
||||||
|
return processGiteaErrorf(err, "failed to delete branch '%s'", branchName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -31,7 +31,7 @@ func (g Adapter) GetLatestCommit(ctx context.Context, repoPath string,
|
|||||||
|
|
||||||
giteaCommit, err := giteaGetCommitByPath(giteaRepo, ref, treePath)
|
giteaCommit, err := giteaGetCommitByPath(giteaRepo, ref, treePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error getting latest commit for '%s': %w", treePath, err)
|
return nil, processGiteaErrorf(err, "error getting latest commit for '%s'", treePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapGiteaCommit(giteaCommit)
|
return mapGiteaCommit(giteaCommit)
|
||||||
@ -47,7 +47,7 @@ func giteaGetCommitByPath(giteaRepo *gitea.Repository, ref string, treePath stri
|
|||||||
stdout, _, runErr := gitea.NewCommand(giteaRepo.Ctx, "log", ref, "-1", giteaPrettyLogFormat, "--", treePath).
|
stdout, _, runErr := gitea.NewCommand(giteaRepo.Ctx, "log", ref, "-1", giteaPrettyLogFormat, "--", treePath).
|
||||||
RunStdBytes(&gitea.RunOpts{Dir: giteaRepo.Path})
|
RunStdBytes(&gitea.RunOpts{Dir: giteaRepo.Path})
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
return nil, runErr
|
return nil, fmt.Errorf("failed to trigger log command: %w", runErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
giteaCommits, err := giteaParsePrettyFormatLogToList(giteaRepo, stdout)
|
giteaCommits, err := giteaParsePrettyFormatLogToList(giteaRepo, stdout)
|
||||||
@ -70,7 +70,7 @@ func giteaParsePrettyFormatLogToList(giteaRepo *gitea.Repository, logs []byte) (
|
|||||||
for _, commitID := range parts {
|
for _, commitID := range parts {
|
||||||
commit, err := giteaRepo.GetCommit(string(commitID))
|
commit, err := giteaRepo.GetCommit(string(commitID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("failed to get commit '%s': %w", string(commitID), err)
|
||||||
}
|
}
|
||||||
giteaCommits = append(giteaCommits, commit)
|
giteaCommits = append(giteaCommits, commit)
|
||||||
}
|
}
|
||||||
@ -91,17 +91,17 @@ func (g Adapter) ListCommits(ctx context.Context, repoPath string,
|
|||||||
// Get the giteaTopCommit object for the ref
|
// Get the giteaTopCommit object for the ref
|
||||||
giteaTopCommit, err := giteaRepo.GetCommit(ref)
|
giteaTopCommit, err := giteaRepo.GetCommit(ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, fmt.Errorf("error getting commit for ref '%s': %w", ref, err)
|
return nil, 0, processGiteaErrorf(err, "error getting commit top commit for ref '%s'", ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
giteaCommits, err := giteaTopCommit.CommitsByRange(page, pageSize)
|
giteaCommits, err := giteaTopCommit.CommitsByRange(page, pageSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, fmt.Errorf("error getting commits: %w", err)
|
return nil, 0, processGiteaErrorf(err, "error getting commits")
|
||||||
}
|
}
|
||||||
|
|
||||||
totalCount, err := giteaTopCommit.CommitsCount()
|
totalCount, err := giteaTopCommit.CommitsCount()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, fmt.Errorf("error getting total commit count: %w", err)
|
return nil, 0, processGiteaErrorf(err, "error getting total commit count")
|
||||||
}
|
}
|
||||||
|
|
||||||
commits := make([]types.Commit, len(giteaCommits))
|
commits := make([]types.Commit, len(giteaCommits))
|
||||||
@ -129,7 +129,7 @@ func (g Adapter) GetCommit(ctx context.Context, repoPath string, ref string) (*t
|
|||||||
|
|
||||||
commit, err := giteaRepo.GetCommit(ref)
|
commit, err := giteaRepo.GetCommit(ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, processGiteaErrorf(err, "error getting commit for ref '%s'", ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapGiteaCommit(commit)
|
return mapGiteaCommit(commit)
|
||||||
@ -149,7 +149,7 @@ func (g Adapter) GetCommits(ctx context.Context, repoPath string, refs []string)
|
|||||||
var giteaCommit *gitea.Commit
|
var giteaCommit *gitea.Commit
|
||||||
giteaCommit, err = giteaRepo.GetCommit(sha)
|
giteaCommit, err = giteaRepo.GetCommit(sha)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, processGiteaErrorf(err, "error getting commit '%s'", sha)
|
||||||
}
|
}
|
||||||
|
|
||||||
var commit *types.Commit
|
var commit *types.Commit
|
||||||
|
@ -5,13 +5,59 @@
|
|||||||
package gitea
|
package gitea
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
gitea "code.gitea.io/gitea/modules/git"
|
gitea "code.gitea.io/gitea/modules/git"
|
||||||
"github.com/harness/gitness/gitrpc/internal/types"
|
"github.com/harness/gitness/gitrpc/internal/types"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Logs the error and message, returns either the provided message or a git equivalent if possible.
|
||||||
|
// Always logs the full message with error as warning.
|
||||||
|
func processGiteaErrorf(err error, format string, args ...interface{}) error {
|
||||||
|
// create fallback error returned if we can't map it
|
||||||
|
fallbackErr := fmt.Errorf(format, args...)
|
||||||
|
|
||||||
|
// always log internal error together with message.
|
||||||
|
log.Warn().Msgf("%v: [GITEA] %v", fallbackErr, err)
|
||||||
|
|
||||||
|
// check if it's a RunStdError error (contains raw git error)
|
||||||
|
var runStdErr gitea.RunStdError
|
||||||
|
if errors.As(err, &runStdErr) {
|
||||||
|
return mapGiteaRunStdError(runStdErr, fallbackErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case gitea.IsErrNotExist(err):
|
||||||
|
return types.ErrNotFound
|
||||||
|
default:
|
||||||
|
return fallbackErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Improve gitea error handling.
|
||||||
|
// Doubt this will work for all std errors, as git doesn't seem to have nice error codes.
|
||||||
|
func mapGiteaRunStdError(err gitea.RunStdError, fallback error) error {
|
||||||
|
switch {
|
||||||
|
// exit status 128 - fatal: A branch named 'mybranch' already exists.
|
||||||
|
// exit status 128 - fatal: cannot lock ref 'refs/heads/a': 'refs/heads/a/b' exists; cannot create 'refs/heads/a'
|
||||||
|
case err.IsExitCode(128) && strings.Contains(err.Stderr(), "exists"):
|
||||||
|
return types.ErrAlreadyExists
|
||||||
|
|
||||||
|
// exit status 128 - fatal: 'a/bc/d/' is not a valid branch name.
|
||||||
|
case err.IsExitCode(128) && strings.Contains(err.Stderr(), "not a valid"):
|
||||||
|
return types.ErrInvalidArgument
|
||||||
|
|
||||||
|
// exit status 1 - error: branch 'mybranch' not found.
|
||||||
|
case err.IsExitCode(1) && strings.Contains(err.Stderr(), "not found"):
|
||||||
|
return types.ErrNotFound
|
||||||
|
default:
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func mapGiteaRawRef(raw map[string]string) (map[types.GitReferenceField]string, error) {
|
func mapGiteaRawRef(raw map[string]string) (map[types.GitReferenceField]string, error) {
|
||||||
res := make(map[types.GitReferenceField]string, len(raw))
|
res := make(map[types.GitReferenceField]string, len(raw))
|
||||||
for k, v := range raw {
|
for k, v := range raw {
|
||||||
@ -57,7 +103,7 @@ func mapGiteaCommit(giteaCommit *gitea.Commit) (*types.Commit, error) {
|
|||||||
return nil, fmt.Errorf("failed to map gitea commiter: %w", err)
|
return nil, fmt.Errorf("failed to map gitea commiter: %w", err)
|
||||||
}
|
}
|
||||||
return &types.Commit{
|
return &types.Commit{
|
||||||
Sha: giteaCommit.ID.String(),
|
SHA: giteaCommit.ID.String(),
|
||||||
Title: giteaCommit.Summary(),
|
Title: giteaCommit.Summary(),
|
||||||
// remove potential tailing newlines from message
|
// remove potential tailing newlines from message
|
||||||
Message: strings.TrimRight(giteaCommit.Message(), "\n"),
|
Message: strings.TrimRight(giteaCommit.Message(), "\n"),
|
||||||
|
@ -119,7 +119,7 @@ func walkGiteaReferenceParser(parser *gitearef.Parser, handler types.WalkReferen
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := parser.Err(); err != nil {
|
if err := parser.Err(); err != nil {
|
||||||
return fmt.Errorf("failed to parse output: %w", err)
|
return processGiteaErrorf(err, "failed to parse reference walk output")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -35,14 +35,14 @@ func (g Adapter) SetDefaultBranch(ctx context.Context, repoPath string,
|
|||||||
// change default branch
|
// change default branch
|
||||||
err = giteaRepo.SetDefaultBranch(defaultBranch)
|
err = giteaRepo.SetDefaultBranch(defaultBranch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to set new default branch: %w", err)
|
return processGiteaErrorf(err, "failed to set new default branch")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g Adapter) Clone(ctx context.Context, from, to string, opts types.CloneRepoOptions) error {
|
func (g Adapter) Clone(ctx context.Context, from, to string, opts types.CloneRepoOptions) error {
|
||||||
return gitea.Clone(ctx, from, to, gitea.CloneRepoOptions{
|
err := gitea.Clone(ctx, from, to, gitea.CloneRepoOptions{
|
||||||
Timeout: opts.Timeout,
|
Timeout: opts.Timeout,
|
||||||
Mirror: opts.Mirror,
|
Mirror: opts.Mirror,
|
||||||
Bare: opts.Bare,
|
Bare: opts.Bare,
|
||||||
@ -54,14 +54,24 @@ func (g Adapter) Clone(ctx context.Context, from, to string, opts types.CloneRep
|
|||||||
Filter: opts.Filter,
|
Filter: opts.Filter,
|
||||||
SkipTLSVerify: opts.SkipTLSVerify,
|
SkipTLSVerify: opts.SkipTLSVerify,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
return processGiteaErrorf(err, "failed to clone repo")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g Adapter) AddFiles(repoPath string, all bool, files ...string) error {
|
func (g Adapter) AddFiles(repoPath string, all bool, files ...string) error {
|
||||||
return gitea.AddChanges(repoPath, all, files...)
|
err := gitea.AddChanges(repoPath, all, files...)
|
||||||
|
if err != nil {
|
||||||
|
return processGiteaErrorf(err, "failed to add changes")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g Adapter) Commit(repoPath string, opts types.CommitChangesOptions) error {
|
func (g Adapter) Commit(repoPath string, opts types.CommitChangesOptions) error {
|
||||||
return gitea.CommitChanges(repoPath, gitea.CommitChangesOptions{
|
err := gitea.CommitChanges(repoPath, gitea.CommitChangesOptions{
|
||||||
Committer: &gitea.Signature{
|
Committer: &gitea.Signature{
|
||||||
Name: opts.Committer.Identity.Name,
|
Name: opts.Committer.Identity.Name,
|
||||||
Email: opts.Committer.Identity.Email,
|
Email: opts.Committer.Identity.Email,
|
||||||
@ -74,10 +84,15 @@ func (g Adapter) Commit(repoPath string, opts types.CommitChangesOptions) error
|
|||||||
},
|
},
|
||||||
Message: opts.Message,
|
Message: opts.Message,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
return processGiteaErrorf(err, "failed to commit changes")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g Adapter) Push(ctx context.Context, repoPath string, opts types.PushOptions) error {
|
func (g Adapter) Push(ctx context.Context, repoPath string, opts types.PushOptions) error {
|
||||||
return gitea.Push(ctx, repoPath, gitea.PushOptions{
|
err := gitea.Push(ctx, repoPath, gitea.PushOptions{
|
||||||
Remote: opts.Remote,
|
Remote: opts.Remote,
|
||||||
Branch: opts.Branch,
|
Branch: opts.Branch,
|
||||||
Force: opts.Force,
|
Force: opts.Force,
|
||||||
@ -85,4 +100,9 @@ func (g Adapter) Push(ctx context.Context, repoPath string, opts types.PushOptio
|
|||||||
Env: opts.Env,
|
Env: opts.Env,
|
||||||
Timeout: opts.Timeout,
|
Timeout: opts.Timeout,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
return processGiteaErrorf(err, "failed to push changes")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ package gitea
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
gitea "code.gitea.io/gitea/modules/git"
|
gitea "code.gitea.io/gitea/modules/git"
|
||||||
"github.com/harness/gitness/gitrpc/internal/types"
|
"github.com/harness/gitness/gitrpc/internal/types"
|
||||||
@ -27,12 +26,12 @@ func (g Adapter) GetSubmodule(ctx context.Context, repoPath string,
|
|||||||
// Get the giteaCommit object for the ref
|
// Get the giteaCommit object for the ref
|
||||||
giteaCommit, err := giteaRepo.GetCommit(ref)
|
giteaCommit, err := giteaRepo.GetCommit(ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error getting commit for ref '%s': %w", ref, err)
|
return nil, processGiteaErrorf(err, "error getting commit for ref '%s'", ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
giteaSubmodule, err := giteaCommit.GetSubModule(treePath)
|
giteaSubmodule, err := giteaCommit.GetSubModule(treePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error getting submodule '%s' from commit: %w", ref, err)
|
return nil, processGiteaErrorf(err, "error getting submodule '%s' from commit", treePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &types.Submodule{
|
return &types.Submodule{
|
||||||
|
@ -31,7 +31,12 @@ func (g Adapter) GetAnnotatedTag(ctx context.Context, repoPath string, sha strin
|
|||||||
}
|
}
|
||||||
defer giteaRepo.Close()
|
defer giteaRepo.Close()
|
||||||
|
|
||||||
return giteaGetAnnotatedTag(giteaRepo, sha)
|
tag, err := giteaGetAnnotatedTag(giteaRepo, sha)
|
||||||
|
if err != nil {
|
||||||
|
return nil, processGiteaErrorf(err, "failed to get annotated tag with sha '%s'", sha)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAnnotatedTags returns the tags for a specific list of tag sha.
|
// GetAnnotatedTags returns the tags for a specific list of tag sha.
|
||||||
@ -47,7 +52,7 @@ func (g Adapter) GetAnnotatedTags(ctx context.Context, repoPath string, shas []s
|
|||||||
var tag *types.Tag
|
var tag *types.Tag
|
||||||
tag, err = giteaGetAnnotatedTag(giteaRepo, sha)
|
tag, err = giteaGetAnnotatedTag(giteaRepo, sha)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, processGiteaErrorf(err, "failed to get annotated tag with sha '%s'", sha)
|
||||||
}
|
}
|
||||||
|
|
||||||
tags[i] = *tag
|
tags[i] = *tag
|
||||||
|
@ -34,13 +34,14 @@ func (g Adapter) GetTreeNode(ctx context.Context, repoPath string,
|
|||||||
// Get the giteaCommit object for the ref
|
// Get the giteaCommit object for the ref
|
||||||
giteaCommit, err := giteaRepo.GetCommit(ref)
|
giteaCommit, err := giteaRepo.GetCommit(ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error getting commit for ref '%s': %w", ref, err)
|
return nil, processGiteaErrorf(err, "error getting commit for ref '%s'", ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: handle ErrNotExist :)
|
// TODO: handle ErrNotExist :)
|
||||||
giteaTreeEntry, err := giteaCommit.GetTreeEntryByPath(treePath)
|
giteaTreeEntry, err := giteaCommit.GetTreeEntryByPath(treePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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())
|
nodeType, mode, err := mapGiteaNodeToTreeNodeModeAndType(giteaTreeEntry.Mode())
|
||||||
@ -83,13 +84,13 @@ func (g Adapter) ListTreeNodes(ctx context.Context, repoPath string,
|
|||||||
// Get the giteaCommit object for the ref
|
// Get the giteaCommit object for the ref
|
||||||
giteaCommit, err := giteaRepo.GetCommit(ref)
|
giteaCommit, err := giteaRepo.GetCommit(ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error getting commit for ref '%s': %w", ref, err)
|
return nil, processGiteaErrorf(err, "error getting commit for ref '%s'", ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the giteaTree object for the ref
|
// Get the giteaTree object for the ref
|
||||||
giteaTree, err := giteaCommit.SubTree(treePath)
|
giteaTree, err := giteaCommit.SubTree(treePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error getting tree for '%s': %w", treePath, err)
|
return nil, processGiteaErrorf(err, "error getting tree for '%s'", treePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
var giteaEntries gitea.Entries
|
var giteaEntries gitea.Entries
|
||||||
@ -99,7 +100,7 @@ func (g Adapter) ListTreeNodes(ctx context.Context, repoPath string,
|
|||||||
giteaEntries, err = giteaTree.ListEntries()
|
giteaEntries, err = giteaTree.ListEntries()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to list entries for tree '%s': %w", treePath, err)
|
return nil, processGiteaErrorf(err, "failed to list entries for tree '%s'", treePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
var latestCommits []gitea.CommitInfo
|
var latestCommits []gitea.CommitInfo
|
||||||
@ -107,7 +108,7 @@ func (g Adapter) ListTreeNodes(ctx context.Context, repoPath string,
|
|||||||
// TODO: can be speed up with latestCommitCache (currently nil)
|
// TODO: can be speed up with latestCommitCache (currently nil)
|
||||||
latestCommits, _, err = giteaEntries.GetCommitsInfo(ctx, giteaCommit, treePath, nil)
|
latestCommits, _, err = giteaEntries.GetCommitsInfo(ctx, giteaCommit, treePath, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get latest commits for entries: %w", err)
|
return nil, processGiteaErrorf(err, "failed to get latest commits for entries")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(latestCommits) != len(giteaEntries) {
|
if len(latestCommits) != len(giteaEntries) {
|
||||||
|
@ -11,11 +11,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (s RepositoryService) GetBlob(ctx context.Context, request *rpc.GetBlobRequest) (*rpc.GetBlobResponse, error) {
|
func (s RepositoryService) GetBlob(ctx context.Context, request *rpc.GetBlobRequest) (*rpc.GetBlobResponse, error) {
|
||||||
repoPath := s.getFullPathForRepo(request.GetRepoUid())
|
repoPath := getFullPathForRepo(s.reposRoot, request.GetRepoUid())
|
||||||
// TODO: do we need to validate request for nil?
|
// TODO: do we need to validate request for nil?
|
||||||
gitBlob, err := s.adapter.GetBlob(ctx, repoPath, request.GetSha(), request.GetSizeLimit())
|
gitBlob, err := s.adapter.GetBlob(ctx, repoPath, request.GetSha(), request.GetSizeLimit())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, processGitErrorf(err, "failed to get blob")
|
||||||
}
|
}
|
||||||
|
|
||||||
return &rpc.GetBlobResponse{
|
return &rpc.GetBlobResponse{
|
||||||
|
@ -18,10 +18,42 @@ import (
|
|||||||
|
|
||||||
var listBranchesRefFields = []types.GitReferenceField{types.GitReferenceFieldRefName, types.GitReferenceFieldObjectName}
|
var listBranchesRefFields = []types.GitReferenceField{types.GitReferenceFieldRefName, types.GitReferenceFieldObjectName}
|
||||||
|
|
||||||
func (s RepositoryService) ListBranches(request *rpc.ListBranchesRequest,
|
func (s ReferenceService) CreateBranch(ctx context.Context,
|
||||||
stream rpc.RepositoryService_ListBranchesServer) error {
|
request *rpc.CreateBranchRequest) (*rpc.CreateBranchResponse, error) {
|
||||||
|
repoPath := getFullPathForRepo(s.reposRoot, request.GetRepoUid())
|
||||||
|
|
||||||
|
gitBranch, err := s.adapter.CreateBranch(ctx, repoPath, request.GetBranchName(), request.GetTarget())
|
||||||
|
if err != nil {
|
||||||
|
return nil, processGitErrorf(err, "failed to create branch")
|
||||||
|
}
|
||||||
|
|
||||||
|
branch, err := mapGitBranch(gitBranch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &rpc.CreateBranchResponse{
|
||||||
|
Branch: branch,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ReferenceService) DeleteBranch(ctx context.Context,
|
||||||
|
request *rpc.DeleteBranchRequest) (*rpc.DeleteBranchResponse, error) {
|
||||||
|
repoPath := getFullPathForRepo(s.reposRoot, request.GetRepoUid())
|
||||||
|
|
||||||
|
// TODO: block deletion of protected branch (in the future)
|
||||||
|
err := s.adapter.DeleteBranch(ctx, repoPath, request.GetBranchName(), request.GetForce())
|
||||||
|
if err != nil {
|
||||||
|
return nil, processGitErrorf(err, "failed to delete branch")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &rpc.DeleteBranchResponse{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ReferenceService) ListBranches(request *rpc.ListBranchesRequest,
|
||||||
|
stream rpc.ReferenceService_ListBranchesServer) error {
|
||||||
ctx := stream.Context()
|
ctx := stream.Context()
|
||||||
repoPath := s.getFullPathForRepo(request.GetRepoUid())
|
repoPath := getFullPathForRepo(s.reposRoot, request.GetRepoUid())
|
||||||
|
|
||||||
// get all required information from git refrences
|
// get all required information from git refrences
|
||||||
branches, err := s.listBranchesLoadReferenceData(ctx, repoPath, request)
|
branches, err := s.listBranchesLoadReferenceData(ctx, repoPath, request)
|
||||||
@ -63,7 +95,7 @@ func (s RepositoryService) ListBranches(request *rpc.ListBranchesRequest,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s RepositoryService) listBranchesLoadReferenceData(ctx context.Context,
|
func (s ReferenceService) listBranchesLoadReferenceData(ctx context.Context,
|
||||||
repoPath string, request *rpc.ListBranchesRequest) ([]*rpc.Branch, error) {
|
repoPath string, request *rpc.ListBranchesRequest) ([]*rpc.Branch, error) {
|
||||||
// TODO: can we be smarter with slice allocation
|
// TODO: can we be smarter with slice allocation
|
||||||
branches := make([]*rpc.Branch, 0, 16)
|
branches := make([]*rpc.Branch, 0, 16)
|
||||||
@ -88,7 +120,7 @@ func (s RepositoryService) listBranchesLoadReferenceData(ctx context.Context,
|
|||||||
|
|
||||||
err = s.adapter.WalkReferences(ctx, repoPath, handler, opts)
|
err = s.adapter.WalkReferences(ctx, repoPath, handler, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Errorf(codes.Internal, "failed to get branch references: %v", err)
|
return nil, processGitErrorf(err, "failed to walk branch references")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().Msgf("git adapter returned %d branches", len(branches))
|
log.Trace().Msgf("git adapter returned %d branches", len(branches))
|
||||||
|
@ -15,12 +15,12 @@ import (
|
|||||||
|
|
||||||
func (s RepositoryService) ListCommits(request *rpc.ListCommitsRequest,
|
func (s RepositoryService) ListCommits(request *rpc.ListCommitsRequest,
|
||||||
stream rpc.RepositoryService_ListCommitsServer) error {
|
stream rpc.RepositoryService_ListCommitsServer) error {
|
||||||
repoPath := s.getFullPathForRepo(request.GetRepoUid())
|
repoPath := getFullPathForRepo(s.reposRoot, request.GetRepoUid())
|
||||||
|
|
||||||
gitCommits, totalCount, err := s.adapter.ListCommits(stream.Context(), repoPath, request.GetGitRef(),
|
gitCommits, totalCount, err := s.adapter.ListCommits(stream.Context(), repoPath, request.GetGitRef(),
|
||||||
int(request.GetPage()), int(request.GetPageSize()))
|
int(request.GetPage()), int(request.GetPageSize()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return status.Errorf(codes.Internal, "failed to list commits: %v", err)
|
return processGitErrorf(err, "failed to get list of commits")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().Msgf("git adapter returned %d commits (total: %d)", len(gitCommits), totalCount)
|
log.Trace().Msgf("git adapter returned %d commits (total: %d)", len(gitCommits), totalCount)
|
||||||
@ -61,7 +61,7 @@ func (s RepositoryService) getLatestCommit(ctx context.Context, repoPath string,
|
|||||||
ref string, path string) (*rpc.Commit, error) {
|
ref string, path string) (*rpc.Commit, error) {
|
||||||
gitCommit, err := s.adapter.GetLatestCommit(ctx, repoPath, ref, path)
|
gitCommit, err := s.adapter.GetLatestCommit(ctx, repoPath, ref, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, processGitErrorf(err, "failed to get latest commit")
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapGitCommit(gitCommit)
|
return mapGitCommit(gitCommit)
|
||||||
|
@ -7,11 +7,9 @@ package service
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -38,30 +36,13 @@ type SmartHTTPService struct {
|
|||||||
reposRoot string
|
reposRoot string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHTTPService(adapter GitAdapter, gitRoot string) (*SmartHTTPService, error) {
|
func NewHTTPService(adapter GitAdapter, reposRoot string) (*SmartHTTPService, error) {
|
||||||
reposRoot := filepath.Join(gitRoot, repoSubdirName)
|
|
||||||
if _, err := os.Stat(reposRoot); errors.Is(err, os.ErrNotExist) {
|
|
||||||
if err = os.MkdirAll(reposRoot, 0o700); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &SmartHTTPService{
|
return &SmartHTTPService{
|
||||||
adapter: adapter,
|
adapter: adapter,
|
||||||
reposRoot: reposRoot,
|
reposRoot: reposRoot,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SmartHTTPService) getFullPathForRepo(uid string) string {
|
|
||||||
// split repos into subfolders using their prefix to distribute repos accross a set of folders.
|
|
||||||
return filepath.Join(
|
|
||||||
s.reposRoot, // root folder
|
|
||||||
uid[0:2], // first subfolder
|
|
||||||
uid[2:4], // second subfolder
|
|
||||||
fmt.Sprintf("%s.%s", uid[4:], gitRepoSuffix), // remainder with .git
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SmartHTTPService) InfoRefs(
|
func (s *SmartHTTPService) InfoRefs(
|
||||||
r *rpc.InfoRefsRequest,
|
r *rpc.InfoRefsRequest,
|
||||||
stream rpc.SmartHTTPService_InfoRefsServer,
|
stream rpc.SmartHTTPService_InfoRefsServer,
|
||||||
@ -72,7 +53,7 @@ func (s *SmartHTTPService) InfoRefs(
|
|||||||
environ = append(environ, "GIT_PROTOCOL="+r.GitProtocol)
|
environ = append(environ, "GIT_PROTOCOL="+r.GitProtocol)
|
||||||
}
|
}
|
||||||
|
|
||||||
repoPath := s.getFullPathForRepo(r.GetRepoUid())
|
repoPath := getFullPathForRepo(s.reposRoot, r.GetRepoUid())
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -120,7 +101,7 @@ func (s *SmartHTTPService) ServicePack(stream rpc.SmartHTTPService_ServicePackSe
|
|||||||
return status.Errorf(codes.InvalidArgument, "PostUploadPack(): repository UID is missing")
|
return status.Errorf(codes.InvalidArgument, "PostUploadPack(): repository UID is missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
repoPath := s.getFullPathForRepo(req.GetRepoUid())
|
repoPath := getFullPathForRepo(s.reposRoot, req.GetRepoUid())
|
||||||
|
|
||||||
stdin := streamio.NewReader(func() ([]byte, error) {
|
stdin := streamio.NewReader(func() ([]byte, error) {
|
||||||
resp, streamErr := stream.Recv()
|
resp, streamErr := stream.Recv()
|
||||||
|
@ -32,4 +32,6 @@ type GitAdapter interface {
|
|||||||
GetLatestCommit(ctx context.Context, repoPath string, ref string, treePath string) (*types.Commit, error)
|
GetLatestCommit(ctx context.Context, repoPath string, ref string, treePath string) (*types.Commit, error)
|
||||||
GetAnnotatedTag(ctx context.Context, repoPath string, sha string) (*types.Tag, error)
|
GetAnnotatedTag(ctx context.Context, repoPath string, sha string) (*types.Tag, error)
|
||||||
GetAnnotatedTags(ctx context.Context, repoPath string, shas []string) ([]types.Tag, error)
|
GetAnnotatedTags(ctx context.Context, repoPath string, shas []string) ([]types.Tag, error)
|
||||||
|
CreateBranch(ctx context.Context, repoPath string, branchName string, target string) (*types.Branch, error)
|
||||||
|
DeleteBranch(ctx context.Context, repoPath string, branchName string, force bool) error
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,37 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/harness/gitness/gitrpc/internal/types"
|
"github.com/harness/gitness/gitrpc/internal/types"
|
||||||
"github.com/harness/gitness/gitrpc/rpc"
|
"github.com/harness/gitness/gitrpc/rpc"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Logs the error and message, returns either the provided message or a rpc equivalent if possible.
|
||||||
|
// Always logs the full message with error as warning.
|
||||||
|
func processGitErrorf(err error, format string, args ...interface{}) error {
|
||||||
|
// create fallback error returned if we can't map it
|
||||||
|
message := fmt.Sprintf(format, args...)
|
||||||
|
|
||||||
|
// always log internal error together with message.
|
||||||
|
log.Warn().Msgf("%s: [GIT] %v", message, err)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case errors.Is(err, types.ErrNotFound):
|
||||||
|
return status.Error(codes.NotFound, message)
|
||||||
|
case errors.Is(err, types.ErrAlreadyExists):
|
||||||
|
return status.Errorf(codes.AlreadyExists, message)
|
||||||
|
case errors.Is(err, types.ErrInvalidArgument):
|
||||||
|
return status.Errorf(codes.InvalidArgument, message)
|
||||||
|
default:
|
||||||
|
return status.Errorf(codes.Unknown, message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func mapSortOrder(s rpc.SortOrder) types.SortOrder {
|
func mapSortOrder(s rpc.SortOrder) types.SortOrder {
|
||||||
switch s {
|
switch s {
|
||||||
case rpc.SortOrder_Asc:
|
case rpc.SortOrder_Asc:
|
||||||
@ -63,13 +88,34 @@ func mapGitMode(m types.TreeNodeMode) rpc.TreeNodeMode {
|
|||||||
return rpc.TreeNodeMode(m)
|
return rpc.TreeNodeMode(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mapGitBranch(gitBranch *types.Branch) (*rpc.Branch, error) {
|
||||||
|
if gitBranch == nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "git branch is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
var commit *rpc.Commit
|
||||||
|
var err error
|
||||||
|
if gitBranch.Commit != nil {
|
||||||
|
commit, err = mapGitCommit(gitBranch.Commit)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &rpc.Branch{
|
||||||
|
Name: gitBranch.Name,
|
||||||
|
Sha: gitBranch.SHA,
|
||||||
|
Commit: commit,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func mapGitCommit(gitCommit *types.Commit) (*rpc.Commit, error) {
|
func mapGitCommit(gitCommit *types.Commit) (*rpc.Commit, error) {
|
||||||
if gitCommit == nil {
|
if gitCommit == nil {
|
||||||
return nil, status.Errorf(codes.Internal, "git commit is nil")
|
return nil, status.Errorf(codes.Internal, "git commit is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
return &rpc.Commit{
|
return &rpc.Commit{
|
||||||
Sha: gitCommit.Sha,
|
Sha: gitCommit.SHA,
|
||||||
Title: gitCommit.Title,
|
Title: gitCommit.Title,
|
||||||
Message: gitCommit.Message,
|
Message: gitCommit.Message,
|
||||||
Author: mapGitSignature(gitCommit.Author),
|
Author: mapGitSignature(gitCommit.Author),
|
||||||
|
22
gitrpc/internal/service/path.go
Normal file
22
gitrpc/internal/service/path.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// 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 service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
// getFullPathForRepo returns the full path of a repo given the root dir of repos and the uid of the repo.
|
||||||
|
// NOTE: Split repos into subfolders using their prefix to distribute repos accross a set of folders.
|
||||||
|
func getFullPathForRepo(reposRoot, uid string) string {
|
||||||
|
// ASSUMPTION: repoUID is of lenth at least 4 - otherwise we have trouble either way.
|
||||||
|
return filepath.Join(
|
||||||
|
reposRoot, // root folder
|
||||||
|
uid[0:2], // first subfolder
|
||||||
|
uid[2:4], // second subfolder
|
||||||
|
fmt.Sprintf("%s.%s", uid[4:], gitRepoSuffix), // remainder with .git
|
||||||
|
)
|
||||||
|
}
|
@ -10,8 +10,22 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/harness/gitness/gitrpc/internal/types"
|
"github.com/harness/gitness/gitrpc/internal/types"
|
||||||
|
"github.com/harness/gitness/gitrpc/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ReferenceService struct {
|
||||||
|
rpc.UnimplementedReferenceServiceServer
|
||||||
|
adapter GitAdapter
|
||||||
|
reposRoot string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewReferenceService(adapter GitAdapter, reposRoot string) (*ReferenceService, error) {
|
||||||
|
return &ReferenceService{
|
||||||
|
adapter: adapter,
|
||||||
|
reposRoot: reposRoot,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// sanitizeReferenceQuery removes characters that aren't allowd in a branch name.
|
// sanitizeReferenceQuery removes characters that aren't allowd in a branch name.
|
||||||
// TODO: should we error out instead of ignore bad chars?
|
// TODO: should we error out instead of ignore bad chars?
|
||||||
func sanitizeReferenceQuery(query string) (string, bool, bool) {
|
func sanitizeReferenceQuery(query string) (string, bool, bool) {
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/harness/gitness/gitrpc/internal/types"
|
"github.com/harness/gitness/gitrpc/internal/types"
|
||||||
"github.com/harness/gitness/gitrpc/rpc"
|
"github.com/harness/gitness/gitrpc/rpc"
|
||||||
@ -21,9 +20,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
maxFileSize = 1 << 20
|
maxFileSize = 1 << 20
|
||||||
repoSubdirName = "repos"
|
gitRepoSuffix = "git"
|
||||||
gitRepoSuffix = "git"
|
|
||||||
|
|
||||||
gitReferenceNamePrefixBranch = "refs/heads/"
|
gitReferenceNamePrefixBranch = "refs/heads/"
|
||||||
gitReferenceNamePrefixTag = "refs/tags/"
|
gitReferenceNamePrefixTag = "refs/tags/"
|
||||||
@ -48,14 +46,7 @@ type RepositoryService struct {
|
|||||||
reposRoot string
|
reposRoot string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRepositoryService(adapter GitAdapter, store Storage, gitRoot string) (*RepositoryService, error) {
|
func NewRepositoryService(adapter GitAdapter, store Storage, reposRoot string) (*RepositoryService, error) {
|
||||||
reposRoot := filepath.Join(gitRoot, repoSubdirName)
|
|
||||||
if _, err := os.Stat(reposRoot); errors.Is(err, os.ErrNotExist) {
|
|
||||||
if err = os.MkdirAll(reposRoot, 0o700); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &RepositoryService{
|
return &RepositoryService{
|
||||||
adapter: adapter,
|
adapter: adapter,
|
||||||
store: store,
|
store: store,
|
||||||
@ -63,16 +54,6 @@ func NewRepositoryService(adapter GitAdapter, store Storage, gitRoot string) (*R
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s RepositoryService) getFullPathForRepo(uid string) string {
|
|
||||||
// split repos into subfolders using their prefix to distribute repos accross a set of folders.
|
|
||||||
return filepath.Join(
|
|
||||||
s.reposRoot, // root folder
|
|
||||||
uid[0:2], // first subfolder
|
|
||||||
uid[2:4], // second subfolder
|
|
||||||
fmt.Sprintf("%s.%s", uid[4:], gitRepoSuffix), // remainder with .git
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
//nolint:gocognit // need to refactor this code
|
//nolint:gocognit // need to refactor this code
|
||||||
func (s RepositoryService) CreateRepository(stream rpc.RepositoryService_CreateRepositoryServer) error {
|
func (s RepositoryService) CreateRepository(stream rpc.RepositoryService_CreateRepositoryServer) error {
|
||||||
// first get repo params from stream
|
// first get repo params from stream
|
||||||
@ -87,7 +68,7 @@ func (s RepositoryService) CreateRepository(stream rpc.RepositoryService_CreateR
|
|||||||
}
|
}
|
||||||
log.Info().Msgf("received a create repository request %v", header)
|
log.Info().Msgf("received a create repository request %v", header)
|
||||||
|
|
||||||
repoPath := s.getFullPathForRepo(header.GetUid())
|
repoPath := getFullPathForRepo(s.reposRoot, header.GetUid())
|
||||||
if _, err = os.Stat(repoPath); !os.IsNotExist(err) {
|
if _, err = os.Stat(repoPath); !os.IsNotExist(err) {
|
||||||
return status.Errorf(codes.AlreadyExists, "repository exists already: %v", repoPath)
|
return status.Errorf(codes.AlreadyExists, "repository exists already: %v", repoPath)
|
||||||
}
|
}
|
||||||
@ -101,13 +82,13 @@ func (s RepositoryService) CreateRepository(stream rpc.RepositoryService_CreateR
|
|||||||
defer func(path string) {
|
defer func(path string) {
|
||||||
_ = os.RemoveAll(path)
|
_ = os.RemoveAll(path)
|
||||||
}(repoPath)
|
}(repoPath)
|
||||||
return fmt.Errorf("CreateRepository error: %w", err)
|
return processGitErrorf(err, "failed to initialize the repository")
|
||||||
}
|
}
|
||||||
|
|
||||||
// update default branch (currently set to non-existent branch)
|
// update default branch (currently set to non-existent branch)
|
||||||
err = s.adapter.SetDefaultBranch(ctx, repoPath, header.GetDefaultBranch(), true)
|
err = s.adapter.SetDefaultBranch(ctx, repoPath, header.GetDefaultBranch(), true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error updating default branch for repo %s: %w", header.GetUid(), err)
|
return processGitErrorf(err, "error updating default branch for repo '%s'", header.GetUid())
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need temp dir for cloning
|
// we need temp dir for cloning
|
||||||
@ -125,7 +106,7 @@ func (s RepositoryService) CreateRepository(stream rpc.RepositoryService_CreateR
|
|||||||
|
|
||||||
// Clone repository to temp dir
|
// Clone repository to temp dir
|
||||||
if err = s.adapter.Clone(ctx, repoPath, tempDir, types.CloneRepoOptions{}); err != nil {
|
if err = s.adapter.Clone(ctx, repoPath, tempDir, types.CloneRepoOptions{}); err != nil {
|
||||||
return status.Errorf(codes.Internal, "failed to clone repo: %v", err)
|
return processGitErrorf(err, "failed to clone repo")
|
||||||
}
|
}
|
||||||
|
|
||||||
// logic for receiving files
|
// logic for receiving files
|
||||||
|
@ -12,11 +12,11 @@ import (
|
|||||||
|
|
||||||
func (s RepositoryService) GetSubmodule(ctx context.Context,
|
func (s RepositoryService) GetSubmodule(ctx context.Context,
|
||||||
request *rpc.GetSubmoduleRequest) (*rpc.GetSubmoduleResponse, error) {
|
request *rpc.GetSubmoduleRequest) (*rpc.GetSubmoduleResponse, error) {
|
||||||
repoPath := s.getFullPathForRepo(request.GetRepoUid())
|
repoPath := getFullPathForRepo(s.reposRoot, request.GetRepoUid())
|
||||||
// TODO: do we need to validate request for nil?
|
// TODO: do we need to validate request for nil?
|
||||||
gitSubmodule, err := s.adapter.GetSubmodule(ctx, repoPath, request.GetGitRef(), request.GetPath())
|
gitSubmodule, err := s.adapter.GetSubmodule(ctx, repoPath, request.GetGitRef(), request.GetPath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, processGitErrorf(err, "failed to get submodule")
|
||||||
}
|
}
|
||||||
|
|
||||||
return &rpc.GetSubmoduleResponse{
|
return &rpc.GetSubmoduleResponse{
|
||||||
|
@ -16,10 +16,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
//nolint:gocognit // need to refactor this code
|
//nolint:gocognit // need to refactor this code
|
||||||
func (s RepositoryService) ListCommitTags(request *rpc.ListCommitTagsRequest,
|
func (s ReferenceService) ListCommitTags(request *rpc.ListCommitTagsRequest,
|
||||||
stream rpc.RepositoryService_ListCommitTagsServer) error {
|
stream rpc.ReferenceService_ListCommitTagsServer) error {
|
||||||
ctx := stream.Context()
|
ctx := stream.Context()
|
||||||
repoPath := s.getFullPathForRepo(request.GetRepoUid())
|
repoPath := getFullPathForRepo(s.reposRoot, request.GetRepoUid())
|
||||||
|
|
||||||
// get all required information from git references
|
// get all required information from git references
|
||||||
tags, err := s.listCommitTagsLoadReferenceData(ctx, repoPath, request)
|
tags, err := s.listCommitTagsLoadReferenceData(ctx, repoPath, request)
|
||||||
@ -43,7 +43,7 @@ func (s RepositoryService) ListCommitTags(request *rpc.ListCommitTagsRequest,
|
|||||||
var gitTags []types.Tag
|
var gitTags []types.Tag
|
||||||
gitTags, err = s.adapter.GetAnnotatedTags(ctx, repoPath, annotatedTagSHAs)
|
gitTags, err = s.adapter.GetAnnotatedTags(ctx, repoPath, annotatedTagSHAs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return status.Errorf(codes.Internal, "failed to get annotated tag: %v", err)
|
return processGitErrorf(err, "failed to get annotated tag")
|
||||||
}
|
}
|
||||||
|
|
||||||
ai := 0 // since only some tags are annotated, we need second index
|
ai := 0 // since only some tags are annotated, we need second index
|
||||||
@ -71,7 +71,7 @@ func (s RepositoryService) ListCommitTags(request *rpc.ListCommitTagsRequest,
|
|||||||
var gitCommits []types.Commit
|
var gitCommits []types.Commit
|
||||||
gitCommits, err = s.adapter.GetCommits(ctx, repoPath, commitSHAs)
|
gitCommits, err = s.adapter.GetCommits(ctx, repoPath, commitSHAs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return status.Errorf(codes.Internal, "failed to get commits: %v", err)
|
return processGitErrorf(err, "failed to get commits")
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range gitCommits {
|
for i := range gitCommits {
|
||||||
@ -118,7 +118,7 @@ var listCommitTagsRefFields = []types.GitReferenceField{types.GitReferenceFieldR
|
|||||||
types.GitReferenceFieldObjectType, types.GitReferenceFieldObjectName}
|
types.GitReferenceFieldObjectType, types.GitReferenceFieldObjectName}
|
||||||
var listCommitTagsObjectTypeFilter = []types.GitObjectType{types.GitObjectTypeCommit, types.GitObjectTypeTag}
|
var listCommitTagsObjectTypeFilter = []types.GitObjectType{types.GitObjectTypeCommit, types.GitObjectTypeTag}
|
||||||
|
|
||||||
func (s RepositoryService) listCommitTagsLoadReferenceData(ctx context.Context,
|
func (s ReferenceService) listCommitTagsLoadReferenceData(ctx context.Context,
|
||||||
repoPath string, request *rpc.ListCommitTagsRequest) ([]*rpc.CommitTag, error) {
|
repoPath string, request *rpc.ListCommitTagsRequest) ([]*rpc.CommitTag, error) {
|
||||||
// TODO: can we be smarter with slice allocation
|
// TODO: can we be smarter with slice allocation
|
||||||
tags := make([]*rpc.CommitTag, 0, 16)
|
tags := make([]*rpc.CommitTag, 0, 16)
|
||||||
@ -143,7 +143,7 @@ func (s RepositoryService) listCommitTagsLoadReferenceData(ctx context.Context,
|
|||||||
|
|
||||||
err = s.adapter.WalkReferences(ctx, repoPath, handler, opts)
|
err = s.adapter.WalkReferences(ctx, repoPath, handler, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Errorf(codes.Internal, "failed to get tag references: %v", err)
|
return nil, processGitErrorf(err, "failed to walk tag references")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().Msgf("git adapter returned %d tags", len(tags))
|
log.Trace().Msgf("git adapter returned %d tags", len(tags))
|
||||||
|
@ -15,12 +15,12 @@ import (
|
|||||||
|
|
||||||
func (s RepositoryService) ListTreeNodes(request *rpc.ListTreeNodesRequest,
|
func (s RepositoryService) ListTreeNodes(request *rpc.ListTreeNodesRequest,
|
||||||
stream rpc.RepositoryService_ListTreeNodesServer) error {
|
stream rpc.RepositoryService_ListTreeNodesServer) error {
|
||||||
repoPath := s.getFullPathForRepo(request.GetRepoUid())
|
repoPath := getFullPathForRepo(s.reposRoot, request.GetRepoUid())
|
||||||
|
|
||||||
gitNodes, err := s.adapter.ListTreeNodes(stream.Context(), repoPath,
|
gitNodes, err := s.adapter.ListTreeNodes(stream.Context(), repoPath,
|
||||||
request.GetGitRef(), request.GetPath(), request.GetRecursive(), request.GetIncludeLatestCommit())
|
request.GetGitRef(), request.GetPath(), request.GetRecursive(), request.GetIncludeLatestCommit())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return status.Errorf(codes.Internal, "failed to list nodes: %v", err)
|
return processGitErrorf(err, "failed to list tree nodes")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().Msgf("git adapter returned %d nodes", len(gitNodes))
|
log.Trace().Msgf("git adapter returned %d nodes", len(gitNodes))
|
||||||
@ -54,11 +54,11 @@ func (s RepositoryService) ListTreeNodes(request *rpc.ListTreeNodesRequest,
|
|||||||
|
|
||||||
func (s RepositoryService) GetTreeNode(ctx context.Context,
|
func (s RepositoryService) GetTreeNode(ctx context.Context,
|
||||||
request *rpc.GetTreeNodeRequest) (*rpc.GetTreeNodeResponse, error) {
|
request *rpc.GetTreeNodeRequest) (*rpc.GetTreeNodeResponse, error) {
|
||||||
repoPath := s.getFullPathForRepo(request.GetRepoUid())
|
repoPath := getFullPathForRepo(s.reposRoot, request.GetRepoUid())
|
||||||
// TODO: do we need to validate request for nil?
|
// TODO: do we need to validate request for nil?
|
||||||
gitNode, err := s.adapter.GetTreeNode(ctx, repoPath, request.GetGitRef(), request.GetPath())
|
gitNode, err := s.adapter.GetTreeNode(ctx, repoPath, request.GetGitRef(), request.GetPath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, processGitErrorf(err, "failed to get tree node")
|
||||||
}
|
}
|
||||||
|
|
||||||
res := &rpc.GetTreeNodeResponse{
|
res := &rpc.GetTreeNodeResponse{
|
||||||
@ -76,7 +76,7 @@ func (s RepositoryService) GetTreeNode(ctx context.Context,
|
|||||||
var commit *rpc.Commit
|
var commit *rpc.Commit
|
||||||
commit, err = s.getLatestCommit(ctx, repoPath, request.GetGitRef(), request.GetPath())
|
commit, err = s.getLatestCommit(ctx, repoPath, request.GetGitRef(), request.GetPath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Errorf(codes.Internal, "failed to get latest commit: %v", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
res.Commit = commit
|
res.Commit = commit
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ func (s RepositoryService) AddFilesAndPush(
|
|||||||
|
|
||||||
err := s.adapter.AddFiles(repoPath, false, filePaths...)
|
err := s.adapter.AddFiles(repoPath, false, filePaths...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return processGitErrorf(err, "failed to add files")
|
||||||
}
|
}
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
err = s.adapter.Commit(repoPath, types.CommitChangesOptions{
|
err = s.adapter.Commit(repoPath, types.CommitChangesOptions{
|
||||||
@ -60,7 +60,7 @@ func (s RepositoryService) AddFilesAndPush(
|
|||||||
Message: message,
|
Message: message,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return processGitErrorf(err, "failed to commit files")
|
||||||
}
|
}
|
||||||
err = s.adapter.Push(ctx, repoPath, types.PushOptions{
|
err = s.adapter.Push(ctx, repoPath, types.PushOptions{
|
||||||
// TODO: Don't hard-code
|
// TODO: Don't hard-code
|
||||||
@ -72,7 +72,7 @@ func (s RepositoryService) AddFilesAndPush(
|
|||||||
Timeout: 0,
|
Timeout: 0,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return processGitErrorf(err, "failed to push files")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -2,4 +2,12 @@
|
|||||||
// Use of this source code is governed by the Polyform Free Trial License
|
// 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.
|
// that can be found in the LICENSE.md file for this repository.
|
||||||
|
|
||||||
package gitrpc
|
package types
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrAlreadyExists = errors.New("already exists")
|
||||||
|
ErrInvalidArgument = errors.New("invalid argument")
|
||||||
|
ErrNotFound = errors.New("not found")
|
||||||
|
)
|
@ -126,13 +126,19 @@ type WalkReferencesOptions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Commit struct {
|
type Commit struct {
|
||||||
Sha string
|
SHA string
|
||||||
Title string
|
Title string
|
||||||
Message string
|
Message string
|
||||||
Author Signature
|
Author Signature
|
||||||
Committer Signature
|
Committer Signature
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Branch struct {
|
||||||
|
Name string
|
||||||
|
SHA string
|
||||||
|
Commit *Commit
|
||||||
|
}
|
||||||
|
|
||||||
type Tag struct {
|
type Tag struct {
|
||||||
Sha string
|
Sha string
|
||||||
Name string
|
Name string
|
||||||
|
@ -9,8 +9,38 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/harness/gitness/gitrpc/rpc"
|
"github.com/harness/gitness/gitrpc/rpc"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Logs the error and message, returns either the provided message or a gitrpc equivalent if possible.
|
||||||
|
// Always logs the full message with error as warning.
|
||||||
|
func processRPCErrorf(err error, format string, args ...interface{}) error {
|
||||||
|
// create fallback error returned if we can't map it
|
||||||
|
fallbackErr := fmt.Errorf(format, args...)
|
||||||
|
|
||||||
|
// always log internal error together with message.
|
||||||
|
log.Warn().Msgf("%v: [RPC] %v", fallbackErr, err)
|
||||||
|
|
||||||
|
// ensure it's an rpc error
|
||||||
|
rpcErr, ok := status.FromError(err)
|
||||||
|
if !ok {
|
||||||
|
return fallbackErr
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case rpcErr.Code() == codes.AlreadyExists:
|
||||||
|
return ErrAlreadyExists
|
||||||
|
case rpcErr.Code() == codes.NotFound:
|
||||||
|
return ErrNotFound
|
||||||
|
case rpcErr.Code() == codes.InvalidArgument:
|
||||||
|
return ErrInvalidArgument
|
||||||
|
default:
|
||||||
|
return fallbackErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func mapToRPCSortOrder(o SortOrder) rpc.SortOrder {
|
func mapToRPCSortOrder(o SortOrder) rpc.SortOrder {
|
||||||
switch o {
|
switch o {
|
||||||
case SortOrderAsc:
|
case SortOrderAsc:
|
||||||
|
88
gitrpc/proto/ref.proto
Normal file
88
gitrpc/proto/ref.proto
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
package rpc;
|
||||||
|
|
||||||
|
option go_package = "github.com/harness/gitness/gitrpc/rpc";
|
||||||
|
|
||||||
|
import "shared.proto";
|
||||||
|
|
||||||
|
service ReferenceService {
|
||||||
|
rpc CreateBranch(CreateBranchRequest) returns (CreateBranchResponse);
|
||||||
|
rpc DeleteBranch(DeleteBranchRequest) returns (DeleteBranchResponse);
|
||||||
|
rpc ListBranches(ListBranchesRequest) returns (stream ListBranchesResponse);
|
||||||
|
rpc ListCommitTags(ListCommitTagsRequest) returns (stream ListCommitTagsResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
message CreateBranchRequest {
|
||||||
|
string repo_uid = 1;
|
||||||
|
string branch_name = 2;
|
||||||
|
string target = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CreateBranchResponse {
|
||||||
|
Branch branch = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DeleteBranchRequest {
|
||||||
|
string repo_uid = 1;
|
||||||
|
string branch_name = 2;
|
||||||
|
bool force = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DeleteBranchResponse {
|
||||||
|
}
|
||||||
|
|
||||||
|
message ListBranchesRequest {
|
||||||
|
enum SortOption {
|
||||||
|
Default = 0;
|
||||||
|
Name = 1;
|
||||||
|
Date = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
string repo_uid = 1;
|
||||||
|
bool include_commit = 2;
|
||||||
|
string query = 3;
|
||||||
|
SortOption sort = 4;
|
||||||
|
SortOrder order = 5;
|
||||||
|
int32 page = 6;
|
||||||
|
int32 pageSize = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ListBranchesResponse {
|
||||||
|
Branch branch = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Branch {
|
||||||
|
string name = 1;
|
||||||
|
string sha = 2;
|
||||||
|
Commit commit = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ListCommitTagsRequest {
|
||||||
|
enum SortOption {
|
||||||
|
Default = 0;
|
||||||
|
Name = 1;
|
||||||
|
Date = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
string repo_uid = 1;
|
||||||
|
bool include_commit = 2;
|
||||||
|
string query = 3;
|
||||||
|
SortOption sort = 4;
|
||||||
|
SortOrder order = 5;
|
||||||
|
int32 page = 6;
|
||||||
|
int32 pageSize = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ListCommitTagsResponse {
|
||||||
|
CommitTag tag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CommitTag {
|
||||||
|
string name = 1;
|
||||||
|
string sha = 2;
|
||||||
|
bool is_annotated = 3;
|
||||||
|
string title = 4;
|
||||||
|
string message = 5;
|
||||||
|
Signature tagger = 6;
|
||||||
|
Commit commit = 7;
|
||||||
|
}
|
@ -13,8 +13,6 @@ service RepositoryService {
|
|||||||
rpc GetSubmodule(GetSubmoduleRequest) returns (GetSubmoduleResponse);
|
rpc GetSubmodule(GetSubmoduleRequest) returns (GetSubmoduleResponse);
|
||||||
rpc GetBlob(GetBlobRequest) returns (GetBlobResponse);
|
rpc GetBlob(GetBlobRequest) returns (GetBlobResponse);
|
||||||
rpc ListCommits(ListCommitsRequest) returns (stream ListCommitsResponse);
|
rpc ListCommits(ListCommitsRequest) returns (stream ListCommitsResponse);
|
||||||
rpc ListBranches(ListBranchesRequest) returns (stream ListBranchesResponse);
|
|
||||||
rpc ListCommitTags(ListCommitTagsRequest) returns (stream ListCommitTagsResponse);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message CreateRepositoryRequest {
|
message CreateRepositoryRequest {
|
||||||
@ -96,32 +94,6 @@ message ListCommitsResponseHeader {
|
|||||||
int64 total_count = 1;
|
int64 total_count = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ListBranchesRequest {
|
|
||||||
enum SortOption {
|
|
||||||
Default = 0;
|
|
||||||
Name = 1;
|
|
||||||
Date = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
string repo_uid = 1;
|
|
||||||
bool include_commit = 2;
|
|
||||||
string query = 3;
|
|
||||||
SortOption sort = 4;
|
|
||||||
SortOrder order = 5;
|
|
||||||
int32 page = 6;
|
|
||||||
int32 pageSize = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
message ListBranchesResponse {
|
|
||||||
Branch branch = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Branch {
|
|
||||||
string name = 1;
|
|
||||||
string sha = 2;
|
|
||||||
Commit commit = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message GetBlobRequest {
|
message GetBlobRequest {
|
||||||
string repo_uid = 1;
|
string repo_uid = 1;
|
||||||
string sha = 2;
|
string sha = 2;
|
||||||
@ -151,52 +123,4 @@ message GetSubmoduleResponse {
|
|||||||
message Submodule {
|
message Submodule {
|
||||||
string name = 1;
|
string name = 1;
|
||||||
string url = 2;
|
string url = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ListCommitTagsRequest {
|
|
||||||
enum SortOption {
|
|
||||||
Default = 0;
|
|
||||||
Name = 1;
|
|
||||||
Date = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
string repo_uid = 1;
|
|
||||||
bool include_commit = 2;
|
|
||||||
string query = 3;
|
|
||||||
SortOption sort = 4;
|
|
||||||
SortOrder order = 5;
|
|
||||||
int32 page = 6;
|
|
||||||
int32 pageSize = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
message ListCommitTagsResponse {
|
|
||||||
CommitTag tag = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message CommitTag {
|
|
||||||
string name = 1;
|
|
||||||
string sha = 2;
|
|
||||||
bool is_annotated = 3;
|
|
||||||
string title = 4;
|
|
||||||
string message = 5;
|
|
||||||
Signature tagger = 6;
|
|
||||||
Commit commit = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Commit {
|
|
||||||
string sha = 1;
|
|
||||||
string title = 2;
|
|
||||||
string message = 3;
|
|
||||||
Signature author = 4;
|
|
||||||
Signature committer = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Signature {
|
|
||||||
Identity identity = 1;
|
|
||||||
int64 when = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Identity {
|
|
||||||
string name = 1;
|
|
||||||
string email = 2;
|
|
||||||
}
|
|
@ -23,4 +23,22 @@ enum SortOrder {
|
|||||||
Default = 0;
|
Default = 0;
|
||||||
Asc = 1;
|
Asc = 1;
|
||||||
Desc = 2;
|
Desc = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message Commit {
|
||||||
|
string sha = 1;
|
||||||
|
string title = 2;
|
||||||
|
string message = 3;
|
||||||
|
Signature author = 4;
|
||||||
|
Signature committer = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Signature {
|
||||||
|
Identity identity = 1;
|
||||||
|
int64 when = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Identity {
|
||||||
|
string name = 1;
|
||||||
|
string email = 2;
|
||||||
|
}
|
||||||
|
@ -79,7 +79,7 @@ func (c *Client) CreateRepository(ctx context.Context,
|
|||||||
|
|
||||||
_, err = stream.CloseAndRecv()
|
_, err = stream.CloseAndRecv()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, processRPCErrorf(err, "failed to create repo on server (uid: '%s')", uid)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Ctx(ctx).Info().Msgf("completed git repo setup.")
|
log.Ctx(ctx).Info().Msgf("completed git repo setup.")
|
||||||
|
1090
gitrpc/rpc/ref.pb.go
Normal file
1090
gitrpc/rpc/ref.pb.go
Normal file
File diff suppressed because it is too large
Load Diff
268
gitrpc/rpc/ref_grpc.pb.go
Normal file
268
gitrpc/rpc/ref_grpc.pb.go
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// - protoc-gen-go-grpc v1.2.0
|
||||||
|
// - protoc v3.21.7
|
||||||
|
// source: ref.proto
|
||||||
|
|
||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
codes "google.golang.org/grpc/codes"
|
||||||
|
status "google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
// Requires gRPC-Go v1.32.0 or later.
|
||||||
|
const _ = grpc.SupportPackageIsVersion7
|
||||||
|
|
||||||
|
// ReferenceServiceClient is the client API for ReferenceService service.
|
||||||
|
//
|
||||||
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||||
|
type ReferenceServiceClient interface {
|
||||||
|
CreateBranch(ctx context.Context, in *CreateBranchRequest, opts ...grpc.CallOption) (*CreateBranchResponse, error)
|
||||||
|
DeleteBranch(ctx context.Context, in *DeleteBranchRequest, opts ...grpc.CallOption) (*DeleteBranchResponse, error)
|
||||||
|
ListBranches(ctx context.Context, in *ListBranchesRequest, opts ...grpc.CallOption) (ReferenceService_ListBranchesClient, error)
|
||||||
|
ListCommitTags(ctx context.Context, in *ListCommitTagsRequest, opts ...grpc.CallOption) (ReferenceService_ListCommitTagsClient, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type referenceServiceClient struct {
|
||||||
|
cc grpc.ClientConnInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewReferenceServiceClient(cc grpc.ClientConnInterface) ReferenceServiceClient {
|
||||||
|
return &referenceServiceClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *referenceServiceClient) CreateBranch(ctx context.Context, in *CreateBranchRequest, opts ...grpc.CallOption) (*CreateBranchResponse, error) {
|
||||||
|
out := new(CreateBranchResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/rpc.ReferenceService/CreateBranch", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *referenceServiceClient) DeleteBranch(ctx context.Context, in *DeleteBranchRequest, opts ...grpc.CallOption) (*DeleteBranchResponse, error) {
|
||||||
|
out := new(DeleteBranchResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/rpc.ReferenceService/DeleteBranch", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *referenceServiceClient) ListBranches(ctx context.Context, in *ListBranchesRequest, opts ...grpc.CallOption) (ReferenceService_ListBranchesClient, error) {
|
||||||
|
stream, err := c.cc.NewStream(ctx, &ReferenceService_ServiceDesc.Streams[0], "/rpc.ReferenceService/ListBranches", opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
x := &referenceServiceListBranchesClient{stream}
|
||||||
|
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := x.ClientStream.CloseSend(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return x, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReferenceService_ListBranchesClient interface {
|
||||||
|
Recv() (*ListBranchesResponse, error)
|
||||||
|
grpc.ClientStream
|
||||||
|
}
|
||||||
|
|
||||||
|
type referenceServiceListBranchesClient struct {
|
||||||
|
grpc.ClientStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *referenceServiceListBranchesClient) Recv() (*ListBranchesResponse, error) {
|
||||||
|
m := new(ListBranchesResponse)
|
||||||
|
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *referenceServiceClient) ListCommitTags(ctx context.Context, in *ListCommitTagsRequest, opts ...grpc.CallOption) (ReferenceService_ListCommitTagsClient, error) {
|
||||||
|
stream, err := c.cc.NewStream(ctx, &ReferenceService_ServiceDesc.Streams[1], "/rpc.ReferenceService/ListCommitTags", opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
x := &referenceServiceListCommitTagsClient{stream}
|
||||||
|
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := x.ClientStream.CloseSend(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return x, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReferenceService_ListCommitTagsClient interface {
|
||||||
|
Recv() (*ListCommitTagsResponse, error)
|
||||||
|
grpc.ClientStream
|
||||||
|
}
|
||||||
|
|
||||||
|
type referenceServiceListCommitTagsClient struct {
|
||||||
|
grpc.ClientStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *referenceServiceListCommitTagsClient) Recv() (*ListCommitTagsResponse, error) {
|
||||||
|
m := new(ListCommitTagsResponse)
|
||||||
|
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReferenceServiceServer is the server API for ReferenceService service.
|
||||||
|
// All implementations must embed UnimplementedReferenceServiceServer
|
||||||
|
// for forward compatibility
|
||||||
|
type ReferenceServiceServer interface {
|
||||||
|
CreateBranch(context.Context, *CreateBranchRequest) (*CreateBranchResponse, error)
|
||||||
|
DeleteBranch(context.Context, *DeleteBranchRequest) (*DeleteBranchResponse, error)
|
||||||
|
ListBranches(*ListBranchesRequest, ReferenceService_ListBranchesServer) error
|
||||||
|
ListCommitTags(*ListCommitTagsRequest, ReferenceService_ListCommitTagsServer) error
|
||||||
|
mustEmbedUnimplementedReferenceServiceServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnimplementedReferenceServiceServer must be embedded to have forward compatible implementations.
|
||||||
|
type UnimplementedReferenceServiceServer struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (UnimplementedReferenceServiceServer) CreateBranch(context.Context, *CreateBranchRequest) (*CreateBranchResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method CreateBranch not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedReferenceServiceServer) DeleteBranch(context.Context, *DeleteBranchRequest) (*DeleteBranchResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method DeleteBranch not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedReferenceServiceServer) ListBranches(*ListBranchesRequest, ReferenceService_ListBranchesServer) error {
|
||||||
|
return status.Errorf(codes.Unimplemented, "method ListBranches not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedReferenceServiceServer) ListCommitTags(*ListCommitTagsRequest, ReferenceService_ListCommitTagsServer) error {
|
||||||
|
return status.Errorf(codes.Unimplemented, "method ListCommitTags not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedReferenceServiceServer) mustEmbedUnimplementedReferenceServiceServer() {}
|
||||||
|
|
||||||
|
// UnsafeReferenceServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||||
|
// Use of this interface is not recommended, as added methods to ReferenceServiceServer will
|
||||||
|
// result in compilation errors.
|
||||||
|
type UnsafeReferenceServiceServer interface {
|
||||||
|
mustEmbedUnimplementedReferenceServiceServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterReferenceServiceServer(s grpc.ServiceRegistrar, srv ReferenceServiceServer) {
|
||||||
|
s.RegisterService(&ReferenceService_ServiceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _ReferenceService_CreateBranch_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(CreateBranchRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(ReferenceServiceServer).CreateBranch(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/rpc.ReferenceService/CreateBranch",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(ReferenceServiceServer).CreateBranch(ctx, req.(*CreateBranchRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _ReferenceService_DeleteBranch_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(DeleteBranchRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(ReferenceServiceServer).DeleteBranch(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/rpc.ReferenceService/DeleteBranch",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(ReferenceServiceServer).DeleteBranch(ctx, req.(*DeleteBranchRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _ReferenceService_ListBranches_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||||
|
m := new(ListBranchesRequest)
|
||||||
|
if err := stream.RecvMsg(m); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return srv.(ReferenceServiceServer).ListBranches(m, &referenceServiceListBranchesServer{stream})
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReferenceService_ListBranchesServer interface {
|
||||||
|
Send(*ListBranchesResponse) error
|
||||||
|
grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
type referenceServiceListBranchesServer struct {
|
||||||
|
grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *referenceServiceListBranchesServer) Send(m *ListBranchesResponse) error {
|
||||||
|
return x.ServerStream.SendMsg(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _ReferenceService_ListCommitTags_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||||
|
m := new(ListCommitTagsRequest)
|
||||||
|
if err := stream.RecvMsg(m); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return srv.(ReferenceServiceServer).ListCommitTags(m, &referenceServiceListCommitTagsServer{stream})
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReferenceService_ListCommitTagsServer interface {
|
||||||
|
Send(*ListCommitTagsResponse) error
|
||||||
|
grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
type referenceServiceListCommitTagsServer struct {
|
||||||
|
grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *referenceServiceListCommitTagsServer) Send(m *ListCommitTagsResponse) error {
|
||||||
|
return x.ServerStream.SendMsg(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReferenceService_ServiceDesc is the grpc.ServiceDesc for ReferenceService service.
|
||||||
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
|
// and not to be introspected or modified (even as a copy)
|
||||||
|
var ReferenceService_ServiceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "rpc.ReferenceService",
|
||||||
|
HandlerType: (*ReferenceServiceServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "CreateBranch",
|
||||||
|
Handler: _ReferenceService_CreateBranch_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "DeleteBranch",
|
||||||
|
Handler: _ReferenceService_DeleteBranch_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{
|
||||||
|
{
|
||||||
|
StreamName: "ListBranches",
|
||||||
|
Handler: _ReferenceService_ListBranches_Handler,
|
||||||
|
ServerStreams: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StreamName: "ListCommitTags",
|
||||||
|
Handler: _ReferenceService_ListCommitTags_Handler,
|
||||||
|
ServerStreams: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Metadata: "ref.proto",
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -28,8 +28,6 @@ type RepositoryServiceClient interface {
|
|||||||
GetSubmodule(ctx context.Context, in *GetSubmoduleRequest, opts ...grpc.CallOption) (*GetSubmoduleResponse, error)
|
GetSubmodule(ctx context.Context, in *GetSubmoduleRequest, opts ...grpc.CallOption) (*GetSubmoduleResponse, error)
|
||||||
GetBlob(ctx context.Context, in *GetBlobRequest, opts ...grpc.CallOption) (*GetBlobResponse, error)
|
GetBlob(ctx context.Context, in *GetBlobRequest, opts ...grpc.CallOption) (*GetBlobResponse, error)
|
||||||
ListCommits(ctx context.Context, in *ListCommitsRequest, opts ...grpc.CallOption) (RepositoryService_ListCommitsClient, error)
|
ListCommits(ctx context.Context, in *ListCommitsRequest, opts ...grpc.CallOption) (RepositoryService_ListCommitsClient, error)
|
||||||
ListBranches(ctx context.Context, in *ListBranchesRequest, opts ...grpc.CallOption) (RepositoryService_ListBranchesClient, error)
|
|
||||||
ListCommitTags(ctx context.Context, in *ListCommitTagsRequest, opts ...grpc.CallOption) (RepositoryService_ListCommitTagsClient, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type repositoryServiceClient struct {
|
type repositoryServiceClient struct {
|
||||||
@ -165,70 +163,6 @@ func (x *repositoryServiceListCommitsClient) Recv() (*ListCommitsResponse, error
|
|||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *repositoryServiceClient) ListBranches(ctx context.Context, in *ListBranchesRequest, opts ...grpc.CallOption) (RepositoryService_ListBranchesClient, error) {
|
|
||||||
stream, err := c.cc.NewStream(ctx, &RepositoryService_ServiceDesc.Streams[3], "/rpc.RepositoryService/ListBranches", opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
x := &repositoryServiceListBranchesClient{stream}
|
|
||||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := x.ClientStream.CloseSend(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return x, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type RepositoryService_ListBranchesClient interface {
|
|
||||||
Recv() (*ListBranchesResponse, error)
|
|
||||||
grpc.ClientStream
|
|
||||||
}
|
|
||||||
|
|
||||||
type repositoryServiceListBranchesClient struct {
|
|
||||||
grpc.ClientStream
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *repositoryServiceListBranchesClient) Recv() (*ListBranchesResponse, error) {
|
|
||||||
m := new(ListBranchesResponse)
|
|
||||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *repositoryServiceClient) ListCommitTags(ctx context.Context, in *ListCommitTagsRequest, opts ...grpc.CallOption) (RepositoryService_ListCommitTagsClient, error) {
|
|
||||||
stream, err := c.cc.NewStream(ctx, &RepositoryService_ServiceDesc.Streams[4], "/rpc.RepositoryService/ListCommitTags", opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
x := &repositoryServiceListCommitTagsClient{stream}
|
|
||||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := x.ClientStream.CloseSend(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return x, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type RepositoryService_ListCommitTagsClient interface {
|
|
||||||
Recv() (*ListCommitTagsResponse, error)
|
|
||||||
grpc.ClientStream
|
|
||||||
}
|
|
||||||
|
|
||||||
type repositoryServiceListCommitTagsClient struct {
|
|
||||||
grpc.ClientStream
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *repositoryServiceListCommitTagsClient) Recv() (*ListCommitTagsResponse, error) {
|
|
||||||
m := new(ListCommitTagsResponse)
|
|
||||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RepositoryServiceServer is the server API for RepositoryService service.
|
// RepositoryServiceServer is the server API for RepositoryService service.
|
||||||
// All implementations must embed UnimplementedRepositoryServiceServer
|
// All implementations must embed UnimplementedRepositoryServiceServer
|
||||||
// for forward compatibility
|
// for forward compatibility
|
||||||
@ -239,8 +173,6 @@ type RepositoryServiceServer interface {
|
|||||||
GetSubmodule(context.Context, *GetSubmoduleRequest) (*GetSubmoduleResponse, error)
|
GetSubmodule(context.Context, *GetSubmoduleRequest) (*GetSubmoduleResponse, error)
|
||||||
GetBlob(context.Context, *GetBlobRequest) (*GetBlobResponse, error)
|
GetBlob(context.Context, *GetBlobRequest) (*GetBlobResponse, error)
|
||||||
ListCommits(*ListCommitsRequest, RepositoryService_ListCommitsServer) error
|
ListCommits(*ListCommitsRequest, RepositoryService_ListCommitsServer) error
|
||||||
ListBranches(*ListBranchesRequest, RepositoryService_ListBranchesServer) error
|
|
||||||
ListCommitTags(*ListCommitTagsRequest, RepositoryService_ListCommitTagsServer) error
|
|
||||||
mustEmbedUnimplementedRepositoryServiceServer()
|
mustEmbedUnimplementedRepositoryServiceServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,12 +198,6 @@ func (UnimplementedRepositoryServiceServer) GetBlob(context.Context, *GetBlobReq
|
|||||||
func (UnimplementedRepositoryServiceServer) ListCommits(*ListCommitsRequest, RepositoryService_ListCommitsServer) error {
|
func (UnimplementedRepositoryServiceServer) ListCommits(*ListCommitsRequest, RepositoryService_ListCommitsServer) error {
|
||||||
return status.Errorf(codes.Unimplemented, "method ListCommits not implemented")
|
return status.Errorf(codes.Unimplemented, "method ListCommits not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedRepositoryServiceServer) ListBranches(*ListBranchesRequest, RepositoryService_ListBranchesServer) error {
|
|
||||||
return status.Errorf(codes.Unimplemented, "method ListBranches not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedRepositoryServiceServer) ListCommitTags(*ListCommitTagsRequest, RepositoryService_ListCommitTagsServer) error {
|
|
||||||
return status.Errorf(codes.Unimplemented, "method ListCommitTags not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedRepositoryServiceServer) mustEmbedUnimplementedRepositoryServiceServer() {}
|
func (UnimplementedRepositoryServiceServer) mustEmbedUnimplementedRepositoryServiceServer() {}
|
||||||
|
|
||||||
// UnsafeRepositoryServiceServer may be embedded to opt out of forward compatibility for this service.
|
// UnsafeRepositoryServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||||
@ -407,48 +333,6 @@ func (x *repositoryServiceListCommitsServer) Send(m *ListCommitsResponse) error
|
|||||||
return x.ServerStream.SendMsg(m)
|
return x.ServerStream.SendMsg(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _RepositoryService_ListBranches_Handler(srv interface{}, stream grpc.ServerStream) error {
|
|
||||||
m := new(ListBranchesRequest)
|
|
||||||
if err := stream.RecvMsg(m); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return srv.(RepositoryServiceServer).ListBranches(m, &repositoryServiceListBranchesServer{stream})
|
|
||||||
}
|
|
||||||
|
|
||||||
type RepositoryService_ListBranchesServer interface {
|
|
||||||
Send(*ListBranchesResponse) error
|
|
||||||
grpc.ServerStream
|
|
||||||
}
|
|
||||||
|
|
||||||
type repositoryServiceListBranchesServer struct {
|
|
||||||
grpc.ServerStream
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *repositoryServiceListBranchesServer) Send(m *ListBranchesResponse) error {
|
|
||||||
return x.ServerStream.SendMsg(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _RepositoryService_ListCommitTags_Handler(srv interface{}, stream grpc.ServerStream) error {
|
|
||||||
m := new(ListCommitTagsRequest)
|
|
||||||
if err := stream.RecvMsg(m); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return srv.(RepositoryServiceServer).ListCommitTags(m, &repositoryServiceListCommitTagsServer{stream})
|
|
||||||
}
|
|
||||||
|
|
||||||
type RepositoryService_ListCommitTagsServer interface {
|
|
||||||
Send(*ListCommitTagsResponse) error
|
|
||||||
grpc.ServerStream
|
|
||||||
}
|
|
||||||
|
|
||||||
type repositoryServiceListCommitTagsServer struct {
|
|
||||||
grpc.ServerStream
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *repositoryServiceListCommitTagsServer) Send(m *ListCommitTagsResponse) error {
|
|
||||||
return x.ServerStream.SendMsg(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RepositoryService_ServiceDesc is the grpc.ServiceDesc for RepositoryService service.
|
// RepositoryService_ServiceDesc is the grpc.ServiceDesc for RepositoryService service.
|
||||||
// It's only intended for direct use with grpc.RegisterService,
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
// and not to be introspected or modified (even as a copy)
|
// and not to be introspected or modified (even as a copy)
|
||||||
@ -485,16 +369,6 @@ var RepositoryService_ServiceDesc = grpc.ServiceDesc{
|
|||||||
Handler: _RepositoryService_ListCommits_Handler,
|
Handler: _RepositoryService_ListCommits_Handler,
|
||||||
ServerStreams: true,
|
ServerStreams: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
StreamName: "ListBranches",
|
|
||||||
Handler: _RepositoryService_ListBranches_Handler,
|
|
||||||
ServerStreams: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
StreamName: "ListCommitTags",
|
|
||||||
Handler: _RepositoryService_ListCommitTags_Handler,
|
|
||||||
ServerStreams: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Metadata: "repo.proto",
|
Metadata: "repo.proto",
|
||||||
}
|
}
|
||||||
|
@ -251,6 +251,195 @@ func (x *Chunk) GetData() []byte {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Commit struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Sha string `protobuf:"bytes,1,opt,name=sha,proto3" json:"sha,omitempty"`
|
||||||
|
Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
|
||||||
|
Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"`
|
||||||
|
Author *Signature `protobuf:"bytes,4,opt,name=author,proto3" json:"author,omitempty"`
|
||||||
|
Committer *Signature `protobuf:"bytes,5,opt,name=committer,proto3" json:"committer,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Commit) Reset() {
|
||||||
|
*x = Commit{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_shared_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Commit) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Commit) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *Commit) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_shared_proto_msgTypes[3]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use Commit.ProtoReflect.Descriptor instead.
|
||||||
|
func (*Commit) Descriptor() ([]byte, []int) {
|
||||||
|
return file_shared_proto_rawDescGZIP(), []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Commit) GetSha() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Sha
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Commit) GetTitle() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Title
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Commit) GetMessage() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Message
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Commit) GetAuthor() *Signature {
|
||||||
|
if x != nil {
|
||||||
|
return x.Author
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Commit) GetCommitter() *Signature {
|
||||||
|
if x != nil {
|
||||||
|
return x.Committer
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Signature struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Identity *Identity `protobuf:"bytes,1,opt,name=identity,proto3" json:"identity,omitempty"`
|
||||||
|
When int64 `protobuf:"varint,2,opt,name=when,proto3" json:"when,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Signature) Reset() {
|
||||||
|
*x = Signature{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_shared_proto_msgTypes[4]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Signature) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Signature) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *Signature) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_shared_proto_msgTypes[4]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use Signature.ProtoReflect.Descriptor instead.
|
||||||
|
func (*Signature) Descriptor() ([]byte, []int) {
|
||||||
|
return file_shared_proto_rawDescGZIP(), []int{4}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Signature) GetIdentity() *Identity {
|
||||||
|
if x != nil {
|
||||||
|
return x.Identity
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Signature) GetWhen() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.When
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type Identity struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
|
Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Identity) Reset() {
|
||||||
|
*x = Identity{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_shared_proto_msgTypes[5]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Identity) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Identity) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *Identity) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_shared_proto_msgTypes[5]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use Identity.ProtoReflect.Descriptor instead.
|
||||||
|
func (*Identity) Descriptor() ([]byte, []int) {
|
||||||
|
return file_shared_proto_rawDescGZIP(), []int{5}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Identity) GetName() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Identity) GetEmail() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Email
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
var File_shared_proto protoreflect.FileDescriptor
|
var File_shared_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_shared_proto_rawDesc = []byte{
|
var file_shared_proto_rawDesc = []byte{
|
||||||
@ -267,13 +456,31 @@ var file_shared_proto_rawDesc = []byte{
|
|||||||
0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2d, 0x0a, 0x05, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x12,
|
0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0x2d, 0x0a, 0x05, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x12,
|
||||||
0x10, 0x0a, 0x03, 0x65, 0x6f, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x65, 0x6f,
|
0x10, 0x0a, 0x03, 0x65, 0x6f, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x65, 0x6f,
|
||||||
0x66, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
0x66, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
||||||
0x04, 0x64, 0x61, 0x74, 0x61, 0x2a, 0x2b, 0x0a, 0x09, 0x53, 0x6f, 0x72, 0x74, 0x4f, 0x72, 0x64,
|
0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xa0, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74,
|
||||||
0x65, 0x72, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x10, 0x00, 0x12,
|
0x12, 0x10, 0x0a, 0x03, 0x73, 0x68, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73,
|
||||||
0x07, 0x0a, 0x03, 0x41, 0x73, 0x63, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x65, 0x73, 0x63,
|
0x68, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||||
0x10, 0x02, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73,
|
||||||
0x2f, 0x68, 0x61, 0x72, 0x6e, 0x65, 0x73, 0x73, 0x2f, 0x67, 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73,
|
0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61,
|
||||||
0x2f, 0x67, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2f, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
0x67, 0x65, 0x12, 0x26, 0x0a, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01,
|
||||||
0x74, 0x6f, 0x33,
|
0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75,
|
||||||
|
0x72, 0x65, 0x52, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x12, 0x2c, 0x0a, 0x09, 0x63, 0x6f,
|
||||||
|
0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e,
|
||||||
|
0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x09, 0x63,
|
||||||
|
0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x22, 0x4a, 0x0a, 0x09, 0x53, 0x69, 0x67, 0x6e,
|
||||||
|
0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x29, 0x0a, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74,
|
||||||
|
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x64,
|
||||||
|
0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79,
|
||||||
|
0x12, 0x12, 0x0a, 0x04, 0x77, 0x68, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04,
|
||||||
|
0x77, 0x68, 0x65, 0x6e, 0x22, 0x34, 0x0a, 0x08, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79,
|
||||||
|
0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
|
||||||
|
0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20,
|
||||||
|
0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x2a, 0x2b, 0x0a, 0x09, 0x53, 0x6f,
|
||||||
|
0x72, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x65, 0x66, 0x61, 0x75,
|
||||||
|
0x6c, 0x74, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x73, 0x63, 0x10, 0x01, 0x12, 0x08, 0x0a,
|
||||||
|
0x04, 0x44, 0x65, 0x73, 0x63, 0x10, 0x02, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||||
|
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x72, 0x6e, 0x65, 0x73, 0x73, 0x2f, 0x67, 0x69,
|
||||||
|
0x74, 0x6e, 0x65, 0x73, 0x73, 0x2f, 0x67, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2f, 0x72, 0x70, 0x63,
|
||||||
|
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -289,21 +496,27 @@ func file_shared_proto_rawDescGZIP() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var file_shared_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
var file_shared_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||||
var file_shared_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
var file_shared_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||||
var file_shared_proto_goTypes = []interface{}{
|
var file_shared_proto_goTypes = []interface{}{
|
||||||
(SortOrder)(0), // 0: rpc.SortOrder
|
(SortOrder)(0), // 0: rpc.SortOrder
|
||||||
(*FileUpload)(nil), // 1: rpc.FileUpload
|
(*FileUpload)(nil), // 1: rpc.FileUpload
|
||||||
(*FileUploadHeader)(nil), // 2: rpc.FileUploadHeader
|
(*FileUploadHeader)(nil), // 2: rpc.FileUploadHeader
|
||||||
(*Chunk)(nil), // 3: rpc.Chunk
|
(*Chunk)(nil), // 3: rpc.Chunk
|
||||||
|
(*Commit)(nil), // 4: rpc.Commit
|
||||||
|
(*Signature)(nil), // 5: rpc.Signature
|
||||||
|
(*Identity)(nil), // 6: rpc.Identity
|
||||||
}
|
}
|
||||||
var file_shared_proto_depIdxs = []int32{
|
var file_shared_proto_depIdxs = []int32{
|
||||||
2, // 0: rpc.FileUpload.header:type_name -> rpc.FileUploadHeader
|
2, // 0: rpc.FileUpload.header:type_name -> rpc.FileUploadHeader
|
||||||
3, // 1: rpc.FileUpload.chunk:type_name -> rpc.Chunk
|
3, // 1: rpc.FileUpload.chunk:type_name -> rpc.Chunk
|
||||||
2, // [2:2] is the sub-list for method output_type
|
5, // 2: rpc.Commit.author:type_name -> rpc.Signature
|
||||||
2, // [2:2] is the sub-list for method input_type
|
5, // 3: rpc.Commit.committer:type_name -> rpc.Signature
|
||||||
2, // [2:2] is the sub-list for extension type_name
|
6, // 4: rpc.Signature.identity:type_name -> rpc.Identity
|
||||||
2, // [2:2] is the sub-list for extension extendee
|
5, // [5:5] is the sub-list for method output_type
|
||||||
0, // [0:2] is the sub-list for field type_name
|
5, // [5:5] is the sub-list for method input_type
|
||||||
|
5, // [5:5] is the sub-list for extension type_name
|
||||||
|
5, // [5:5] is the sub-list for extension extendee
|
||||||
|
0, // [0:5] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_shared_proto_init() }
|
func init() { file_shared_proto_init() }
|
||||||
@ -348,6 +561,42 @@ func file_shared_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
file_shared_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Commit); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_shared_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Signature); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_shared_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Identity); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
file_shared_proto_msgTypes[0].OneofWrappers = []interface{}{
|
file_shared_proto_msgTypes[0].OneofWrappers = []interface{}{
|
||||||
(*FileUpload_Header)(nil),
|
(*FileUpload_Header)(nil),
|
||||||
@ -359,7 +608,7 @@ func file_shared_proto_init() {
|
|||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_shared_proto_rawDesc,
|
RawDescriptor: file_shared_proto_rawDesc,
|
||||||
NumEnums: 1,
|
NumEnums: 1,
|
||||||
NumMessages: 3,
|
NumMessages: 6,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
|
@ -5,6 +5,10 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/harness/gitness/gitrpc/internal/gitea"
|
"github.com/harness/gitness/gitrpc/internal/gitea"
|
||||||
"github.com/harness/gitness/gitrpc/internal/service"
|
"github.com/harness/gitness/gitrpc/internal/service"
|
||||||
"github.com/harness/gitness/gitrpc/internal/storage"
|
"github.com/harness/gitness/gitrpc/internal/storage"
|
||||||
@ -16,6 +20,10 @@ import (
|
|||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
repoSubdirName = "repos"
|
||||||
|
)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
*grpc.Server
|
*grpc.Server
|
||||||
Bind string
|
Bind string
|
||||||
@ -23,6 +31,14 @@ type Server struct {
|
|||||||
|
|
||||||
// TODO: this wiring should be done by wire.
|
// TODO: this wiring should be done by wire.
|
||||||
func NewServer(bind string, gitRoot string) (*Server, error) {
|
func NewServer(bind string, gitRoot string) (*Server, error) {
|
||||||
|
// Create repos folder
|
||||||
|
reposRoot := filepath.Join(gitRoot, repoSubdirName)
|
||||||
|
if _, err := os.Stat(reposRoot); errors.Is(err, os.ErrNotExist) {
|
||||||
|
if err = os.MkdirAll(reposRoot, 0o700); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: should be subdir of gitRoot? What is it being used for?
|
// TODO: should be subdir of gitRoot? What is it being used for?
|
||||||
setting.Git.HomePath = "home"
|
setting.Git.HomePath = "home"
|
||||||
adapter, err := gitea.New()
|
adapter, err := gitea.New()
|
||||||
@ -32,16 +48,22 @@ func NewServer(bind string, gitRoot string) (*Server, error) {
|
|||||||
s := grpc.NewServer()
|
s := grpc.NewServer()
|
||||||
store := storage.NewLocalStore()
|
store := storage.NewLocalStore()
|
||||||
// initialize services
|
// initialize services
|
||||||
repoService, err := service.NewRepositoryService(adapter, store, gitRoot)
|
repoService, err := service.NewRepositoryService(adapter, store, reposRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
httpService, err := service.NewHTTPService(adapter, gitRoot)
|
// initialize services
|
||||||
|
refService, err := service.NewReferenceService(adapter, reposRoot)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
httpService, err := service.NewHTTPService(adapter, reposRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// register services
|
// register services
|
||||||
rpc.RegisterRepositoryServiceServer(s, repoService)
|
rpc.RegisterRepositoryServiceServer(s, repoService)
|
||||||
|
rpc.RegisterReferenceServiceServer(s, refService)
|
||||||
rpc.RegisterSmartHTTPServiceServer(s, httpService)
|
rpc.RegisterSmartHTTPServiceServer(s, httpService)
|
||||||
|
|
||||||
return &Server{
|
return &Server{
|
||||||
|
@ -135,7 +135,7 @@ func (c *Client) ServicePack(ctx context.Context, w io.Writer, params *ServicePa
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("PostUploadPack() error receiving stream bytes: %w", err)
|
return processRPCErrorf(err, "PostUploadPack() error receiving stream bytes")
|
||||||
}
|
}
|
||||||
if response.GetData() == nil {
|
if response.GetData() == nil {
|
||||||
return fmt.Errorf("PostUploadPack() data is nil")
|
return fmt.Errorf("PostUploadPack() data is nil")
|
||||||
|
@ -37,7 +37,7 @@ func (c *Client) GetSubmodule(ctx context.Context, params *GetSubmoduleParams) (
|
|||||||
Path: params.Path,
|
Path: params.Path,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, processRPCErrorf(err, "failed to get submodule from server")
|
||||||
}
|
}
|
||||||
if resp.GetSubmodule() == nil {
|
if resp.GetSubmodule() == nil {
|
||||||
return nil, fmt.Errorf("rpc submodule is nil")
|
return nil, fmt.Errorf("rpc submodule is nil")
|
||||||
|
@ -52,7 +52,7 @@ func (c *Client) ListCommitTags(ctx context.Context, params *ListCommitTagsParam
|
|||||||
return nil, ErrNoParamsProvided
|
return nil, ErrNoParamsProvided
|
||||||
}
|
}
|
||||||
|
|
||||||
stream, err := c.repoService.ListCommitTags(ctx, &rpc.ListCommitTagsRequest{
|
stream, err := c.refService.ListCommitTags(ctx, &rpc.ListCommitTagsRequest{
|
||||||
RepoUid: params.RepoUID,
|
RepoUid: params.RepoUID,
|
||||||
IncludeCommit: params.IncludeCommit,
|
IncludeCommit: params.IncludeCommit,
|
||||||
Query: params.Query,
|
Query: params.Query,
|
||||||
@ -77,7 +77,7 @@ func (c *Client) ListCommitTags(ctx context.Context, params *ListCommitTagsParam
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("received unexpected error from rpc: %w", err)
|
return nil, processRPCErrorf(err, "received unexpected error from server")
|
||||||
}
|
}
|
||||||
if next.GetTag() == nil {
|
if next.GetTag() == nil {
|
||||||
return nil, fmt.Errorf("expected tag message")
|
return nil, fmt.Errorf("expected tag message")
|
||||||
@ -92,7 +92,6 @@ func (c *Client) ListCommitTags(ctx context.Context, params *ListCommitTagsParam
|
|||||||
output.Tags = append(output.Tags, *tag)
|
output.Tags = append(output.Tags, *tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: is this needed?
|
|
||||||
err = stream.CloseSend()
|
err = stream.CloseSend()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to close stream")
|
return nil, fmt.Errorf("failed to close stream")
|
||||||
|
@ -88,7 +88,7 @@ func (c *Client) GetTreeNode(ctx context.Context, params *GetTreeNodeParams) (*G
|
|||||||
IncludeLatestCommit: params.IncludeLatestCommit,
|
IncludeLatestCommit: params.IncludeLatestCommit,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, processRPCErrorf(err, "failed to get tree node from server")
|
||||||
}
|
}
|
||||||
|
|
||||||
node, err := mapRPCTreeNode(resp.GetNode())
|
node, err := mapRPCTreeNode(resp.GetNode())
|
||||||
@ -133,7 +133,7 @@ func (c *Client) ListTreeNodes(ctx context.Context, params *ListTreeNodeParams)
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("received unexpected error from rpc: %w", err)
|
return nil, processRPCErrorf(err, "received unexpected error from server")
|
||||||
}
|
}
|
||||||
|
|
||||||
var node TreeNode
|
var node TreeNode
|
||||||
|
79
internal/api/controller/repo/create_branch.go
Normal file
79
internal/api/controller/repo/create_branch.go
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// 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 repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/harness/gitness/gitrpc"
|
||||||
|
apiauth "github.com/harness/gitness/internal/api/auth"
|
||||||
|
"github.com/harness/gitness/internal/api/usererror"
|
||||||
|
"github.com/harness/gitness/internal/auth"
|
||||||
|
"github.com/harness/gitness/types/check"
|
||||||
|
"github.com/harness/gitness/types/enum"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateBranchInput used for branch creation apis.
|
||||||
|
type CreateBranchInput struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// Target is the commit (or points to the commit) the new branch will be pointing to.
|
||||||
|
// If no target is provided, the branch points to the same commit as the default branch of the repo.
|
||||||
|
Target *string `json:"target"`
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Creates a new branch for a repo.
|
||||||
|
*/
|
||||||
|
func (c *Controller) CreateBranch(ctx context.Context, session *auth.Session,
|
||||||
|
repoRef string, in *CreateBranchInput) (*Branch, error) {
|
||||||
|
repo, err := findRepoFromRef(ctx, c.repoStore, repoRef)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoEdit, false); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// set target to default branch in case no target was provided
|
||||||
|
if in.Target == nil || *in.Target == "" {
|
||||||
|
in.Target = &repo.DefaultBranch
|
||||||
|
}
|
||||||
|
|
||||||
|
err = checkBranchName(in.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rpcOut, err := c.gitRPCClient.CreateBranch(ctx, &gitrpc.CreateBranchParams{
|
||||||
|
RepoUID: repo.GitUID,
|
||||||
|
BranchName: in.Name,
|
||||||
|
Target: *in.Target,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
branch, err := mapBranch(rpcOut.Branch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to map branch: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &branch, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkBranchName does some basic branch validation
|
||||||
|
// We only ensure there are no control characters, the rest is up to git.
|
||||||
|
// TODO: Do we need some more validation here?
|
||||||
|
func checkBranchName(name string) error {
|
||||||
|
// fail fast on missing name
|
||||||
|
if len(name) == 0 {
|
||||||
|
return usererror.ErrBadRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
return check.ForControlCharacters(name)
|
||||||
|
}
|
47
internal/api/controller/repo/delete_branch.go
Normal file
47
internal/api/controller/repo/delete_branch.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// 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 repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/harness/gitness/gitrpc"
|
||||||
|
apiauth "github.com/harness/gitness/internal/api/auth"
|
||||||
|
"github.com/harness/gitness/internal/api/usererror"
|
||||||
|
"github.com/harness/gitness/internal/auth"
|
||||||
|
"github.com/harness/gitness/types/enum"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DeletePath deletes a repo branch.
|
||||||
|
*/
|
||||||
|
func (c *Controller) DeleteBranch(ctx context.Context, session *auth.Session, repoRef string, branchName string) error {
|
||||||
|
repo, err := findRepoFromRef(ctx, c.repoStore, repoRef)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoEdit, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure user isn't deleting the default branch
|
||||||
|
// ASSUMPTION: lower layer calls explicit branch api
|
||||||
|
// and 'refs/heads/branch1' would fail if 'branch1' exists.
|
||||||
|
// TODO: Add functional test to ensure the scenario is covered!
|
||||||
|
if branchName == repo.DefaultBranch {
|
||||||
|
return usererror.ErrDefaultBranchCantBeDeleted
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.gitRPCClient.DeleteBranch(ctx, &gitrpc.DeleteBranchParams{
|
||||||
|
RepoUID: repo.GitUID,
|
||||||
|
BranchName: branchName,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -13,10 +13,8 @@ import (
|
|||||||
"github.com/harness/gitness/gitrpc"
|
"github.com/harness/gitness/gitrpc"
|
||||||
|
|
||||||
apiauth "github.com/harness/gitness/internal/api/auth"
|
apiauth "github.com/harness/gitness/internal/api/auth"
|
||||||
"github.com/harness/gitness/internal/api/usererror"
|
|
||||||
"github.com/harness/gitness/internal/auth"
|
"github.com/harness/gitness/internal/auth"
|
||||||
"github.com/harness/gitness/types/enum"
|
"github.com/harness/gitness/types/enum"
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -125,7 +123,6 @@ func (c *Controller) GetContent(ctx context.Context, session *auth.Session, repo
|
|||||||
gitRef = repo.DefaultBranch
|
gitRef = repo.DefaultBranch
|
||||||
}
|
}
|
||||||
|
|
||||||
log := log.Ctx(ctx)
|
|
||||||
treeNodeOutput, err := c.gitRPCClient.GetTreeNode(ctx, &gitrpc.GetTreeNodeParams{
|
treeNodeOutput, err := c.gitRPCClient.GetTreeNode(ctx, &gitrpc.GetTreeNodeParams{
|
||||||
RepoUID: repo.GitUID,
|
RepoUID: repo.GitUID,
|
||||||
GitREF: gitRef,
|
GitREF: gitRef,
|
||||||
@ -133,11 +130,7 @@ func (c *Controller) GetContent(ctx context.Context, session *auth.Session, repo
|
|||||||
IncludeLatestCommit: includeLatestCommit,
|
IncludeLatestCommit: includeLatestCommit,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: this should only return not found if it's an actual not found error.
|
return nil, err
|
||||||
// This requires gitrpc to also return notfound though!
|
|
||||||
log.Debug().Err(err).
|
|
||||||
Msgf("unable to find content for repo '%s', gitRef '%s' and path '%s'", repoRef, gitRef, repoPath)
|
|
||||||
return nil, usererror.ErrNotFound
|
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := mapToContentInfo(&treeNodeOutput.Node, treeNodeOutput.Commit)
|
info, err := mapToContentInfo(&treeNodeOutput.Node, treeNodeOutput.Commit)
|
||||||
|
44
internal/api/handler/repo/create_branch.go
Normal file
44
internal/api/handler/repo/create_branch.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// 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 repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/harness/gitness/internal/api/controller/repo"
|
||||||
|
"github.com/harness/gitness/internal/api/render"
|
||||||
|
"github.com/harness/gitness/internal/api/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Writes json-encoded branch information to the http response body.
|
||||||
|
*/
|
||||||
|
func HandleCreateBranch(repoCtrl *repo.Controller) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
session, _ := request.AuthSessionFrom(ctx)
|
||||||
|
repoRef, err := request.GetRepoRefFromPath(r)
|
||||||
|
if err != nil {
|
||||||
|
render.TranslatedUserError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
in := new(repo.CreateBranchInput)
|
||||||
|
err = json.NewDecoder(r.Body).Decode(in)
|
||||||
|
if err != nil {
|
||||||
|
render.BadRequestf(w, "Invalid request body: %s.", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
branch, err := repoCtrl.CreateBranch(ctx, session, repoRef, in)
|
||||||
|
if err != nil {
|
||||||
|
render.TranslatedUserError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
render.JSON(w, http.StatusOK, branch)
|
||||||
|
}
|
||||||
|
}
|
40
internal/api/handler/repo/delete_branch.go
Normal file
40
internal/api/handler/repo/delete_branch.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// 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 repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/harness/gitness/internal/api/controller/repo"
|
||||||
|
"github.com/harness/gitness/internal/api/render"
|
||||||
|
"github.com/harness/gitness/internal/api/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Deletes a given branch.
|
||||||
|
*/
|
||||||
|
func HandleDeleteBranch(repoCtrl *repo.Controller) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
session, _ := request.AuthSessionFrom(ctx)
|
||||||
|
repoRef, err := request.GetRepoRefFromPath(r)
|
||||||
|
if err != nil {
|
||||||
|
render.TranslatedUserError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
branchName, err := request.GetRemainderFromPath(r)
|
||||||
|
if err != nil {
|
||||||
|
render.TranslatedUserError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = repoCtrl.DeleteBranch(ctx, session, repoRef, branchName)
|
||||||
|
if err != nil {
|
||||||
|
render.TranslatedUserError(w, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
render.DeleteSuccessful(w)
|
||||||
|
}
|
||||||
|
}
|
@ -27,6 +27,7 @@ func init() {
|
|||||||
|
|
||||||
// TranslatedUserError writes the translated user error of the provided error.
|
// TranslatedUserError writes the translated user error of the provided error.
|
||||||
func TranslatedUserError(w http.ResponseWriter, err error) {
|
func TranslatedUserError(w http.ResponseWriter, err error) {
|
||||||
|
log.Warn().Msgf("operation resulted in user facing error. Internal details: %s", err)
|
||||||
UserError(w, usererror.Translate(err))
|
UserError(w, usererror.Translate(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +111,11 @@ func GetOptionalRemainderFromPath(r *http.Request) string {
|
|||||||
return PathParamOrEmpty(r, PathParamRemainder)
|
return PathParamOrEmpty(r, PathParamRemainder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRemainderFromPath returns the remainder ("*") from the path or an an error if it doesn't exist.
|
||||||
|
func GetRemainderFromPath(r *http.Request) (string, error) {
|
||||||
|
return PathParamOrError(r, PathParamRemainder)
|
||||||
|
}
|
||||||
|
|
||||||
// ParseQuery extracts the query parameter from the url.
|
// ParseQuery extracts the query parameter from the url.
|
||||||
func ParseQuery(r *http.Request) string {
|
func ParseQuery(r *http.Request) string {
|
||||||
return r.FormValue(QueryParamQuery)
|
return r.FormValue(QueryParamQuery)
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/harness/gitness/gitrpc"
|
||||||
apiauth "github.com/harness/gitness/internal/api/auth"
|
apiauth "github.com/harness/gitness/internal/api/auth"
|
||||||
"github.com/harness/gitness/internal/store"
|
"github.com/harness/gitness/internal/store"
|
||||||
"github.com/harness/gitness/types/check"
|
"github.com/harness/gitness/types/check"
|
||||||
@ -47,6 +48,14 @@ func Translate(err error) *Error {
|
|||||||
case errors.Is(err, store.ErrSpaceWithChildsCantBeDeleted):
|
case errors.Is(err, store.ErrSpaceWithChildsCantBeDeleted):
|
||||||
return ErrSpaceWithChildsCantBeDeleted
|
return ErrSpaceWithChildsCantBeDeleted
|
||||||
|
|
||||||
|
// gitrpc errors
|
||||||
|
case errors.Is(err, gitrpc.ErrAlreadyExists):
|
||||||
|
return ErrDuplicate
|
||||||
|
case errors.Is(err, gitrpc.ErrInvalidArgument):
|
||||||
|
return ErrBadRequest
|
||||||
|
case errors.Is(err, gitrpc.ErrNotFound):
|
||||||
|
return ErrNotFound
|
||||||
|
|
||||||
// unknown error
|
// unknown error
|
||||||
default:
|
default:
|
||||||
log.Warn().Msgf("Unable to translate error: %s", err)
|
log.Warn().Msgf("Unable to translate error: %s", err)
|
||||||
|
@ -29,7 +29,7 @@ var (
|
|||||||
ErrNoChange = New(http.StatusBadRequest, "No Change")
|
ErrNoChange = New(http.StatusBadRequest, "No Change")
|
||||||
|
|
||||||
// ErrDuplicate is returned when a resource already exits.
|
// ErrDuplicate is returned when a resource already exits.
|
||||||
ErrDuplicate = New(http.StatusBadRequest, "Resource already exists")
|
ErrDuplicate = New(http.StatusConflict, "Resource already exists")
|
||||||
|
|
||||||
// ErrPrimaryPathCantBeDeleted is returned when trying to delete a primary path.
|
// ErrPrimaryPathCantBeDeleted is returned when trying to delete a primary path.
|
||||||
ErrPrimaryPathCantBeDeleted = New(http.StatusBadRequest, "The primary path of an object can't be deleted")
|
ErrPrimaryPathCantBeDeleted = New(http.StatusBadRequest, "The primary path of an object can't be deleted")
|
||||||
@ -44,6 +44,9 @@ var (
|
|||||||
// still has child resources.
|
// still has child resources.
|
||||||
ErrSpaceWithChildsCantBeDeleted = New(http.StatusBadRequest,
|
ErrSpaceWithChildsCantBeDeleted = New(http.StatusBadRequest,
|
||||||
"Space can't be deleted as it still contains child resources")
|
"Space can't be deleted as it still contains child resources")
|
||||||
|
|
||||||
|
// ErrDefaultBranchCantBeDeleted is returned if the user tries to delete the default branch of a repository.
|
||||||
|
ErrDefaultBranchCantBeDeleted = New(http.StatusBadRequest, "The default branch of a repository can't be deleted")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Error represents a json-encoded API error.
|
// Error represents a json-encoded API error.
|
||||||
|
@ -168,6 +168,8 @@ func setupRepos(r chi.Router, repoCtrl *repo.Controller) {
|
|||||||
// branch operations
|
// branch operations
|
||||||
r.Route("/branches", func(r chi.Router) {
|
r.Route("/branches", func(r chi.Router) {
|
||||||
r.Get("/", handlerrepo.HandleListBranches(repoCtrl))
|
r.Get("/", handlerrepo.HandleListBranches(repoCtrl))
|
||||||
|
r.Post("/", handlerrepo.HandleCreateBranch(repoCtrl))
|
||||||
|
r.Delete("/*", handlerrepo.HandleDeleteBranch(repoCtrl))
|
||||||
})
|
})
|
||||||
|
|
||||||
// tags operations
|
// tags operations
|
||||||
|
@ -37,19 +37,24 @@ func offset(page, size int) int {
|
|||||||
return page * size
|
return page * size
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logs the error and message, returns either the original error or a store equivalent if possible.
|
// Logs the error and message, returns either the provided message or a gitrpc equivalent if possible.
|
||||||
|
// Always logs the full message with error as warning.
|
||||||
func processSQLErrorf(err error, format string, args ...interface{}) error {
|
func processSQLErrorf(err error, format string, args ...interface{}) error {
|
||||||
// always log DB error (print formated message)
|
// create fallback error returned if we can't map it
|
||||||
log.Debug().Msgf("%s %s", fmt.Sprintf(format, args...), err)
|
fallbackErr := fmt.Errorf(format, args...)
|
||||||
|
|
||||||
|
// always log internal error together with message.
|
||||||
|
log.Debug().Msgf("%v: [SQL] %v", fallbackErr, err)
|
||||||
|
|
||||||
// If it's a known error, return converted error instead.
|
// If it's a known error, return converted error instead.
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
switch {
|
||||||
|
case errors.Is(err, sql.ErrNoRows):
|
||||||
return store.ErrResourceNotFound
|
return store.ErrResourceNotFound
|
||||||
} else if isSQLUniqueConstraintError(err) {
|
case isSQLUniqueConstraintError(err):
|
||||||
return store.ErrDuplicate
|
return store.ErrDuplicate
|
||||||
|
default:
|
||||||
|
return fallbackErr
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func isSQLUniqueConstraintError(original error) bool {
|
func isSQLUniqueConstraintError(original error) bool {
|
||||||
|
@ -7,7 +7,6 @@ package check
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -26,7 +25,6 @@ var (
|
|||||||
ErrDisplayNameLength = &ValidationError{
|
ErrDisplayNameLength = &ValidationError{
|
||||||
fmt.Sprintf("DisplayName has to be between %d and %d in length.", minDisplayNameLength, maxDisplayNameLength),
|
fmt.Sprintf("DisplayName has to be between %d and %d in length.", minDisplayNameLength, maxDisplayNameLength),
|
||||||
}
|
}
|
||||||
ErrDisplayNameContainsInvalidASCII = &ValidationError{"DisplayName has to consist of valid ASCII characters."}
|
|
||||||
|
|
||||||
ErrUIDLength = &ValidationError{
|
ErrUIDLength = &ValidationError{
|
||||||
fmt.Sprintf("UID has to be between %d and %d in length.",
|
fmt.Sprintf("UID has to be between %d and %d in length.",
|
||||||
@ -39,6 +37,8 @@ var (
|
|||||||
ErrEmailLen = &ValidationError{
|
ErrEmailLen = &ValidationError{
|
||||||
fmt.Sprintf("Email address has to be within %d and %d characters", minEmailLength, maxEmailLength),
|
fmt.Sprintf("Email address has to be within %d and %d characters", minEmailLength, maxEmailLength),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ErrInvalidCharacters = &ValidationError{"Input contains invalid characters."}
|
||||||
)
|
)
|
||||||
|
|
||||||
// DisplayName checks the provided display name and returns an error if it isn't valid.
|
// DisplayName checks the provided display name and returns an error if it isn't valid.
|
||||||
@ -48,16 +48,15 @@ func DisplayName(displayName string) error {
|
|||||||
return ErrDisplayNameLength
|
return ErrDisplayNameLength
|
||||||
}
|
}
|
||||||
|
|
||||||
// created sanitized string restricted to ASCII characters (without control characters).
|
return ForControlCharacters(displayName)
|
||||||
sanitizedString := strings.Map(func(r rune) rune {
|
}
|
||||||
if r < 32 || r == 127 || r > 255 {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
return r
|
|
||||||
}, displayName)
|
|
||||||
|
|
||||||
if len(sanitizedString) != len(displayName) {
|
// ForControlCharacters ensures that there are no control characters in the provided string.
|
||||||
return ErrDisplayNameContainsInvalidASCII
|
func ForControlCharacters(s string) error {
|
||||||
|
for _, r := range s {
|
||||||
|
if r < 32 || r == 127 {
|
||||||
|
return ErrInvalidCharacters
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
Loading…
Reference in New Issue
Block a user