mirror of https://github.com/harness/drone.git
279 lines
7.2 KiB
Go
279 lines
7.2 KiB
Go
// Copyright 2023 Harness, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package gitrpc
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/harness/gitness/gitrpc/rpc"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
type GetCommitParams struct {
|
|
ReadParams
|
|
// SHA is the git commit sha
|
|
SHA string
|
|
}
|
|
|
|
type GetCommitOutput struct {
|
|
Commit Commit `json:"commit"`
|
|
}
|
|
|
|
type Commit struct {
|
|
SHA string `json:"sha"`
|
|
Title string `json:"title"`
|
|
Message string `json:"message,omitempty"`
|
|
Author Signature `json:"author"`
|
|
Committer Signature `json:"committer"`
|
|
}
|
|
|
|
type Signature struct {
|
|
Identity Identity `json:"identity"`
|
|
When time.Time `json:"when"`
|
|
}
|
|
|
|
type Identity struct {
|
|
Name string `json:"name"`
|
|
Email string `json:"email"`
|
|
}
|
|
|
|
func (c *Client) GetCommit(ctx context.Context, params *GetCommitParams) (*GetCommitOutput, error) {
|
|
if params == nil {
|
|
return nil, ErrNoParamsProvided
|
|
}
|
|
result, err := c.repoService.GetCommit(ctx, &rpc.GetCommitRequest{
|
|
Base: mapToRPCReadRequest(params.ReadParams),
|
|
Sha: params.SHA,
|
|
})
|
|
if err != nil {
|
|
return nil, processRPCErrorf(err, "failed to get commit")
|
|
}
|
|
|
|
commit, err := mapRPCCommit(result.GetCommit())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to map rpc commit: %w", err)
|
|
}
|
|
|
|
return &GetCommitOutput{
|
|
Commit: *commit,
|
|
}, nil
|
|
}
|
|
|
|
type ListCommitsParams struct {
|
|
ReadParams
|
|
// GitREF is a git reference (branch / tag / commit SHA)
|
|
GitREF string
|
|
// After is a git reference (branch / tag / commit SHA)
|
|
// If provided, commits only up to that reference will be returned (exlusive)
|
|
After string
|
|
Page int32
|
|
Limit int32
|
|
Path string
|
|
|
|
// Since allows to filter for commits since the provided UNIX timestamp - Optional, ignored if value is 0.
|
|
Since int64
|
|
|
|
// Until allows to filter for commits until the provided UNIX timestamp - Optional, ignored if value is 0.
|
|
Until int64
|
|
|
|
// Committer allows to filter for commits based on the committer - Optional, ignored if string is empty.
|
|
Committer string
|
|
}
|
|
|
|
type RenameDetails struct {
|
|
OldPath string
|
|
NewPath string
|
|
CommitShaBefore string
|
|
CommitShaAfter string
|
|
}
|
|
|
|
type ListCommitsOutput struct {
|
|
Commits []Commit
|
|
RenameDetails []*RenameDetails
|
|
TotalCommits int
|
|
}
|
|
|
|
func (c *Client) ListCommits(ctx context.Context, params *ListCommitsParams) (*ListCommitsOutput, error) {
|
|
if params == nil {
|
|
return nil, ErrNoParamsProvided
|
|
}
|
|
stream, err := c.repoService.ListCommits(ctx, &rpc.ListCommitsRequest{
|
|
Base: mapToRPCReadRequest(params.ReadParams),
|
|
GitRef: params.GitREF,
|
|
After: params.After,
|
|
Page: params.Page,
|
|
Limit: params.Limit,
|
|
Path: params.Path,
|
|
Since: params.Since,
|
|
Until: params.Until,
|
|
Committer: params.Committer,
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to start stream for commits: %w", err)
|
|
}
|
|
// NOTE: don't use PageSize as initial slice capacity - as that theoretically could be MaxInt
|
|
output := &ListCommitsOutput{
|
|
Commits: make([]Commit, 0, 16),
|
|
}
|
|
|
|
// check for list commits header
|
|
header, err := stream.Header()
|
|
if err != nil {
|
|
return nil, processRPCErrorf(err, "failed to read list commits header from stream")
|
|
}
|
|
|
|
values := header.Get("total-commits")
|
|
if len(values) > 0 && values[0] != "" {
|
|
total, err := strconv.ParseInt(values[0], 10, 32)
|
|
if err != nil {
|
|
return nil, processRPCErrorf(err, "failed to convert header total-commits")
|
|
}
|
|
output.TotalCommits = int(total)
|
|
}
|
|
|
|
for {
|
|
var next *rpc.ListCommitsResponse
|
|
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 server")
|
|
}
|
|
if next.GetCommit() == nil {
|
|
return nil, fmt.Errorf("expected commit message")
|
|
}
|
|
|
|
var commit *Commit
|
|
commit, err = mapRPCCommit(next.GetCommit())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to map rpc commit: %w", err)
|
|
}
|
|
output.Commits = append(output.Commits, *commit)
|
|
|
|
if next.RenameDetails != nil {
|
|
output.RenameDetails = mapRPCRenameDetails(next.RenameDetails)
|
|
}
|
|
}
|
|
|
|
return output, nil
|
|
}
|
|
|
|
type GetCommitDivergencesParams struct {
|
|
ReadParams
|
|
MaxCount int32
|
|
Requests []CommitDivergenceRequest
|
|
}
|
|
|
|
type GetCommitDivergencesOutput struct {
|
|
Divergences []CommitDivergence
|
|
}
|
|
|
|
// CommitDivergenceRequest contains the refs for which the converging commits should be counted.
|
|
type CommitDivergenceRequest struct {
|
|
// From is the ref from which the counting of the diverging commits starts.
|
|
From string
|
|
// To is the ref at which the counting of the diverging commits ends.
|
|
To string
|
|
}
|
|
|
|
// CommitDivergence contains the information of the count of converging commits between two refs.
|
|
type CommitDivergence struct {
|
|
// Ahead is the count of commits the 'From' ref is ahead of the 'To' ref.
|
|
Ahead int32
|
|
// Behind is the count of commits the 'From' ref is behind the 'To' ref.
|
|
Behind int32
|
|
}
|
|
|
|
func (c *Client) GetCommitDivergences(ctx context.Context,
|
|
params *GetCommitDivergencesParams) (*GetCommitDivergencesOutput, error) {
|
|
if params == nil {
|
|
return nil, ErrNoParamsProvided
|
|
}
|
|
|
|
// build rpc request
|
|
req := &rpc.GetCommitDivergencesRequest{
|
|
Base: mapToRPCReadRequest(params.ReadParams),
|
|
MaxCount: params.MaxCount,
|
|
Requests: make([]*rpc.CommitDivergenceRequest, len(params.Requests)),
|
|
}
|
|
for i := range params.Requests {
|
|
req.Requests[i] = &rpc.CommitDivergenceRequest{
|
|
From: params.Requests[i].From,
|
|
To: params.Requests[i].To,
|
|
}
|
|
}
|
|
resp, err := c.repoService.GetCommitDivergences(ctx, req)
|
|
if err != nil {
|
|
return nil, processRPCErrorf(err, "failed to get diverging commits from server")
|
|
}
|
|
|
|
divergences := resp.GetDivergences()
|
|
if divergences == nil {
|
|
return nil, NewError(StatusInternal, "server response divergences were nil")
|
|
}
|
|
|
|
// build output
|
|
output := &GetCommitDivergencesOutput{
|
|
Divergences: make([]CommitDivergence, len(divergences)),
|
|
}
|
|
for i := range divergences {
|
|
if divergences[i] == nil {
|
|
return nil, NewError(StatusInternal, "server returned nil divergence")
|
|
}
|
|
|
|
output.Divergences[i] = CommitDivergence{
|
|
Ahead: divergences[i].Ahead,
|
|
Behind: divergences[i].Behind,
|
|
}
|
|
}
|
|
|
|
return output, nil
|
|
}
|
|
|
|
type MergeBaseParams struct {
|
|
ReadParams
|
|
Ref1 string
|
|
Ref2 string
|
|
}
|
|
|
|
type MergeBaseOutput struct {
|
|
MergeBaseSHA string
|
|
}
|
|
|
|
func (c *Client) MergeBase(ctx context.Context,
|
|
params MergeBaseParams,
|
|
) (MergeBaseOutput, error) {
|
|
result, err := c.repoService.MergeBase(ctx, &rpc.MergeBaseRequest{
|
|
Base: mapToRPCReadRequest(params.ReadParams),
|
|
Ref1: params.Ref1,
|
|
Ref2: params.Ref2,
|
|
})
|
|
if err != nil {
|
|
return MergeBaseOutput{}, fmt.Errorf("failed to get merge base commit: %w", err)
|
|
}
|
|
|
|
return MergeBaseOutput{
|
|
MergeBaseSHA: result.MergeBaseSha,
|
|
}, nil
|
|
}
|