drone/gitrpc/branch.go
Johannes Batzill c55c53deab [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
2022-11-10 20:57:31 -08:00

155 lines
3.7 KiB
Go

// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package gitrpc
import (
"context"
"errors"
"fmt"
"io"
"github.com/harness/gitness/gitrpc/rpc"
"github.com/rs/zerolog/log"
)
type BranchSortOption int
const (
BranchSortOptionDefault BranchSortOption = iota
BranchSortOptionName
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
IncludeCommit bool
Query string
Sort BranchSortOption
Order SortOrder
Page int32
PageSize int32
}
type ListBranchesOutput struct {
Branches []Branch
}
type Branch struct {
Name string
SHA string
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.refService.ListBranches(ctx, &rpc.ListBranchesRequest{
RepoUid: params.RepoUID,
IncludeCommit: params.IncludeCommit,
Query: params.Query,
Sort: mapToRPCListBranchesSortOption(params.Sort),
Order: mapToRPCSortOrder(params.Order),
Page: params.Page,
PageSize: params.PageSize,
})
if err != nil {
return nil, fmt.Errorf("failed to start stream for branches: %w", err)
}
// NOTE: don't use PageSize as initial slice capacity - as that theoretically could be MaxInt
output := &ListBranchesOutput{
Branches: make([]Branch, 0, 16),
}
for {
var next *rpc.ListBranchesResponse
next, err = stream.Recv()
if errors.Is(err, io.EOF) {
log.Ctx(ctx).Debug().Msg("received end of stream")
break
}
if err != nil {
return nil, processRPCErrorf(err, "received unexpected error from rpc")
}
if next.GetBranch() == nil {
return nil, fmt.Errorf("expected branch message")
}
var branch *Branch
branch, err = mapRPCBranch(next.GetBranch())
if err != nil {
return nil, fmt.Errorf("failed to map rpc branch: %w", err)
}
output.Branches = append(output.Branches, *branch)
}
return output, nil
}