mirror of
https://github.com/harness/drone.git
synced 2025-05-04 09:21:08 +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,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, processRPCErrorf(err, "failed to get blob from server")
|
||||
}
|
||||
|
||||
blob := resp.GetBlob()
|
||||
|
@ -22,6 +22,26 @@ const (
|
||||
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 {
|
||||
// RepoUID is the uid of the git repository
|
||||
RepoUID string
|
||||
@ -43,12 +63,54 @@ type Branch struct {
|
||||
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) {
|
||||
if params == nil {
|
||||
return nil, ErrNoParamsProvided
|
||||
}
|
||||
|
||||
stream, err := c.repoService.ListBranches(ctx, &rpc.ListBranchesRequest{
|
||||
stream, err := c.refService.ListBranches(ctx, &rpc.ListBranchesRequest{
|
||||
RepoUid: params.RepoUID,
|
||||
IncludeCommit: params.IncludeCommit,
|
||||
Query: params.Query,
|
||||
@ -73,7 +135,7 @@ func (c *Client) ListBranches(ctx context.Context, params *ListBranchesParams) (
|
||||
break
|
||||
}
|
||||
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 {
|
||||
return nil, fmt.Errorf("expected branch message")
|
||||
|
@ -18,6 +18,7 @@ type Config struct {
|
||||
type Client struct {
|
||||
conn *grpc.ClientConn
|
||||
repoService rpc.RepositoryServiceClient
|
||||
refService rpc.ReferenceServiceClient
|
||||
httpService rpc.SmartHTTPServiceClient
|
||||
}
|
||||
|
||||
@ -30,6 +31,7 @@ func New(remoteAddr string) (*Client, error) {
|
||||
return &Client{
|
||||
conn: conn,
|
||||
repoService: rpc.NewRepositoryServiceClient(conn),
|
||||
refService: rpc.NewReferenceServiceClient(conn),
|
||||
httpService: rpc.NewSmartHTTPServiceClient(conn),
|
||||
}, nil
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ func (c *Client) ListCommits(ctx context.Context, params *ListCommitsParams) (*L
|
||||
// get header first
|
||||
header, err := stream.Recv()
|
||||
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 {
|
||||
return nil, fmt.Errorf("header missing")
|
||||
@ -84,7 +84,7 @@ func (c *Client) ListCommits(ctx context.Context, params *ListCommitsParams) (*L
|
||||
break
|
||||
}
|
||||
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 {
|
||||
return nil, fmt.Errorf("expected commit message")
|
||||
|
@ -7,3 +7,6 @@ package gitrpc
|
||||
import "errors"
|
||||
|
||||
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)
|
||||
GetBlob(ctx context.Context, params *GetBlobParams) (*GetBlobOutput, 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)
|
||||
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)
|
||||
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()
|
||||
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()
|
||||
|
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)
|
||||
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)
|
||||
@ -47,7 +47,7 @@ func giteaGetCommitByPath(giteaRepo *gitea.Repository, ref string, treePath stri
|
||||
stdout, _, runErr := gitea.NewCommand(giteaRepo.Ctx, "log", ref, "-1", giteaPrettyLogFormat, "--", treePath).
|
||||
RunStdBytes(&gitea.RunOpts{Dir: giteaRepo.Path})
|
||||
if runErr != nil {
|
||||
return nil, runErr
|
||||
return nil, fmt.Errorf("failed to trigger log command: %w", runErr)
|
||||
}
|
||||
|
||||
giteaCommits, err := giteaParsePrettyFormatLogToList(giteaRepo, stdout)
|
||||
@ -70,7 +70,7 @@ func giteaParsePrettyFormatLogToList(giteaRepo *gitea.Repository, logs []byte) (
|
||||
for _, commitID := range parts {
|
||||
commit, err := giteaRepo.GetCommit(string(commitID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to get commit '%s': %w", string(commitID), err)
|
||||
}
|
||||
giteaCommits = append(giteaCommits, commit)
|
||||
}
|
||||
@ -91,17 +91,17 @@ func (g Adapter) ListCommits(ctx context.Context, repoPath string,
|
||||
// Get the giteaTopCommit object for the ref
|
||||
giteaTopCommit, err := giteaRepo.GetCommit(ref)
|
||||
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)
|
||||
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()
|
||||
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))
|
||||
@ -129,7 +129,7 @@ func (g Adapter) GetCommit(ctx context.Context, repoPath string, ref string) (*t
|
||||
|
||||
commit, err := giteaRepo.GetCommit(ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, processGiteaErrorf(err, "error getting commit for ref '%s'", ref)
|
||||
}
|
||||
|
||||
return mapGiteaCommit(commit)
|
||||
@ -149,7 +149,7 @@ func (g Adapter) GetCommits(ctx context.Context, repoPath string, refs []string)
|
||||
var giteaCommit *gitea.Commit
|
||||
giteaCommit, err = giteaRepo.GetCommit(sha)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, processGiteaErrorf(err, "error getting commit '%s'", sha)
|
||||
}
|
||||
|
||||
var commit *types.Commit
|
||||
|
@ -5,13 +5,59 @@
|
||||
package gitea
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
gitea "code.gitea.io/gitea/modules/git"
|
||||
"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) {
|
||||
res := make(map[types.GitReferenceField]string, len(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 &types.Commit{
|
||||
Sha: giteaCommit.ID.String(),
|
||||
SHA: giteaCommit.ID.String(),
|
||||
Title: giteaCommit.Summary(),
|
||||
// remove potential tailing newlines from message
|
||||
Message: strings.TrimRight(giteaCommit.Message(), "\n"),
|
||||
|
@ -119,7 +119,7 @@ func walkGiteaReferenceParser(parser *gitearef.Parser, handler types.WalkReferen
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -35,14 +35,14 @@ func (g Adapter) SetDefaultBranch(ctx context.Context, repoPath string,
|
||||
// change default branch
|
||||
err = giteaRepo.SetDefaultBranch(defaultBranch)
|
||||
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
|
||||
}
|
||||
|
||||
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,
|
||||
Mirror: opts.Mirror,
|
||||
Bare: opts.Bare,
|
||||
@ -54,14 +54,24 @@ func (g Adapter) Clone(ctx context.Context, from, to string, opts types.CloneRep
|
||||
Filter: opts.Filter,
|
||||
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 {
|
||||
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 {
|
||||
return gitea.CommitChanges(repoPath, gitea.CommitChangesOptions{
|
||||
err := gitea.CommitChanges(repoPath, gitea.CommitChangesOptions{
|
||||
Committer: &gitea.Signature{
|
||||
Name: opts.Committer.Identity.Name,
|
||||
Email: opts.Committer.Identity.Email,
|
||||
@ -74,10 +84,15 @@ func (g Adapter) Commit(repoPath string, opts types.CommitChangesOptions) error
|
||||
},
|
||||
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 {
|
||||
return gitea.Push(ctx, repoPath, gitea.PushOptions{
|
||||
err := gitea.Push(ctx, repoPath, gitea.PushOptions{
|
||||
Remote: opts.Remote,
|
||||
Branch: opts.Branch,
|
||||
Force: opts.Force,
|
||||
@ -85,4 +100,9 @@ func (g Adapter) Push(ctx context.Context, repoPath string, opts types.PushOptio
|
||||
Env: opts.Env,
|
||||
Timeout: opts.Timeout,
|
||||
})
|
||||
if err != nil {
|
||||
return processGiteaErrorf(err, "failed to push changes")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ package gitea
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
gitea "code.gitea.io/gitea/modules/git"
|
||||
"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
|
||||
giteaCommit, err := giteaRepo.GetCommit(ref)
|
||||
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)
|
||||
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{
|
||||
|
@ -31,7 +31,12 @@ func (g Adapter) GetAnnotatedTag(ctx context.Context, repoPath string, sha strin
|
||||
}
|
||||
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.
|
||||
@ -47,7 +52,7 @@ func (g Adapter) GetAnnotatedTags(ctx context.Context, repoPath string, shas []s
|
||||
var tag *types.Tag
|
||||
tag, err = giteaGetAnnotatedTag(giteaRepo, sha)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, processGiteaErrorf(err, "failed to get annotated tag with sha '%s'", sha)
|
||||
}
|
||||
|
||||
tags[i] = *tag
|
||||
|
@ -34,13 +34,14 @@ func (g Adapter) GetTreeNode(ctx context.Context, repoPath string,
|
||||
// Get the giteaCommit object for the ref
|
||||
giteaCommit, err := giteaRepo.GetCommit(ref)
|
||||
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 :)
|
||||
giteaTreeEntry, err := giteaCommit.GetTreeEntryByPath(treePath)
|
||||
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())
|
||||
@ -83,13 +84,13 @@ func (g Adapter) ListTreeNodes(ctx context.Context, repoPath string,
|
||||
// Get the giteaCommit object for the ref
|
||||
giteaCommit, err := giteaRepo.GetCommit(ref)
|
||||
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
|
||||
giteaTree, err := giteaCommit.SubTree(treePath)
|
||||
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
|
||||
@ -99,7 +100,7 @@ func (g Adapter) ListTreeNodes(ctx context.Context, repoPath string,
|
||||
giteaEntries, err = giteaTree.ListEntries()
|
||||
}
|
||||
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
|
||||
@ -107,7 +108,7 @@ func (g Adapter) ListTreeNodes(ctx context.Context, repoPath string,
|
||||
// TODO: can be speed up with latestCommitCache (currently nil)
|
||||
latestCommits, _, err = giteaEntries.GetCommitsInfo(ctx, giteaCommit, treePath, 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) {
|
||||
|
@ -11,11 +11,11 @@ import (
|
||||
)
|
||||
|
||||
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?
|
||||
gitBlob, err := s.adapter.GetBlob(ctx, repoPath, request.GetSha(), request.GetSizeLimit())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, processGitErrorf(err, "failed to get blob")
|
||||
}
|
||||
|
||||
return &rpc.GetBlobResponse{
|
||||
|
@ -18,10 +18,42 @@ import (
|
||||
|
||||
var listBranchesRefFields = []types.GitReferenceField{types.GitReferenceFieldRefName, types.GitReferenceFieldObjectName}
|
||||
|
||||
func (s RepositoryService) ListBranches(request *rpc.ListBranchesRequest,
|
||||
stream rpc.RepositoryService_ListBranchesServer) error {
|
||||
func (s ReferenceService) CreateBranch(ctx context.Context,
|
||||
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()
|
||||
repoPath := s.getFullPathForRepo(request.GetRepoUid())
|
||||
repoPath := getFullPathForRepo(s.reposRoot, request.GetRepoUid())
|
||||
|
||||
// get all required information from git refrences
|
||||
branches, err := s.listBranchesLoadReferenceData(ctx, repoPath, request)
|
||||
@ -63,7 +95,7 @@ func (s RepositoryService) ListBranches(request *rpc.ListBranchesRequest,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s RepositoryService) listBranchesLoadReferenceData(ctx context.Context,
|
||||
func (s ReferenceService) listBranchesLoadReferenceData(ctx context.Context,
|
||||
repoPath string, request *rpc.ListBranchesRequest) ([]*rpc.Branch, error) {
|
||||
// TODO: can we be smarter with slice allocation
|
||||
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)
|
||||
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))
|
||||
|
@ -15,12 +15,12 @@ import (
|
||||
|
||||
func (s RepositoryService) ListCommits(request *rpc.ListCommitsRequest,
|
||||
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(),
|
||||
int(request.GetPage()), int(request.GetPageSize()))
|
||||
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)
|
||||
@ -61,7 +61,7 @@ func (s RepositoryService) getLatestCommit(ctx context.Context, repoPath string,
|
||||
ref string, path string) (*rpc.Commit, error) {
|
||||
gitCommit, err := s.adapter.GetLatestCommit(ctx, repoPath, ref, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, processGitErrorf(err, "failed to get latest commit")
|
||||
}
|
||||
|
||||
return mapGitCommit(gitCommit)
|
||||
|
@ -7,11 +7,9 @@ package service
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -38,30 +36,13 @@ type SmartHTTPService struct {
|
||||
reposRoot string
|
||||
}
|
||||
|
||||
func NewHTTPService(adapter GitAdapter, gitRoot 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
|
||||
}
|
||||
}
|
||||
|
||||
func NewHTTPService(adapter GitAdapter, reposRoot string) (*SmartHTTPService, error) {
|
||||
return &SmartHTTPService{
|
||||
adapter: adapter,
|
||||
reposRoot: reposRoot,
|
||||
}, 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(
|
||||
r *rpc.InfoRefsRequest,
|
||||
stream rpc.SmartHTTPService_InfoRefsServer,
|
||||
@ -72,7 +53,7 @@ func (s *SmartHTTPService) InfoRefs(
|
||||
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)
|
||||
defer cancel()
|
||||
@ -120,7 +101,7 @@ func (s *SmartHTTPService) ServicePack(stream rpc.SmartHTTPService_ServicePackSe
|
||||
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) {
|
||||
resp, streamErr := stream.Recv()
|
||||
|
@ -32,4 +32,6 @@ type GitAdapter interface {
|
||||
GetLatestCommit(ctx context.Context, repoPath string, ref string, treePath string) (*types.Commit, error)
|
||||
GetAnnotatedTag(ctx context.Context, repoPath string, sha 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
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/gitrpc/internal/types"
|
||||
"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 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 {
|
||||
switch s {
|
||||
case rpc.SortOrder_Asc:
|
||||
@ -63,13 +88,34 @@ func mapGitMode(m types.TreeNodeMode) rpc.TreeNodeMode {
|
||||
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) {
|
||||
if gitCommit == nil {
|
||||
return nil, status.Errorf(codes.Internal, "git commit is nil")
|
||||
}
|
||||
|
||||
return &rpc.Commit{
|
||||
Sha: gitCommit.Sha,
|
||||
Sha: gitCommit.SHA,
|
||||
Title: gitCommit.Title,
|
||||
Message: gitCommit.Message,
|
||||
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"
|
||||
|
||||
"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.
|
||||
// TODO: should we error out instead of ignore bad chars?
|
||||
func sanitizeReferenceQuery(query string) (string, bool, bool) {
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/harness/gitness/gitrpc/internal/types"
|
||||
"github.com/harness/gitness/gitrpc/rpc"
|
||||
@ -21,9 +20,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
maxFileSize = 1 << 20
|
||||
repoSubdirName = "repos"
|
||||
gitRepoSuffix = "git"
|
||||
maxFileSize = 1 << 20
|
||||
gitRepoSuffix = "git"
|
||||
|
||||
gitReferenceNamePrefixBranch = "refs/heads/"
|
||||
gitReferenceNamePrefixTag = "refs/tags/"
|
||||
@ -48,14 +46,7 @@ type RepositoryService struct {
|
||||
reposRoot string
|
||||
}
|
||||
|
||||
func NewRepositoryService(adapter GitAdapter, store Storage, gitRoot 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
|
||||
}
|
||||
}
|
||||
|
||||
func NewRepositoryService(adapter GitAdapter, store Storage, reposRoot string) (*RepositoryService, error) {
|
||||
return &RepositoryService{
|
||||
adapter: adapter,
|
||||
store: store,
|
||||
@ -63,16 +54,6 @@ func NewRepositoryService(adapter GitAdapter, store Storage, gitRoot string) (*R
|
||||
}, 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
|
||||
func (s RepositoryService) CreateRepository(stream rpc.RepositoryService_CreateRepositoryServer) error {
|
||||
// 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)
|
||||
|
||||
repoPath := s.getFullPathForRepo(header.GetUid())
|
||||
repoPath := getFullPathForRepo(s.reposRoot, header.GetUid())
|
||||
if _, err = os.Stat(repoPath); !os.IsNotExist(err) {
|
||||
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) {
|
||||
_ = os.RemoveAll(path)
|
||||
}(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)
|
||||
err = s.adapter.SetDefaultBranch(ctx, repoPath, header.GetDefaultBranch(), true)
|
||||
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
|
||||
@ -125,7 +106,7 @@ func (s RepositoryService) CreateRepository(stream rpc.RepositoryService_CreateR
|
||||
|
||||
// Clone repository to temp dir
|
||||
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
|
||||
|
@ -12,11 +12,11 @@ import (
|
||||
|
||||
func (s RepositoryService) GetSubmodule(ctx context.Context,
|
||||
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?
|
||||
gitSubmodule, err := s.adapter.GetSubmodule(ctx, repoPath, request.GetGitRef(), request.GetPath())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, processGitErrorf(err, "failed to get submodule")
|
||||
}
|
||||
|
||||
return &rpc.GetSubmoduleResponse{
|
||||
|
@ -16,10 +16,10 @@ import (
|
||||
)
|
||||
|
||||
//nolint:gocognit // need to refactor this code
|
||||
func (s RepositoryService) ListCommitTags(request *rpc.ListCommitTagsRequest,
|
||||
stream rpc.RepositoryService_ListCommitTagsServer) error {
|
||||
func (s ReferenceService) ListCommitTags(request *rpc.ListCommitTagsRequest,
|
||||
stream rpc.ReferenceService_ListCommitTagsServer) error {
|
||||
ctx := stream.Context()
|
||||
repoPath := s.getFullPathForRepo(request.GetRepoUid())
|
||||
repoPath := getFullPathForRepo(s.reposRoot, request.GetRepoUid())
|
||||
|
||||
// get all required information from git references
|
||||
tags, err := s.listCommitTagsLoadReferenceData(ctx, repoPath, request)
|
||||
@ -43,7 +43,7 @@ func (s RepositoryService) ListCommitTags(request *rpc.ListCommitTagsRequest,
|
||||
var gitTags []types.Tag
|
||||
gitTags, err = s.adapter.GetAnnotatedTags(ctx, repoPath, annotatedTagSHAs)
|
||||
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
|
||||
@ -71,7 +71,7 @@ func (s RepositoryService) ListCommitTags(request *rpc.ListCommitTagsRequest,
|
||||
var gitCommits []types.Commit
|
||||
gitCommits, err = s.adapter.GetCommits(ctx, repoPath, commitSHAs)
|
||||
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 {
|
||||
@ -118,7 +118,7 @@ var listCommitTagsRefFields = []types.GitReferenceField{types.GitReferenceFieldR
|
||||
types.GitReferenceFieldObjectType, types.GitReferenceFieldObjectName}
|
||||
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) {
|
||||
// TODO: can we be smarter with slice allocation
|
||||
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)
|
||||
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))
|
||||
|
@ -15,12 +15,12 @@ import (
|
||||
|
||||
func (s RepositoryService) ListTreeNodes(request *rpc.ListTreeNodesRequest,
|
||||
stream rpc.RepositoryService_ListTreeNodesServer) error {
|
||||
repoPath := s.getFullPathForRepo(request.GetRepoUid())
|
||||
repoPath := getFullPathForRepo(s.reposRoot, request.GetRepoUid())
|
||||
|
||||
gitNodes, err := s.adapter.ListTreeNodes(stream.Context(), repoPath,
|
||||
request.GetGitRef(), request.GetPath(), request.GetRecursive(), request.GetIncludeLatestCommit())
|
||||
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))
|
||||
@ -54,11 +54,11 @@ func (s RepositoryService) ListTreeNodes(request *rpc.ListTreeNodesRequest,
|
||||
|
||||
func (s RepositoryService) GetTreeNode(ctx context.Context,
|
||||
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?
|
||||
gitNode, err := s.adapter.GetTreeNode(ctx, repoPath, request.GetGitRef(), request.GetPath())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, processGitErrorf(err, "failed to get tree node")
|
||||
}
|
||||
|
||||
res := &rpc.GetTreeNodeResponse{
|
||||
@ -76,7 +76,7 @@ func (s RepositoryService) GetTreeNode(ctx context.Context,
|
||||
var commit *rpc.Commit
|
||||
commit, err = s.getLatestCommit(ctx, repoPath, request.GetGitRef(), request.GetPath())
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get latest commit: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
res.Commit = commit
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ func (s RepositoryService) AddFilesAndPush(
|
||||
|
||||
err := s.adapter.AddFiles(repoPath, false, filePaths...)
|
||||
if err != nil {
|
||||
return err
|
||||
return processGitErrorf(err, "failed to add files")
|
||||
}
|
||||
now := time.Now()
|
||||
err = s.adapter.Commit(repoPath, types.CommitChangesOptions{
|
||||
@ -60,7 +60,7 @@ func (s RepositoryService) AddFilesAndPush(
|
||||
Message: message,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
return processGitErrorf(err, "failed to commit files")
|
||||
}
|
||||
err = s.adapter.Push(ctx, repoPath, types.PushOptions{
|
||||
// TODO: Don't hard-code
|
||||
@ -72,7 +72,7 @@ func (s RepositoryService) AddFilesAndPush(
|
||||
Timeout: 0,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
return processGitErrorf(err, "failed to push files")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -2,4 +2,12 @@
|
||||
// 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 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 {
|
||||
Sha string
|
||||
SHA string
|
||||
Title string
|
||||
Message string
|
||||
Author Signature
|
||||
Committer Signature
|
||||
}
|
||||
|
||||
type Branch struct {
|
||||
Name string
|
||||
SHA string
|
||||
Commit *Commit
|
||||
}
|
||||
|
||||
type Tag struct {
|
||||
Sha string
|
||||
Name string
|
||||
|
@ -9,8 +9,38 @@ import (
|
||||
"time"
|
||||
|
||||
"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 {
|
||||
switch o {
|
||||
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 GetBlob(GetBlobRequest) returns (GetBlobResponse);
|
||||
rpc ListCommits(ListCommitsRequest) returns (stream ListCommitsResponse);
|
||||
rpc ListBranches(ListBranchesRequest) returns (stream ListBranchesResponse);
|
||||
rpc ListCommitTags(ListCommitTagsRequest) returns (stream ListCommitTagsResponse);
|
||||
}
|
||||
|
||||
message CreateRepositoryRequest {
|
||||
@ -96,32 +94,6 @@ message ListCommitsResponseHeader {
|
||||
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 {
|
||||
string repo_uid = 1;
|
||||
string sha = 2;
|
||||
@ -151,52 +123,4 @@ message GetSubmoduleResponse {
|
||||
message Submodule {
|
||||
string name = 1;
|
||||
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;
|
||||
Asc = 1;
|
||||
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()
|
||||
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.")
|
||||
|
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)
|
||||
GetBlob(ctx context.Context, in *GetBlobRequest, opts ...grpc.CallOption) (*GetBlobResponse, 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 {
|
||||
@ -165,70 +163,6 @@ func (x *repositoryServiceListCommitsClient) Recv() (*ListCommitsResponse, error
|
||||
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.
|
||||
// All implementations must embed UnimplementedRepositoryServiceServer
|
||||
// for forward compatibility
|
||||
@ -239,8 +173,6 @@ type RepositoryServiceServer interface {
|
||||
GetSubmodule(context.Context, *GetSubmoduleRequest) (*GetSubmoduleResponse, error)
|
||||
GetBlob(context.Context, *GetBlobRequest) (*GetBlobResponse, error)
|
||||
ListCommits(*ListCommitsRequest, RepositoryService_ListCommitsServer) error
|
||||
ListBranches(*ListBranchesRequest, RepositoryService_ListBranchesServer) error
|
||||
ListCommitTags(*ListCommitTagsRequest, RepositoryService_ListCommitTagsServer) error
|
||||
mustEmbedUnimplementedRepositoryServiceServer()
|
||||
}
|
||||
|
||||
@ -266,12 +198,6 @@ func (UnimplementedRepositoryServiceServer) GetBlob(context.Context, *GetBlobReq
|
||||
func (UnimplementedRepositoryServiceServer) ListCommits(*ListCommitsRequest, RepositoryService_ListCommitsServer) error {
|
||||
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() {}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
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.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@ -485,16 +369,6 @@ var RepositoryService_ServiceDesc = grpc.ServiceDesc{
|
||||
Handler: _RepositoryService_ListCommits_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
{
|
||||
StreamName: "ListBranches",
|
||||
Handler: _RepositoryService_ListBranches_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
{
|
||||
StreamName: "ListCommitTags",
|
||||
Handler: _RepositoryService_ListCommitTags_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "repo.proto",
|
||||
}
|
||||
|
@ -251,6 +251,195 @@ func (x *Chunk) GetData() []byte {
|
||||
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_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,
|
||||
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,
|
||||
0x04, 0x64, 0x61, 0x74, 0x61, 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,
|
||||
0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xa0, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74,
|
||||
0x12, 0x10, 0x0a, 0x03, 0x73, 0x68, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73,
|
||||
0x68, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73,
|
||||
0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x12, 0x26, 0x0a, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01,
|
||||
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 (
|
||||
@ -289,21 +496,27 @@ func file_shared_proto_rawDescGZIP() []byte {
|
||||
}
|
||||
|
||||
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{}{
|
||||
(SortOrder)(0), // 0: rpc.SortOrder
|
||||
(*FileUpload)(nil), // 1: rpc.FileUpload
|
||||
(*FileUploadHeader)(nil), // 2: rpc.FileUploadHeader
|
||||
(*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{
|
||||
2, // 0: rpc.FileUpload.header:type_name -> rpc.FileUploadHeader
|
||||
3, // 1: rpc.FileUpload.chunk:type_name -> rpc.Chunk
|
||||
2, // [2:2] is the sub-list for method output_type
|
||||
2, // [2:2] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
5, // 2: rpc.Commit.author:type_name -> rpc.Signature
|
||||
5, // 3: rpc.Commit.committer:type_name -> rpc.Signature
|
||||
6, // 4: rpc.Signature.identity:type_name -> rpc.Identity
|
||||
5, // [5:5] is the sub-list for method output_type
|
||||
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() }
|
||||
@ -348,6 +561,42 @@ func file_shared_proto_init() {
|
||||
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{}{
|
||||
(*FileUpload_Header)(nil),
|
||||
@ -359,7 +608,7 @@ func file_shared_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_shared_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumMessages: 3,
|
||||
NumMessages: 6,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
@ -5,6 +5,10 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/harness/gitness/gitrpc/internal/gitea"
|
||||
"github.com/harness/gitness/gitrpc/internal/service"
|
||||
"github.com/harness/gitness/gitrpc/internal/storage"
|
||||
@ -16,6 +20,10 @@ import (
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
const (
|
||||
repoSubdirName = "repos"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
*grpc.Server
|
||||
Bind string
|
||||
@ -23,6 +31,14 @@ type Server struct {
|
||||
|
||||
// TODO: this wiring should be done by wire.
|
||||
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?
|
||||
setting.Git.HomePath = "home"
|
||||
adapter, err := gitea.New()
|
||||
@ -32,16 +48,22 @@ func NewServer(bind string, gitRoot string) (*Server, error) {
|
||||
s := grpc.NewServer()
|
||||
store := storage.NewLocalStore()
|
||||
// initialize services
|
||||
repoService, err := service.NewRepositoryService(adapter, store, gitRoot)
|
||||
repoService, err := service.NewRepositoryService(adapter, store, reposRoot)
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
// register services
|
||||
rpc.RegisterRepositoryServiceServer(s, repoService)
|
||||
rpc.RegisterReferenceServiceServer(s, refService)
|
||||
rpc.RegisterSmartHTTPServiceServer(s, httpService)
|
||||
|
||||
return &Server{
|
||||
|
@ -135,7 +135,7 @@ func (c *Client) ServicePack(ctx context.Context, w io.Writer, params *ServicePa
|
||||
break
|
||||
}
|
||||
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 {
|
||||
return fmt.Errorf("PostUploadPack() data is nil")
|
||||
|
@ -37,7 +37,7 @@ func (c *Client) GetSubmodule(ctx context.Context, params *GetSubmoduleParams) (
|
||||
Path: params.Path,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, processRPCErrorf(err, "failed to get submodule from server")
|
||||
}
|
||||
if resp.GetSubmodule() == 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
|
||||
}
|
||||
|
||||
stream, err := c.repoService.ListCommitTags(ctx, &rpc.ListCommitTagsRequest{
|
||||
stream, err := c.refService.ListCommitTags(ctx, &rpc.ListCommitTagsRequest{
|
||||
RepoUid: params.RepoUID,
|
||||
IncludeCommit: params.IncludeCommit,
|
||||
Query: params.Query,
|
||||
@ -77,7 +77,7 @@ func (c *Client) ListCommitTags(ctx context.Context, params *ListCommitTagsParam
|
||||
break
|
||||
}
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
||||
// TODO: is this needed?
|
||||
err = stream.CloseSend()
|
||||
if err != nil {
|
||||
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,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, processRPCErrorf(err, "failed to get tree node from server")
|
||||
}
|
||||
|
||||
node, err := mapRPCTreeNode(resp.GetNode())
|
||||
@ -133,7 +133,7 @@ func (c *Client) ListTreeNodes(ctx context.Context, params *ListTreeNodeParams)
|
||||
break
|
||||
}
|
||||
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
|
||||
|
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"
|
||||
|
||||
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"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -125,7 +123,6 @@ func (c *Controller) GetContent(ctx context.Context, session *auth.Session, repo
|
||||
gitRef = repo.DefaultBranch
|
||||
}
|
||||
|
||||
log := log.Ctx(ctx)
|
||||
treeNodeOutput, err := c.gitRPCClient.GetTreeNode(ctx, &gitrpc.GetTreeNodeParams{
|
||||
RepoUID: repo.GitUID,
|
||||
GitREF: gitRef,
|
||||
@ -133,11 +130,7 @@ func (c *Controller) GetContent(ctx context.Context, session *auth.Session, repo
|
||||
IncludeLatestCommit: includeLatestCommit,
|
||||
})
|
||||
if err != nil {
|
||||
// TODO: this should only return not found if it's an actual not found error.
|
||||
// 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
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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.
|
||||
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))
|
||||
}
|
||||
|
||||
|
@ -111,6 +111,11 @@ func GetOptionalRemainderFromPath(r *http.Request) string {
|
||||
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.
|
||||
func ParseQuery(r *http.Request) string {
|
||||
return r.FormValue(QueryParamQuery)
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/gitrpc"
|
||||
apiauth "github.com/harness/gitness/internal/api/auth"
|
||||
"github.com/harness/gitness/internal/store"
|
||||
"github.com/harness/gitness/types/check"
|
||||
@ -47,6 +48,14 @@ func Translate(err error) *Error {
|
||||
case errors.Is(err, store.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
|
||||
default:
|
||||
log.Warn().Msgf("Unable to translate error: %s", err)
|
||||
|
@ -29,7 +29,7 @@ var (
|
||||
ErrNoChange = New(http.StatusBadRequest, "No Change")
|
||||
|
||||
// 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 = New(http.StatusBadRequest, "The primary path of an object can't be deleted")
|
||||
@ -44,6 +44,9 @@ var (
|
||||
// still has child resources.
|
||||
ErrSpaceWithChildsCantBeDeleted = New(http.StatusBadRequest,
|
||||
"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.
|
||||
|
@ -168,6 +168,8 @@ func setupRepos(r chi.Router, repoCtrl *repo.Controller) {
|
||||
// branch operations
|
||||
r.Route("/branches", func(r chi.Router) {
|
||||
r.Get("/", handlerrepo.HandleListBranches(repoCtrl))
|
||||
r.Post("/", handlerrepo.HandleCreateBranch(repoCtrl))
|
||||
r.Delete("/*", handlerrepo.HandleDeleteBranch(repoCtrl))
|
||||
})
|
||||
|
||||
// tags operations
|
||||
|
@ -37,19 +37,24 @@ func offset(page, size int) int {
|
||||
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 {
|
||||
// always log DB error (print formated message)
|
||||
log.Debug().Msgf("%s %s", fmt.Sprintf(format, args...), err)
|
||||
// create fallback error returned if we can't map it
|
||||
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 errors.Is(err, sql.ErrNoRows) {
|
||||
switch {
|
||||
case errors.Is(err, sql.ErrNoRows):
|
||||
return store.ErrResourceNotFound
|
||||
} else if isSQLUniqueConstraintError(err) {
|
||||
case isSQLUniqueConstraintError(err):
|
||||
return store.ErrDuplicate
|
||||
default:
|
||||
return fallbackErr
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func isSQLUniqueConstraintError(original error) bool {
|
||||
|
@ -7,7 +7,6 @@ package check
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -26,7 +25,6 @@ var (
|
||||
ErrDisplayNameLength = &ValidationError{
|
||||
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{
|
||||
fmt.Sprintf("UID has to be between %d and %d in length.",
|
||||
@ -39,6 +37,8 @@ var (
|
||||
ErrEmailLen = &ValidationError{
|
||||
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.
|
||||
@ -48,16 +48,15 @@ func DisplayName(displayName string) error {
|
||||
return ErrDisplayNameLength
|
||||
}
|
||||
|
||||
// created sanitized string restricted to ASCII characters (without control characters).
|
||||
sanitizedString := strings.Map(func(r rune) rune {
|
||||
if r < 32 || r == 127 || r > 255 {
|
||||
return -1
|
||||
}
|
||||
return r
|
||||
}, displayName)
|
||||
return ForControlCharacters(displayName)
|
||||
}
|
||||
|
||||
if len(sanitizedString) != len(displayName) {
|
||||
return ErrDisplayNameContainsInvalidASCII
|
||||
// ForControlCharacters ensures that there are no control characters in the provided string.
|
||||
func ForControlCharacters(s string) error {
|
||||
for _, r := range s {
|
||||
if r < 32 || r == 127 {
|
||||
return ErrInvalidCharacters
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
Loading…
Reference in New Issue
Block a user