mirror of
https://github.com/harness/drone.git
synced 2025-05-16 00:50:00 +08:00
Merge branch 'code-comment-create' of _OKE5H2PQKOUfzFFDuD4FA/default/CODE/gitness (#17)
This commit is contained in:
commit
b886a96943
@ -34,6 +34,7 @@ import (
|
||||
pullreqevents "github.com/harness/gitness/internal/events/pullreq"
|
||||
"github.com/harness/gitness/internal/server"
|
||||
"github.com/harness/gitness/internal/services"
|
||||
"github.com/harness/gitness/internal/services/codecomments"
|
||||
pullreqservice "github.com/harness/gitness/internal/services/pullreq"
|
||||
"github.com/harness/gitness/internal/services/webhook"
|
||||
"github.com/harness/gitness/internal/store/cache"
|
||||
@ -86,6 +87,7 @@ func initSystem(ctx context.Context, config *gitnesstypes.Config) (*system, erro
|
||||
githook.WireSet,
|
||||
lock.WireSet,
|
||||
pubsub.WireSet,
|
||||
codecomments.WireSet,
|
||||
)
|
||||
return &system{}, nil
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/harness/gitness/events"
|
||||
"github.com/harness/gitness/gitrpc"
|
||||
server2 "github.com/harness/gitness/gitrpc/server"
|
||||
@ -33,6 +32,7 @@ import (
|
||||
router2 "github.com/harness/gitness/internal/router"
|
||||
"github.com/harness/gitness/internal/server"
|
||||
"github.com/harness/gitness/internal/services"
|
||||
"github.com/harness/gitness/internal/services/codecomments"
|
||||
pullreq2 "github.com/harness/gitness/internal/services/pullreq"
|
||||
"github.com/harness/gitness/internal/services/webhook"
|
||||
"github.com/harness/gitness/internal/store/cache"
|
||||
@ -116,6 +116,7 @@ func initSystem(ctx context.Context, config *types.Config) (*system, error) {
|
||||
principalInfoCache := cache.ProvidePrincipalInfoCache(principalInfoView)
|
||||
pullReqStore := database.ProvidePullReqStore(db, principalInfoCache)
|
||||
pullReqActivityStore := database.ProvidePullReqActivityStore(db, principalInfoCache)
|
||||
codeCommentView := database.ProvideCodeCommentView(db)
|
||||
pullReqReviewStore := database.ProvidePullReqReviewStore(db)
|
||||
pullReqReviewerStore := database.ProvidePullReqReviewerStore(db, principalInfoCache)
|
||||
eventsConfig, err := ProvideEventsConfig()
|
||||
@ -136,7 +137,8 @@ func initSystem(ctx context.Context, config *types.Config) (*system, error) {
|
||||
}
|
||||
lockConfig := lock.ProvideConfig(config)
|
||||
mutexManager := lock.ProvideMutexManager(lockConfig, universalClient)
|
||||
pullreqController := pullreq.ProvideController(db, provider, authorizer, pullReqStore, pullReqActivityStore, pullReqReviewStore, pullReqReviewerStore, repoStore, principalStore, gitrpcInterface, reporter, mutexManager)
|
||||
migrator := codecomments.ProvideMigrator(gitrpcInterface)
|
||||
pullreqController := pullreq.ProvideController(db, provider, authorizer, pullReqStore, pullReqActivityStore, codeCommentView, pullReqReviewStore, pullReqReviewerStore, repoStore, principalStore, gitrpcInterface, reporter, mutexManager, migrator)
|
||||
webhookConfig, err := ProvideWebhookConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -179,7 +181,7 @@ func initSystem(ctx context.Context, config *types.Config) (*system, error) {
|
||||
repoGitInfoCache := cache.ProvideRepoGitInfoCache(repoGitInfoView)
|
||||
pubsubConfig := pubsub.ProvideConfig(config)
|
||||
pubSub := pubsub.ProvidePubSub(pubsubConfig, universalClient)
|
||||
pullreqService, err := pullreq2.ProvideService(ctx, config, readerFactory, eventsReaderFactory, reporter, gitrpcInterface, db, repoGitInfoCache, principalInfoCache, repoStore, pullReqStore, pullReqActivityStore, pubSub)
|
||||
pullreqService, err := pullreq2.ProvideService(ctx, config, readerFactory, eventsReaderFactory, reporter, gitrpcInterface, db, repoGitInfoCache, principalInfoCache, repoStore, pullReqStore, pullReqActivityStore, codeCommentView, migrator, pubSub)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import (
|
||||
"github.com/harness/gitness/internal/router"
|
||||
"github.com/harness/gitness/internal/server"
|
||||
"github.com/harness/gitness/internal/services"
|
||||
"github.com/harness/gitness/internal/services/codecomments"
|
||||
pullreqservice "github.com/harness/gitness/internal/services/pullreq"
|
||||
"github.com/harness/gitness/internal/services/webhook"
|
||||
"github.com/harness/gitness/internal/store"
|
||||
@ -83,6 +84,7 @@ func initSystem(ctx context.Context, config *types.Config) (*system, error) {
|
||||
githook.WireSet,
|
||||
lock.WireSet,
|
||||
pubsub.WireSet,
|
||||
codecomments.WireSet,
|
||||
)
|
||||
return &system{}, nil
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/harness/gitness/events"
|
||||
"github.com/harness/gitness/gitrpc"
|
||||
server2 "github.com/harness/gitness/gitrpc/server"
|
||||
@ -29,6 +28,7 @@ import (
|
||||
"github.com/harness/gitness/internal/router"
|
||||
"github.com/harness/gitness/internal/server"
|
||||
"github.com/harness/gitness/internal/services"
|
||||
"github.com/harness/gitness/internal/services/codecomments"
|
||||
pullreq2 "github.com/harness/gitness/internal/services/pullreq"
|
||||
"github.com/harness/gitness/internal/services/webhook"
|
||||
"github.com/harness/gitness/internal/store"
|
||||
@ -81,6 +81,7 @@ func initSystem(ctx context.Context, config *types.Config) (*system, error) {
|
||||
principalInfoCache := cache.ProvidePrincipalInfoCache(principalInfoView)
|
||||
pullReqStore := database.ProvidePullReqStore(db, principalInfoCache)
|
||||
pullReqActivityStore := database.ProvidePullReqActivityStore(db, principalInfoCache)
|
||||
codeCommentView := database.ProvideCodeCommentView(db)
|
||||
pullReqReviewStore := database.ProvidePullReqReviewStore(db)
|
||||
pullReqReviewerStore := database.ProvidePullReqReviewerStore(db, principalInfoCache)
|
||||
eventsConfig, err := ProvideEventsConfig()
|
||||
@ -101,7 +102,8 @@ func initSystem(ctx context.Context, config *types.Config) (*system, error) {
|
||||
}
|
||||
lockConfig := lock.ProvideConfig(config)
|
||||
mutexManager := lock.ProvideMutexManager(lockConfig, universalClient)
|
||||
pullreqController := pullreq.ProvideController(db, provider, authorizer, pullReqStore, pullReqActivityStore, pullReqReviewStore, pullReqReviewerStore, repoStore, principalStore, gitrpcInterface, reporter, mutexManager)
|
||||
migrator := codecomments.ProvideMigrator(gitrpcInterface)
|
||||
pullreqController := pullreq.ProvideController(db, provider, authorizer, pullReqStore, pullReqActivityStore, codeCommentView, pullReqReviewStore, pullReqReviewerStore, repoStore, principalStore, gitrpcInterface, reporter, mutexManager, migrator)
|
||||
webhookConfig, err := ProvideWebhookConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -146,7 +148,7 @@ func initSystem(ctx context.Context, config *types.Config) (*system, error) {
|
||||
repoGitInfoCache := cache.ProvideRepoGitInfoCache(repoGitInfoView)
|
||||
pubsubConfig := pubsub.ProvideConfig(config)
|
||||
pubSub := pubsub.ProvidePubSub(pubsubConfig, universalClient)
|
||||
pullreqService, err := pullreq2.ProvideService(ctx, config, readerFactory, eventsReaderFactory, reporter, gitrpcInterface, db, repoGitInfoCache, principalInfoCache, repoStore, pullReqStore, pullReqActivityStore, pubSub)
|
||||
pullreqService, err := pullreq2.ProvideService(ctx, config, readerFactory, eventsReaderFactory, reporter, gitrpcInterface, db, repoGitInfoCache, principalInfoCache, repoStore, pullReqStore, pullReqActivityStore, codeCommentView, migrator, pubSub)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
130
gitrpc/diff.go
130
gitrpc/diff.go
@ -9,8 +9,10 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/harness/gitness/gitrpc/internal/streamio"
|
||||
"github.com/harness/gitness/gitrpc/internal/types"
|
||||
"github.com/harness/gitness/gitrpc/rpc"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
@ -152,3 +154,131 @@ func (c *Client) DiffStats(ctx context.Context, params *DiffParams) (DiffStatsOu
|
||||
FilesChanged: totalFiles,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type GetDiffHunkHeadersParams struct {
|
||||
ReadParams
|
||||
SourceCommitSHA string
|
||||
TargetCommitSHA string
|
||||
}
|
||||
|
||||
type DiffFileHeader struct {
|
||||
OldName string
|
||||
NewName string
|
||||
}
|
||||
|
||||
type HunkHeader struct {
|
||||
OldLine int
|
||||
OldSpan int
|
||||
NewLine int
|
||||
NewSpan int
|
||||
Text string
|
||||
}
|
||||
|
||||
type DiffFileHunkHeaders struct {
|
||||
FileHeader DiffFileHeader
|
||||
HunkHeaders []HunkHeader
|
||||
}
|
||||
|
||||
type GetDiffHunkHeadersOutput struct {
|
||||
Files []DiffFileHunkHeaders
|
||||
}
|
||||
|
||||
func (c *Client) GetDiffHunkHeaders(
|
||||
ctx context.Context,
|
||||
params GetDiffHunkHeadersParams,
|
||||
) (GetDiffHunkHeadersOutput, error) {
|
||||
if params.SourceCommitSHA == params.TargetCommitSHA {
|
||||
return GetDiffHunkHeadersOutput{}, nil
|
||||
}
|
||||
|
||||
hunkHeaders, err := c.diffService.GetDiffHunkHeaders(ctx, &rpc.GetDiffHunkHeadersRequest{
|
||||
Base: mapToRPCReadRequest(params.ReadParams),
|
||||
SourceCommitSha: params.SourceCommitSHA,
|
||||
TargetCommitSha: params.TargetCommitSHA,
|
||||
})
|
||||
if err != nil {
|
||||
return GetDiffHunkHeadersOutput{}, processRPCErrorf(err, "failed to get git diff hunk headers")
|
||||
}
|
||||
|
||||
files := make([]DiffFileHunkHeaders, len(hunkHeaders.Files))
|
||||
for i, file := range hunkHeaders.Files {
|
||||
headers := make([]HunkHeader, len(file.HunkHeaders))
|
||||
for j, header := range file.HunkHeaders {
|
||||
headers[j] = mapHunkHeader(header)
|
||||
}
|
||||
files[i] = DiffFileHunkHeaders{
|
||||
FileHeader: mapDiffFileHeader(file.FileHeader),
|
||||
HunkHeaders: headers,
|
||||
}
|
||||
}
|
||||
|
||||
return GetDiffHunkHeadersOutput{
|
||||
Files: files,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type DiffCutOutput struct {
|
||||
Header HunkHeader
|
||||
Lines []string
|
||||
MergeBaseSHA string
|
||||
LatestSourceSHA string
|
||||
AnyNew bool
|
||||
}
|
||||
|
||||
type DiffCutParams struct {
|
||||
ReadParams
|
||||
SourceCommitSHA string
|
||||
SourceBranch string
|
||||
TargetCommitSHA string
|
||||
TargetBranch string
|
||||
Path string
|
||||
LineStart int
|
||||
LineStartNew bool
|
||||
LineEnd int
|
||||
LineEndNew bool
|
||||
}
|
||||
|
||||
// DiffCut extracts diff snippet from a git diff hunk.
|
||||
// The snippet is from the specific commit (specified by commit SHA), between refs
|
||||
// source branch and target branch, from the specific file.
|
||||
func (c *Client) DiffCut(ctx context.Context, params *DiffCutParams) (DiffCutOutput, error) {
|
||||
result, err := c.diffService.DiffCut(ctx, &rpc.DiffCutRequest{
|
||||
Base: mapToRPCReadRequest(params.ReadParams),
|
||||
SourceCommitSha: params.SourceCommitSHA,
|
||||
SourceBranch: params.SourceBranch,
|
||||
TargetCommitSha: params.TargetCommitSHA,
|
||||
TargetBranch: params.TargetBranch,
|
||||
Path: params.Path,
|
||||
LineStart: int32(params.LineStart),
|
||||
LineStartNew: params.LineStartNew,
|
||||
LineEnd: int32(params.LineEnd),
|
||||
LineEndNew: params.LineEndNew,
|
||||
})
|
||||
if err != nil {
|
||||
return DiffCutOutput{}, processRPCErrorf(err, "failed to get git diff sub hunk")
|
||||
}
|
||||
|
||||
var anyNew bool
|
||||
for _, line := range result.Lines {
|
||||
if strings.HasPrefix(line, "+") {
|
||||
anyNew = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
hunkHeader := types.HunkHeader{
|
||||
OldLine: int(result.HunkHeader.OldLine),
|
||||
OldSpan: int(result.HunkHeader.OldSpan),
|
||||
NewLine: int(result.HunkHeader.NewLine),
|
||||
NewSpan: int(result.HunkHeader.NewSpan),
|
||||
Text: result.HunkHeader.Text,
|
||||
}
|
||||
|
||||
return DiffCutOutput{
|
||||
Header: HunkHeader(hunkHeader),
|
||||
Lines: result.Lines,
|
||||
MergeBaseSHA: result.MergeBaseSha,
|
||||
LatestSourceSHA: result.LatestSourceSha,
|
||||
AnyNew: anyNew,
|
||||
}, nil
|
||||
}
|
||||
|
@ -50,6 +50,9 @@ type Interface interface {
|
||||
DiffShortStat(ctx context.Context, params *DiffParams) (DiffShortStatOutput, error)
|
||||
DiffStats(ctx context.Context, params *DiffParams) (DiffStatsOutput, error)
|
||||
|
||||
GetDiffHunkHeaders(ctx context.Context, params GetDiffHunkHeadersParams) (GetDiffHunkHeadersOutput, error)
|
||||
DiffCut(ctx context.Context, params *DiffCutParams) (DiffCutOutput, error)
|
||||
|
||||
/*
|
||||
* Merge services
|
||||
*/
|
||||
|
@ -7,9 +7,12 @@ package gitea
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/harness/gitness/gitrpc/internal/parser"
|
||||
"github.com/harness/gitness/gitrpc/internal/types"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
@ -70,3 +73,106 @@ func (g Adapter) DiffShortStat(
|
||||
Deletions: totalDeletions,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetDiffHunkHeaders for each file in diff output returns file name (old and new to detect renames),
|
||||
// and all hunk headers. The diffs are generated with unified=0 parameter to create minimum sized hunks.
|
||||
// Hunks' body is ignored.
|
||||
// The purpose of this function is to get data based on which code comments could be repositioned.
|
||||
func (g Adapter) GetDiffHunkHeaders(
|
||||
ctx context.Context,
|
||||
repoPath, targetRef, sourceRef string,
|
||||
) ([]*types.DiffFileHunkHeaders, error) {
|
||||
pipeRead, pipeWrite := io.Pipe()
|
||||
stderr := &bytes.Buffer{}
|
||||
go func() {
|
||||
var err error
|
||||
|
||||
defer func() {
|
||||
// If running of the command below fails, make the pipe reader also fail with the same error.
|
||||
_ = pipeWrite.CloseWithError(err)
|
||||
}()
|
||||
|
||||
cmd := git.NewCommand(ctx,
|
||||
"diff", "--patch", "--no-color", "--unified=0", sourceRef, targetRef)
|
||||
err = cmd.Run(&git.RunOpts{
|
||||
Dir: repoPath,
|
||||
Stdout: pipeWrite,
|
||||
Stderr: stderr, // We capture stderr output in a buffer.
|
||||
})
|
||||
}()
|
||||
|
||||
fileHunkHeaders, err := parser.GetHunkHeaders(pipeRead)
|
||||
|
||||
// First check if there's something in the stderr buffer, if yes that's the error
|
||||
if errStderr := parseDiffStderr(stderr); errStderr != nil {
|
||||
return nil, errStderr
|
||||
}
|
||||
|
||||
// Next check if reading the git diff output caused an error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return fileHunkHeaders, nil
|
||||
}
|
||||
|
||||
// DiffCut parses full file git diff output and returns lines specified with the parameters.
|
||||
// The purpose of this function is to get diff data with which code comments could be generated.
|
||||
func (g Adapter) DiffCut(
|
||||
ctx context.Context,
|
||||
repoPath, targetRef, sourceRef, path string,
|
||||
params types.DiffCutParams,
|
||||
) (types.Hunk, error) {
|
||||
pipeRead, pipeWrite := io.Pipe()
|
||||
stderr := &bytes.Buffer{}
|
||||
go func() {
|
||||
var err error
|
||||
|
||||
defer func() {
|
||||
// If running of the command below fails, make the pipe reader also fail with the same error.
|
||||
_ = pipeWrite.CloseWithError(err)
|
||||
}()
|
||||
|
||||
cmd := git.NewCommand(ctx,
|
||||
"diff", "--merge-base", "--patch", "--no-color", "--unified=100000000",
|
||||
targetRef, sourceRef, "--", path)
|
||||
err = cmd.Run(&git.RunOpts{
|
||||
Dir: repoPath,
|
||||
Stdout: pipeWrite,
|
||||
Stderr: stderr, // We capture stderr output in a buffer.
|
||||
})
|
||||
}()
|
||||
|
||||
hunk, err := parser.DiffCut(pipeRead, params)
|
||||
|
||||
// First check if there's something in the stderr buffer, if yes that's the error
|
||||
if errStderr := parseDiffStderr(stderr); errStderr != nil {
|
||||
return types.Hunk{}, errStderr
|
||||
}
|
||||
|
||||
// Next check if reading the git diff output caused an error
|
||||
if err != nil {
|
||||
return types.Hunk{}, err
|
||||
}
|
||||
|
||||
return hunk, nil
|
||||
}
|
||||
|
||||
func parseDiffStderr(stderr *bytes.Buffer) error {
|
||||
errRaw := stderr.String() // assume there will never be a lot of output to stdout
|
||||
if len(errRaw) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if idx := strings.IndexByte(errRaw, '\n'); idx > 0 {
|
||||
errRaw = errRaw[:idx] // get only the first line of the output
|
||||
}
|
||||
|
||||
errRaw = strings.TrimPrefix(errRaw, "fatal: ") // git errors start with the "fatal: " prefix
|
||||
|
||||
if strings.Contains(errRaw, "bad revision") {
|
||||
return types.ErrSHADoesNotMatch
|
||||
}
|
||||
|
||||
return errors.New(errRaw)
|
||||
}
|
||||
|
263
gitrpc/internal/parser/diff_cut.go
Normal file
263
gitrpc/internal/parser/diff_cut.go
Normal file
@ -0,0 +1,263 @@
|
||||
// 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 parser
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/harness/gitness/gitrpc/internal/types"
|
||||
)
|
||||
|
||||
// DiffCut parses git diff output that should consist of a single hunk
|
||||
// (usually generated with large value passed to the "--unified" parameter)
|
||||
// and returns lines specified with the parameters.
|
||||
//
|
||||
//nolint:funlen,gocognit,nestif,gocognit,gocyclo,cyclop // it's actually very readable
|
||||
func DiffCut(r io.Reader, params types.DiffCutParams) (types.Hunk, error) {
|
||||
scanner := bufio.NewScanner(r)
|
||||
|
||||
var err error
|
||||
var hunkHeader types.HunkHeader
|
||||
|
||||
if _, err = scanFileHeader(scanner); err != nil {
|
||||
return types.Hunk{}, err
|
||||
}
|
||||
|
||||
if hunkHeader, err = scanHunkHeader(scanner); err != nil {
|
||||
return types.Hunk{}, err
|
||||
}
|
||||
|
||||
currentOldLine := hunkHeader.OldLine
|
||||
currentNewLine := hunkHeader.NewLine
|
||||
|
||||
var inCut bool
|
||||
var diffCutHeader types.HunkHeader
|
||||
var diffCut []string
|
||||
|
||||
linesBeforeBuf := newStrCircBuf(params.BeforeLines)
|
||||
|
||||
for {
|
||||
if params.LineEndNew && currentNewLine > params.LineEnd ||
|
||||
!params.LineEndNew && currentOldLine > params.LineEnd {
|
||||
break // exceeded the requested line range
|
||||
}
|
||||
|
||||
var line string
|
||||
var action diffAction
|
||||
|
||||
line, action, err = scanHunkLine(scanner)
|
||||
if err != nil {
|
||||
return types.Hunk{}, err
|
||||
}
|
||||
|
||||
if line == "" {
|
||||
err = io.EOF
|
||||
break
|
||||
}
|
||||
|
||||
if params.LineStartNew && currentNewLine < params.LineStart ||
|
||||
!params.LineStartNew && currentOldLine < params.LineStart {
|
||||
// not yet in the requested line range
|
||||
linesBeforeBuf.push(line)
|
||||
} else {
|
||||
if !inCut {
|
||||
diffCutHeader.NewLine = currentNewLine
|
||||
diffCutHeader.OldLine = currentOldLine
|
||||
}
|
||||
inCut = true
|
||||
|
||||
if action != actionRemoved {
|
||||
diffCutHeader.NewSpan++
|
||||
}
|
||||
if action != actionAdded {
|
||||
diffCutHeader.OldSpan++
|
||||
}
|
||||
|
||||
diffCut = append(diffCut, line)
|
||||
if len(diffCut) > params.LineLimit {
|
||||
break // safety break
|
||||
}
|
||||
}
|
||||
|
||||
// increment the line numbers
|
||||
if action != actionRemoved {
|
||||
currentNewLine++
|
||||
}
|
||||
if action != actionAdded {
|
||||
currentOldLine++
|
||||
}
|
||||
}
|
||||
|
||||
if !inCut {
|
||||
return types.Hunk{}, types.ErrHunkNotFound
|
||||
}
|
||||
|
||||
var (
|
||||
linesBefore []string
|
||||
linesAfter []string
|
||||
)
|
||||
|
||||
linesBefore = linesBeforeBuf.lines()
|
||||
if !errors.Is(err, io.EOF) {
|
||||
for i := 0; i < params.AfterLines && scanner.Scan(); i++ {
|
||||
line := scanner.Text()
|
||||
if line == "" {
|
||||
break
|
||||
}
|
||||
linesAfter = append(linesAfter, line)
|
||||
}
|
||||
if err = scanner.Err(); err != nil {
|
||||
return types.Hunk{}, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, s := range linesBefore {
|
||||
action := diffAction(s[0])
|
||||
if action != actionRemoved {
|
||||
diffCutHeader.NewLine--
|
||||
diffCutHeader.NewSpan++
|
||||
}
|
||||
if action != actionAdded {
|
||||
diffCutHeader.OldLine--
|
||||
diffCutHeader.OldSpan++
|
||||
}
|
||||
}
|
||||
|
||||
for _, s := range linesAfter {
|
||||
action := diffAction(s[0])
|
||||
if action != actionRemoved {
|
||||
diffCutHeader.NewSpan++
|
||||
}
|
||||
if action != actionAdded {
|
||||
diffCutHeader.OldSpan++
|
||||
}
|
||||
}
|
||||
|
||||
return types.Hunk{
|
||||
HunkHeader: diffCutHeader,
|
||||
Lines: concat(linesBefore, diffCut, linesAfter),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// scanFileHeader keeps reading lines until file header line is read.
|
||||
func scanFileHeader(scan *bufio.Scanner) (types.DiffFileHeader, error) {
|
||||
for scan.Scan() {
|
||||
line := scan.Text()
|
||||
if h, ok := ParseDiffFileHeader(line); ok {
|
||||
return h, nil
|
||||
}
|
||||
}
|
||||
|
||||
if err := scan.Err(); err != nil {
|
||||
return types.DiffFileHeader{}, err
|
||||
}
|
||||
|
||||
return types.DiffFileHeader{}, types.ErrHunkNotFound
|
||||
}
|
||||
|
||||
// scanHunkHeader keeps reading lines until hunk header line is read.
|
||||
func scanHunkHeader(scan *bufio.Scanner) (types.HunkHeader, error) {
|
||||
for scan.Scan() {
|
||||
line := scan.Text()
|
||||
if h, ok := ParseDiffHunkHeader(line); ok {
|
||||
return h, nil
|
||||
}
|
||||
}
|
||||
|
||||
if err := scan.Err(); err != nil {
|
||||
return types.HunkHeader{}, err
|
||||
}
|
||||
|
||||
return types.HunkHeader{}, types.ErrHunkNotFound
|
||||
}
|
||||
|
||||
type diffAction byte
|
||||
|
||||
const (
|
||||
actionUnchanged diffAction = ' '
|
||||
actionRemoved diffAction = '-'
|
||||
actionAdded diffAction = '+'
|
||||
)
|
||||
|
||||
func scanHunkLine(scan *bufio.Scanner) (string, diffAction, error) {
|
||||
if !scan.Scan() {
|
||||
return "", actionUnchanged, scan.Err()
|
||||
}
|
||||
|
||||
line := scan.Text()
|
||||
if line == "" {
|
||||
return "", actionUnchanged, types.ErrHunkNotFound // should not happen: empty line in diff output
|
||||
}
|
||||
|
||||
action := diffAction(line[0])
|
||||
if action != actionRemoved && action != actionAdded && action != actionUnchanged {
|
||||
return "", actionUnchanged, nil
|
||||
}
|
||||
|
||||
return line, action, nil
|
||||
}
|
||||
|
||||
type strCircBuf struct {
|
||||
head int
|
||||
entries []string
|
||||
}
|
||||
|
||||
func newStrCircBuf(size int) strCircBuf {
|
||||
return strCircBuf{
|
||||
head: -1,
|
||||
entries: make([]string, 0, size),
|
||||
}
|
||||
}
|
||||
|
||||
func (b *strCircBuf) push(s string) {
|
||||
n := cap(b.entries)
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
b.head++
|
||||
|
||||
if len(b.entries) < n {
|
||||
b.entries = append(b.entries, s)
|
||||
return
|
||||
}
|
||||
|
||||
if b.head >= n {
|
||||
b.head = 0
|
||||
}
|
||||
b.entries[b.head] = s
|
||||
}
|
||||
|
||||
func (b *strCircBuf) lines() []string {
|
||||
n := cap(b.entries)
|
||||
if len(b.entries) < n {
|
||||
return b.entries
|
||||
}
|
||||
|
||||
res := make([]string, n)
|
||||
for i := 0; i < n; i++ {
|
||||
idx := (b.head + 1 + i) % n
|
||||
res[i] = b.entries[idx]
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func concat[T any](a ...[]T) []T {
|
||||
var n int
|
||||
for _, m := range a {
|
||||
n += len(m)
|
||||
}
|
||||
res := make([]T, n)
|
||||
|
||||
n = 0
|
||||
for _, m := range a {
|
||||
copy(res[n:], m)
|
||||
n += len(m)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
165
gitrpc/internal/parser/diff_cut_test.go
Normal file
165
gitrpc/internal/parser/diff_cut_test.go
Normal file
@ -0,0 +1,165 @@
|
||||
// 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 parser
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/harness/gitness/gitrpc/internal/types"
|
||||
)
|
||||
|
||||
func TestDiffCut(t *testing.T) {
|
||||
const input = `diff --git a/test.txt b/test.txt
|
||||
--- a/test.txt
|
||||
+++ b/test.txt
|
||||
@@ -1,15 +1,11 @@
|
||||
+0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
-6
|
||||
-7
|
||||
-8
|
||||
+6,7,8
|
||||
9
|
||||
10
|
||||
11
|
||||
12
|
||||
-13
|
||||
-14
|
||||
-15
|
||||
`
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
params types.DiffCutParams
|
||||
expCutHeader string
|
||||
expCut []string
|
||||
expError error
|
||||
}{
|
||||
{
|
||||
name: "at-'+6,7,8':new",
|
||||
params: types.DiffCutParams{
|
||||
LineStart: 7, LineStartNew: true,
|
||||
LineEnd: 7, LineEndNew: true,
|
||||
BeforeLines: 0, AfterLines: 0,
|
||||
LineLimit: 1000,
|
||||
},
|
||||
expCutHeader: "@@ -6,3 +7 @@",
|
||||
expCut: []string{"-6", "-7", "-8", "+6,7,8"},
|
||||
expError: nil,
|
||||
},
|
||||
{
|
||||
name: "at-'+6,7,8':new-with-lines-around",
|
||||
params: types.DiffCutParams{
|
||||
LineStart: 7, LineStartNew: true,
|
||||
LineEnd: 7, LineEndNew: true,
|
||||
BeforeLines: 1, AfterLines: 2,
|
||||
LineLimit: 1000,
|
||||
},
|
||||
expCutHeader: "@@ -5,6 +6,4 @@",
|
||||
expCut: []string{" 5", "-6", "-7", "-8", "+6,7,8", " 9", " 10"},
|
||||
expError: nil,
|
||||
},
|
||||
{
|
||||
name: "at-'+0':new-with-lines-around",
|
||||
params: types.DiffCutParams{
|
||||
LineStart: 1, LineStartNew: true,
|
||||
LineEnd: 1, LineEndNew: true,
|
||||
BeforeLines: 3, AfterLines: 3,
|
||||
LineLimit: 1000,
|
||||
},
|
||||
expCutHeader: "@@ -1,3 +1,4 @@",
|
||||
expCut: []string{"+0", " 1", " 2", " 3"},
|
||||
expError: nil,
|
||||
},
|
||||
{
|
||||
name: "at-'-13':one-with-lines-around",
|
||||
params: types.DiffCutParams{
|
||||
LineStart: 13, LineStartNew: false,
|
||||
LineEnd: 13, LineEndNew: false,
|
||||
BeforeLines: 1, AfterLines: 1,
|
||||
LineLimit: 1000,
|
||||
},
|
||||
expCutHeader: "@@ -12,3 +11 @@",
|
||||
expCut: []string{" 12", "-13", "-14"},
|
||||
expError: nil,
|
||||
},
|
||||
{
|
||||
name: "at-'-13':mixed",
|
||||
params: types.DiffCutParams{
|
||||
LineStart: 7, LineStartNew: false,
|
||||
LineEnd: 7, LineEndNew: true,
|
||||
BeforeLines: 0, AfterLines: 0,
|
||||
LineLimit: 1000,
|
||||
},
|
||||
expCutHeader: "@@ -7,2 +7 @@",
|
||||
expCut: []string{"-7", "-8", "+6,7,8"},
|
||||
expError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
hunk, err := DiffCut(
|
||||
strings.NewReader(input),
|
||||
test.params,
|
||||
)
|
||||
|
||||
//nolint:errorlint // this error will not be wrapped
|
||||
if want, got := test.expError, err; want != got {
|
||||
t.Errorf("error mismatch: want=%v got=%v", want, got)
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if want, got := test.expCutHeader, hunk.HunkHeader.String(); want != got {
|
||||
t.Errorf("header mismatch: want=%s got=%s", want, got)
|
||||
}
|
||||
|
||||
if want, got := test.expCut, hunk.Lines; !reflect.DeepEqual(want, got) {
|
||||
t.Errorf("lines mismatch: want=%s got=%s", want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStrCircBuf(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
cap int
|
||||
feed []string
|
||||
exp []string
|
||||
}{
|
||||
{name: "empty", cap: 10, feed: nil, exp: []string{}},
|
||||
{name: "zero-cap", cap: 0, feed: []string{"A", "B"}, exp: []string{}},
|
||||
{name: "one", cap: 5, feed: []string{"A"}, exp: []string{"A"}},
|
||||
{name: "two", cap: 3, feed: []string{"A", "B"}, exp: []string{"A", "B"}},
|
||||
{name: "cap", cap: 3, feed: []string{"A", "B", "C"}, exp: []string{"A", "B", "C"}},
|
||||
{name: "cap+1", cap: 3, feed: []string{"A", "B", "C", "D"}, exp: []string{"B", "C", "D"}},
|
||||
{name: "cap+2", cap: 3, feed: []string{"A", "B", "C", "D", "E"}, exp: []string{"C", "D", "E"}},
|
||||
{name: "cap*2+1", cap: 2, feed: []string{"A", "B", "C", "D", "E"}, exp: []string{"D", "E"}},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
b := newStrCircBuf(test.cap)
|
||||
for _, s := range test.feed {
|
||||
b.push(s)
|
||||
}
|
||||
|
||||
if want, got := test.exp, b.lines(); !reflect.DeepEqual(want, got) {
|
||||
t.Errorf("want=%v, got=%v", want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
71
gitrpc/internal/parser/diff_headers.go
Normal file
71
gitrpc/internal/parser/diff_headers.go
Normal file
@ -0,0 +1,71 @@
|
||||
// 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 parser
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"regexp"
|
||||
|
||||
"github.com/harness/gitness/gitrpc/internal/types"
|
||||
)
|
||||
|
||||
var regExpDiffFileHeader = regexp.MustCompile(`^diff --git a/(.+) b/(.+)$`)
|
||||
|
||||
func ParseDiffFileHeader(line string) (types.DiffFileHeader, bool) {
|
||||
groups := regExpDiffFileHeader.FindStringSubmatch(line)
|
||||
if groups == nil {
|
||||
return types.DiffFileHeader{}, false
|
||||
}
|
||||
|
||||
return types.DiffFileHeader{
|
||||
OldFileName: groups[1],
|
||||
NewFileName: groups[2],
|
||||
}, true
|
||||
}
|
||||
|
||||
// GetHunkHeaders parses git diff output and returns all diff headers for all files.
|
||||
// See for documentation: https://git-scm.com/docs/git-diff#generate_patch_text_with_p
|
||||
func GetHunkHeaders(r io.Reader) ([]*types.DiffFileHunkHeaders, error) {
|
||||
scanner := bufio.NewScanner(r)
|
||||
|
||||
var currentFile *types.DiffFileHunkHeaders
|
||||
var result []*types.DiffFileHunkHeaders
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
||||
if h, ok := ParseDiffFileHeader(line); ok {
|
||||
if currentFile != nil {
|
||||
result = append(result, currentFile)
|
||||
}
|
||||
currentFile = &types.DiffFileHunkHeaders{
|
||||
FileHeader: h,
|
||||
HunksHeaders: nil,
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if h, ok := ParseDiffHunkHeader(line); ok {
|
||||
if currentFile == nil {
|
||||
// should not happen: we reached the hunk header without first finding the file header.
|
||||
return nil, types.ErrHunkNotFound
|
||||
}
|
||||
currentFile.HunksHeaders = append(currentFile.HunksHeaders, h)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if currentFile != nil {
|
||||
result = append(result, currentFile)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
78
gitrpc/internal/parser/diff_headers_test.go
Normal file
78
gitrpc/internal/parser/diff_headers_test.go
Normal file
@ -0,0 +1,78 @@
|
||||
// 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 parser
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/harness/gitness/gitrpc/internal/types"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
func TestGetHunkHeaders(t *testing.T) {
|
||||
input := `diff --git a/new_file.txt b/new_file.txt
|
||||
new file mode 100644
|
||||
index 0000000..fb0c863
|
||||
--- /dev/null
|
||||
+++ b/new_file.txt
|
||||
@@ -0,0 +1,3 @@
|
||||
This is a new file
|
||||
created for this
|
||||
unit test.
|
||||
diff --git a/old_file_name.txt b/changed_file.txt
|
||||
index f043b93..e9449b5 100644
|
||||
--- a/changed_file.txt
|
||||
+++ b/changed_file.txt
|
||||
@@ -7,3 +7,4 @@
|
||||
Unchanged line
|
||||
-Removed line 1
|
||||
+Added line 1
|
||||
+Added line 2
|
||||
Unchanged line
|
||||
@@ -27,2 +28,3 @@
|
||||
Unchanged line
|
||||
+Added line
|
||||
Unchanged line
|
||||
diff --git a/deleted_file.txt b/deleted_file.txt
|
||||
deleted file mode 100644
|
||||
index f043b93..0000000
|
||||
--- a/deleted_file.txt
|
||||
+++ /dev/null
|
||||
@@ -1,3 +0,0 @@
|
||||
-This is content of
|
||||
-a deleted file
|
||||
-in git diff output.
|
||||
`
|
||||
|
||||
got, err := GetHunkHeaders(strings.NewReader(input))
|
||||
if err != nil {
|
||||
t.Errorf("got error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
want := []*types.DiffFileHunkHeaders{
|
||||
{
|
||||
FileHeader: types.DiffFileHeader{OldFileName: "new_file.txt", NewFileName: "new_file.txt"},
|
||||
HunksHeaders: []types.HunkHeader{{OldLine: 0, OldSpan: 0, NewLine: 1, NewSpan: 3}},
|
||||
},
|
||||
{
|
||||
FileHeader: types.DiffFileHeader{OldFileName: "old_file_name.txt", NewFileName: "changed_file.txt"},
|
||||
HunksHeaders: []types.HunkHeader{
|
||||
{OldLine: 7, OldSpan: 3, NewLine: 7, NewSpan: 4},
|
||||
{OldLine: 27, OldSpan: 2, NewLine: 28, NewSpan: 3},
|
||||
},
|
||||
},
|
||||
{
|
||||
FileHeader: types.DiffFileHeader{OldFileName: "deleted_file.txt", NewFileName: "deleted_file.txt"},
|
||||
HunksHeaders: []types.HunkHeader{{OldLine: 1, OldSpan: 3, NewLine: 0, NewSpan: 0}},
|
||||
},
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(got, want); diff != "" {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
40
gitrpc/internal/parser/hunk.go
Normal file
40
gitrpc/internal/parser/hunk.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 parser
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/gitrpc/internal/types"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var regExpHunkHeader = regexp.MustCompile(`^@@ -([0-9]+)(,([0-9]+))? \+([0-9]+)(,([0-9]+))? @@( (.+))?$`)
|
||||
|
||||
func ParseDiffHunkHeader(line string) (types.HunkHeader, bool) {
|
||||
groups := regExpHunkHeader.FindStringSubmatch(line)
|
||||
if groups == nil {
|
||||
return types.HunkHeader{}, false
|
||||
}
|
||||
|
||||
oldLine, _ := strconv.Atoi(groups[1])
|
||||
oldSpan := 1
|
||||
if groups[3] != "" {
|
||||
oldSpan, _ = strconv.Atoi(groups[3])
|
||||
}
|
||||
|
||||
newLine, _ := strconv.Atoi(groups[4])
|
||||
newSpan := 1
|
||||
if groups[6] != "" {
|
||||
newSpan, _ = strconv.Atoi(groups[6])
|
||||
}
|
||||
|
||||
return types.HunkHeader{
|
||||
OldLine: oldLine,
|
||||
OldSpan: oldSpan,
|
||||
NewLine: newLine,
|
||||
NewSpan: newSpan,
|
||||
Text: groups[8],
|
||||
}, true
|
||||
}
|
@ -94,3 +94,58 @@ func (s DiffService) DiffShortStat(ctx context.Context, r *rpc.DiffRequest) (*rp
|
||||
Deletions: int32(stat.Deletions),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s DiffService) GetDiffHunkHeaders(
|
||||
ctx context.Context,
|
||||
r *rpc.GetDiffHunkHeadersRequest,
|
||||
) (*rpc.GetDiffHunkHeadersResponse, error) {
|
||||
base := r.GetBase()
|
||||
repoPath := getFullPathForRepo(s.reposRoot, base.GetRepoUid())
|
||||
|
||||
hunkHeaders, err := s.adapter.GetDiffHunkHeaders(ctx, repoPath, r.TargetCommitSha, r.SourceCommitSha)
|
||||
if err != nil {
|
||||
return nil, processGitErrorf(err, "failed to get diff hunk headers between two commits")
|
||||
}
|
||||
|
||||
return &rpc.GetDiffHunkHeadersResponse{
|
||||
Files: mapDiffFileHunkHeaders(hunkHeaders),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s DiffService) DiffCut(
|
||||
ctx context.Context,
|
||||
r *rpc.DiffCutRequest,
|
||||
) (*rpc.DiffCutResponse, error) {
|
||||
base := r.GetBase()
|
||||
repoPath := getFullPathForRepo(s.reposRoot, base.GetRepoUid())
|
||||
|
||||
mergeBase, _, err := s.adapter.GetMergeBase(ctx, repoPath, "", r.TargetBranch, r.SourceBranch)
|
||||
if err != nil {
|
||||
return nil, processGitErrorf(err, "failed to find merge base")
|
||||
}
|
||||
|
||||
sourceCommits, err := s.adapter.ListCommits(ctx, repoPath, r.SourceBranch, r.TargetBranch, 0, 1)
|
||||
if err != nil || len(sourceCommits) == 0 {
|
||||
return nil, processGitErrorf(err, "failed to get list of source branch commits")
|
||||
}
|
||||
|
||||
hunk, err := s.adapter.DiffCut(ctx, repoPath, r.TargetCommitSha, r.SourceCommitSha, r.Path, types.DiffCutParams{
|
||||
LineStart: int(r.LineStart),
|
||||
LineStartNew: r.LineStartNew,
|
||||
LineEnd: int(r.LineEnd),
|
||||
LineEndNew: r.LineEndNew,
|
||||
BeforeLines: 2,
|
||||
AfterLines: 2,
|
||||
LineLimit: 40,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, processGitErrorf(err, "failed to get diff hunk")
|
||||
}
|
||||
|
||||
return &rpc.DiffCutResponse{
|
||||
HunkHeader: mapHunkHeader(hunk.HunkHeader),
|
||||
Lines: hunk.Lines,
|
||||
MergeBaseSha: mergeBase,
|
||||
LatestSourceSha: sourceCommits[0].SHA,
|
||||
}, nil
|
||||
}
|
||||
|
@ -197,7 +197,9 @@ func processGitErrorf(err error, format string, args ...interface{}) error {
|
||||
// when we add err as argument it will be part of the new error
|
||||
args = append(args, err)
|
||||
switch {
|
||||
case errors.Is(err, types.ErrNotFound):
|
||||
case errors.Is(err, types.ErrNotFound),
|
||||
errors.Is(err, types.ErrSHADoesNotMatch),
|
||||
errors.Is(err, types.ErrHunkNotFound):
|
||||
return ErrNotFoundf(format, args...)
|
||||
case errors.Is(err, types.ErrAlreadyExists):
|
||||
return ErrAlreadyExistsf(format, args...)
|
||||
|
@ -51,5 +51,8 @@ type GitAdapter interface {
|
||||
RawDiff(ctx context.Context, repoPath, base, head string, w io.Writer, args ...string) error
|
||||
DiffShortStat(ctx context.Context, repoPath string,
|
||||
baseRef string, headRef string, direct bool) (types.DiffShortStat, error)
|
||||
GetDiffHunkHeaders(ctx context.Context, repoPath, targetRef, sourceRef string) ([]*types.DiffFileHunkHeaders, error)
|
||||
DiffCut(ctx context.Context, repoPath, targetRef, sourceRef, path string,
|
||||
params types.DiffCutParams) (types.Hunk, error)
|
||||
Blame(ctx context.Context, repoPath, rev, file string, lineFrom, lineTo int) types.BlameReader
|
||||
}
|
||||
|
@ -108,3 +108,34 @@ func mapGitSignature(gitSignature types.Signature) *rpc.Signature {
|
||||
When: gitSignature.When.Unix(),
|
||||
}
|
||||
}
|
||||
func mapHunkHeader(hunkHeader types.HunkHeader) *rpc.HunkHeader {
|
||||
return &rpc.HunkHeader{
|
||||
OldLine: int32(hunkHeader.OldLine),
|
||||
OldSpan: int32(hunkHeader.OldSpan),
|
||||
NewLine: int32(hunkHeader.NewLine),
|
||||
NewSpan: int32(hunkHeader.NewSpan),
|
||||
Text: hunkHeader.Text,
|
||||
}
|
||||
}
|
||||
|
||||
func mapDiffFileHeader(h types.DiffFileHeader) *rpc.DiffFileHeader {
|
||||
return &rpc.DiffFileHeader{
|
||||
OldFileName: h.OldFileName,
|
||||
NewFileName: h.NewFileName,
|
||||
}
|
||||
}
|
||||
|
||||
func mapDiffFileHunkHeaders(diffHunkHeaders []*types.DiffFileHunkHeaders) []*rpc.DiffFileHunkHeaders {
|
||||
res := make([]*rpc.DiffFileHunkHeaders, len(diffHunkHeaders))
|
||||
for i, diffHunkHeader := range diffHunkHeaders {
|
||||
hunkHeaders := make([]*rpc.HunkHeader, len(diffHunkHeader.HunksHeaders))
|
||||
for j, hunkHeader := range diffHunkHeader.HunksHeaders {
|
||||
hunkHeaders[j] = mapHunkHeader(hunkHeader)
|
||||
}
|
||||
res[i] = &rpc.DiffFileHunkHeaders{
|
||||
FileHeader: mapDiffFileHeader(diffHunkHeader.FileHeader),
|
||||
HunkHeaders: hunkHeaders,
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
@ -208,7 +208,10 @@ func isValidGitSHA(sha string) bool {
|
||||
return gitSHARegex.MatchString(sha)
|
||||
}
|
||||
|
||||
func (s RepositoryService) DeleteRepository(ctx context.Context, request *rpc.DeleteRepositoryRequest) (*rpc.DeleteRepositoryResponse, error) {
|
||||
func (s RepositoryService) DeleteRepository(
|
||||
ctx context.Context,
|
||||
request *rpc.DeleteRepositoryRequest,
|
||||
) (*rpc.DeleteRepositoryResponse, error) {
|
||||
base := request.GetBase()
|
||||
|
||||
if base == nil {
|
||||
|
@ -23,6 +23,7 @@ var (
|
||||
ErrSHADoesNotMatch = errors.New("sha does not match")
|
||||
ErrEmptyBaseRef = errors.New("empty base reference")
|
||||
ErrEmptyHeadRef = errors.New("empty head reference")
|
||||
ErrHunkNotFound = errors.New("hunk not found")
|
||||
)
|
||||
|
||||
// MergeConflictsError represents an error if merging fails with a conflict.
|
||||
|
62
gitrpc/internal/types/hunk.go
Normal file
62
gitrpc/internal/types/hunk.go
Normal file
@ -0,0 +1,62 @@
|
||||
// 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 types
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Hunk struct {
|
||||
HunkHeader
|
||||
Lines []string
|
||||
}
|
||||
|
||||
type HunkHeader struct {
|
||||
OldLine int
|
||||
OldSpan int
|
||||
NewLine int
|
||||
NewSpan int
|
||||
Text string
|
||||
}
|
||||
|
||||
func (h *HunkHeader) IsZero() bool {
|
||||
return h.OldLine == 0 && h.OldSpan == 0 && h.NewLine == 0 && h.NewSpan == 0
|
||||
}
|
||||
|
||||
func (h *HunkHeader) IsValid() bool {
|
||||
oldOk := h.OldLine == 0 && h.OldSpan == 0 || h.OldLine > 0 && h.OldSpan > 0
|
||||
newOk := h.NewLine == 0 && h.NewSpan == 0 || h.NewLine > 0 && h.NewSpan > 0
|
||||
return !h.IsZero() && oldOk && newOk
|
||||
}
|
||||
|
||||
func (h *HunkHeader) String() string {
|
||||
sb := strings.Builder{}
|
||||
|
||||
sb.WriteString("@@ -")
|
||||
|
||||
sb.WriteString(strconv.Itoa(h.OldLine))
|
||||
if h.OldSpan != 1 {
|
||||
sb.WriteByte(',')
|
||||
sb.WriteString(strconv.Itoa(h.OldSpan))
|
||||
}
|
||||
|
||||
sb.WriteString(" +")
|
||||
|
||||
sb.WriteString(strconv.Itoa(h.NewLine))
|
||||
if h.NewSpan != 1 {
|
||||
sb.WriteByte(',')
|
||||
sb.WriteString(strconv.Itoa(h.NewSpan))
|
||||
}
|
||||
|
||||
sb.WriteString(" @@")
|
||||
|
||||
if h.Text != "" {
|
||||
sb.WriteByte(' ')
|
||||
sb.WriteString(h.Text)
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
@ -253,6 +253,26 @@ type DiffShortStat struct {
|
||||
Deletions int
|
||||
}
|
||||
|
||||
type DiffFileHeader struct {
|
||||
OldFileName string
|
||||
NewFileName string
|
||||
}
|
||||
|
||||
type DiffFileHunkHeaders struct {
|
||||
FileHeader DiffFileHeader
|
||||
HunksHeaders []HunkHeader
|
||||
}
|
||||
|
||||
type DiffCutParams struct {
|
||||
LineStart int
|
||||
LineStartNew bool
|
||||
LineEnd int
|
||||
LineEndNew bool
|
||||
BeforeLines int
|
||||
AfterLines int
|
||||
LineLimit int
|
||||
}
|
||||
|
||||
type BlameReader interface {
|
||||
NextPart() (*BlamePart, error)
|
||||
}
|
||||
|
@ -225,3 +225,20 @@ func mapToRPCIdentityOptional(identity *Identity) *rpc.Identity {
|
||||
Email: identity.Email,
|
||||
}
|
||||
}
|
||||
|
||||
func mapHunkHeader(h *rpc.HunkHeader) HunkHeader {
|
||||
return HunkHeader{
|
||||
OldLine: int(h.OldLine),
|
||||
OldSpan: int(h.OldSpan),
|
||||
NewLine: int(h.NewLine),
|
||||
NewSpan: int(h.NewSpan),
|
||||
Text: h.Text,
|
||||
}
|
||||
}
|
||||
|
||||
func mapDiffFileHeader(h *rpc.DiffFileHeader) DiffFileHeader {
|
||||
return DiffFileHeader{
|
||||
OldName: h.OldFileName,
|
||||
NewName: h.NewFileName,
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ import "shared.proto";
|
||||
service DiffService {
|
||||
rpc RawDiff(DiffRequest) returns (stream RawDiffResponse) {}
|
||||
rpc DiffShortStat(DiffRequest) returns (DiffShortStatResponse) {}
|
||||
rpc GetDiffHunkHeaders(GetDiffHunkHeadersRequest) returns (GetDiffHunkHeadersResponse) {}
|
||||
rpc DiffCut(DiffCutRequest) returns (DiffCutResponse) {}
|
||||
}
|
||||
|
||||
message DiffRequest {
|
||||
@ -32,3 +34,51 @@ message DiffShortStatResponse {
|
||||
int32 additions = 2;
|
||||
int32 deletions = 3;
|
||||
}
|
||||
|
||||
message HunkHeader {
|
||||
int32 old_line = 1;
|
||||
int32 old_span = 2;
|
||||
int32 new_line = 3;
|
||||
int32 new_span = 4;
|
||||
string text = 5;
|
||||
}
|
||||
|
||||
message DiffFileHeader {
|
||||
string old_file_name = 1;
|
||||
string new_file_name = 2;
|
||||
}
|
||||
|
||||
message DiffFileHunkHeaders {
|
||||
DiffFileHeader file_header = 1;
|
||||
repeated HunkHeader hunk_headers = 2;
|
||||
}
|
||||
|
||||
message GetDiffHunkHeadersRequest {
|
||||
ReadRequest base = 1;
|
||||
string source_commit_sha = 2;
|
||||
string target_commit_sha = 4;
|
||||
}
|
||||
|
||||
message GetDiffHunkHeadersResponse {
|
||||
repeated DiffFileHunkHeaders files = 1;
|
||||
}
|
||||
|
||||
message DiffCutRequest {
|
||||
ReadRequest base = 1;
|
||||
string source_commit_sha = 2;
|
||||
string source_branch = 3;
|
||||
string target_commit_sha = 4;
|
||||
string target_branch = 5;
|
||||
string path = 6;
|
||||
int32 line_start = 7;
|
||||
bool line_start_new = 8;
|
||||
int32 line_end = 9;
|
||||
bool line_end_new = 10;
|
||||
}
|
||||
|
||||
message DiffCutResponse {
|
||||
HunkHeader hunk_header = 1;
|
||||
repeated string lines = 2;
|
||||
string merge_base_sha = 3;
|
||||
string latest_source_sha = 4;
|
||||
}
|
||||
|
@ -205,6 +205,495 @@ func (x *DiffShortStatResponse) GetDeletions() int32 {
|
||||
return 0
|
||||
}
|
||||
|
||||
type HunkHeader struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
OldLine int32 `protobuf:"varint,1,opt,name=old_line,json=oldLine,proto3" json:"old_line,omitempty"`
|
||||
OldSpan int32 `protobuf:"varint,2,opt,name=old_span,json=oldSpan,proto3" json:"old_span,omitempty"`
|
||||
NewLine int32 `protobuf:"varint,3,opt,name=new_line,json=newLine,proto3" json:"new_line,omitempty"`
|
||||
NewSpan int32 `protobuf:"varint,4,opt,name=new_span,json=newSpan,proto3" json:"new_span,omitempty"`
|
||||
Text string `protobuf:"bytes,5,opt,name=text,proto3" json:"text,omitempty"`
|
||||
}
|
||||
|
||||
func (x *HunkHeader) Reset() {
|
||||
*x = HunkHeader{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_diff_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *HunkHeader) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*HunkHeader) ProtoMessage() {}
|
||||
|
||||
func (x *HunkHeader) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_diff_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 HunkHeader.ProtoReflect.Descriptor instead.
|
||||
func (*HunkHeader) Descriptor() ([]byte, []int) {
|
||||
return file_diff_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *HunkHeader) GetOldLine() int32 {
|
||||
if x != nil {
|
||||
return x.OldLine
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *HunkHeader) GetOldSpan() int32 {
|
||||
if x != nil {
|
||||
return x.OldSpan
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *HunkHeader) GetNewLine() int32 {
|
||||
if x != nil {
|
||||
return x.NewLine
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *HunkHeader) GetNewSpan() int32 {
|
||||
if x != nil {
|
||||
return x.NewSpan
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *HunkHeader) GetText() string {
|
||||
if x != nil {
|
||||
return x.Text
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type DiffFileHeader struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
OldFileName string `protobuf:"bytes,1,opt,name=old_file_name,json=oldFileName,proto3" json:"old_file_name,omitempty"`
|
||||
NewFileName string `protobuf:"bytes,2,opt,name=new_file_name,json=newFileName,proto3" json:"new_file_name,omitempty"`
|
||||
}
|
||||
|
||||
func (x *DiffFileHeader) Reset() {
|
||||
*x = DiffFileHeader{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_diff_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *DiffFileHeader) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*DiffFileHeader) ProtoMessage() {}
|
||||
|
||||
func (x *DiffFileHeader) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_diff_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 DiffFileHeader.ProtoReflect.Descriptor instead.
|
||||
func (*DiffFileHeader) Descriptor() ([]byte, []int) {
|
||||
return file_diff_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *DiffFileHeader) GetOldFileName() string {
|
||||
if x != nil {
|
||||
return x.OldFileName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *DiffFileHeader) GetNewFileName() string {
|
||||
if x != nil {
|
||||
return x.NewFileName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type DiffFileHunkHeaders struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
FileHeader *DiffFileHeader `protobuf:"bytes,1,opt,name=file_header,json=fileHeader,proto3" json:"file_header,omitempty"`
|
||||
HunkHeaders []*HunkHeader `protobuf:"bytes,2,rep,name=hunk_headers,json=hunkHeaders,proto3" json:"hunk_headers,omitempty"`
|
||||
}
|
||||
|
||||
func (x *DiffFileHunkHeaders) Reset() {
|
||||
*x = DiffFileHunkHeaders{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_diff_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *DiffFileHunkHeaders) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*DiffFileHunkHeaders) ProtoMessage() {}
|
||||
|
||||
func (x *DiffFileHunkHeaders) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_diff_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 DiffFileHunkHeaders.ProtoReflect.Descriptor instead.
|
||||
func (*DiffFileHunkHeaders) Descriptor() ([]byte, []int) {
|
||||
return file_diff_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *DiffFileHunkHeaders) GetFileHeader() *DiffFileHeader {
|
||||
if x != nil {
|
||||
return x.FileHeader
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *DiffFileHunkHeaders) GetHunkHeaders() []*HunkHeader {
|
||||
if x != nil {
|
||||
return x.HunkHeaders
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type GetDiffHunkHeadersRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Base *ReadRequest `protobuf:"bytes,1,opt,name=base,proto3" json:"base,omitempty"`
|
||||
SourceCommitSha string `protobuf:"bytes,2,opt,name=source_commit_sha,json=sourceCommitSha,proto3" json:"source_commit_sha,omitempty"`
|
||||
TargetCommitSha string `protobuf:"bytes,4,opt,name=target_commit_sha,json=targetCommitSha,proto3" json:"target_commit_sha,omitempty"`
|
||||
}
|
||||
|
||||
func (x *GetDiffHunkHeadersRequest) Reset() {
|
||||
*x = GetDiffHunkHeadersRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_diff_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *GetDiffHunkHeadersRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetDiffHunkHeadersRequest) ProtoMessage() {}
|
||||
|
||||
func (x *GetDiffHunkHeadersRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_diff_proto_msgTypes[6]
|
||||
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 GetDiffHunkHeadersRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetDiffHunkHeadersRequest) Descriptor() ([]byte, []int) {
|
||||
return file_diff_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *GetDiffHunkHeadersRequest) GetBase() *ReadRequest {
|
||||
if x != nil {
|
||||
return x.Base
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *GetDiffHunkHeadersRequest) GetSourceCommitSha() string {
|
||||
if x != nil {
|
||||
return x.SourceCommitSha
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GetDiffHunkHeadersRequest) GetTargetCommitSha() string {
|
||||
if x != nil {
|
||||
return x.TargetCommitSha
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type GetDiffHunkHeadersResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Files []*DiffFileHunkHeaders `protobuf:"bytes,1,rep,name=files,proto3" json:"files,omitempty"`
|
||||
}
|
||||
|
||||
func (x *GetDiffHunkHeadersResponse) Reset() {
|
||||
*x = GetDiffHunkHeadersResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_diff_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *GetDiffHunkHeadersResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetDiffHunkHeadersResponse) ProtoMessage() {}
|
||||
|
||||
func (x *GetDiffHunkHeadersResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_diff_proto_msgTypes[7]
|
||||
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 GetDiffHunkHeadersResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetDiffHunkHeadersResponse) Descriptor() ([]byte, []int) {
|
||||
return file_diff_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *GetDiffHunkHeadersResponse) GetFiles() []*DiffFileHunkHeaders {
|
||||
if x != nil {
|
||||
return x.Files
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type DiffCutRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Base *ReadRequest `protobuf:"bytes,1,opt,name=base,proto3" json:"base,omitempty"`
|
||||
SourceCommitSha string `protobuf:"bytes,2,opt,name=source_commit_sha,json=sourceCommitSha,proto3" json:"source_commit_sha,omitempty"`
|
||||
SourceBranch string `protobuf:"bytes,3,opt,name=source_branch,json=sourceBranch,proto3" json:"source_branch,omitempty"`
|
||||
TargetCommitSha string `protobuf:"bytes,4,opt,name=target_commit_sha,json=targetCommitSha,proto3" json:"target_commit_sha,omitempty"`
|
||||
TargetBranch string `protobuf:"bytes,5,opt,name=target_branch,json=targetBranch,proto3" json:"target_branch,omitempty"`
|
||||
Path string `protobuf:"bytes,6,opt,name=path,proto3" json:"path,omitempty"`
|
||||
LineStart int32 `protobuf:"varint,7,opt,name=line_start,json=lineStart,proto3" json:"line_start,omitempty"`
|
||||
LineStartNew bool `protobuf:"varint,8,opt,name=line_start_new,json=lineStartNew,proto3" json:"line_start_new,omitempty"`
|
||||
LineEnd int32 `protobuf:"varint,9,opt,name=line_end,json=lineEnd,proto3" json:"line_end,omitempty"`
|
||||
LineEndNew bool `protobuf:"varint,10,opt,name=line_end_new,json=lineEndNew,proto3" json:"line_end_new,omitempty"`
|
||||
}
|
||||
|
||||
func (x *DiffCutRequest) Reset() {
|
||||
*x = DiffCutRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_diff_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *DiffCutRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*DiffCutRequest) ProtoMessage() {}
|
||||
|
||||
func (x *DiffCutRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_diff_proto_msgTypes[8]
|
||||
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 DiffCutRequest.ProtoReflect.Descriptor instead.
|
||||
func (*DiffCutRequest) Descriptor() ([]byte, []int) {
|
||||
return file_diff_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *DiffCutRequest) GetBase() *ReadRequest {
|
||||
if x != nil {
|
||||
return x.Base
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *DiffCutRequest) GetSourceCommitSha() string {
|
||||
if x != nil {
|
||||
return x.SourceCommitSha
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *DiffCutRequest) GetSourceBranch() string {
|
||||
if x != nil {
|
||||
return x.SourceBranch
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *DiffCutRequest) GetTargetCommitSha() string {
|
||||
if x != nil {
|
||||
return x.TargetCommitSha
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *DiffCutRequest) GetTargetBranch() string {
|
||||
if x != nil {
|
||||
return x.TargetBranch
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *DiffCutRequest) GetPath() string {
|
||||
if x != nil {
|
||||
return x.Path
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *DiffCutRequest) GetLineStart() int32 {
|
||||
if x != nil {
|
||||
return x.LineStart
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *DiffCutRequest) GetLineStartNew() bool {
|
||||
if x != nil {
|
||||
return x.LineStartNew
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *DiffCutRequest) GetLineEnd() int32 {
|
||||
if x != nil {
|
||||
return x.LineEnd
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *DiffCutRequest) GetLineEndNew() bool {
|
||||
if x != nil {
|
||||
return x.LineEndNew
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type DiffCutResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
HunkHeader *HunkHeader `protobuf:"bytes,1,opt,name=hunk_header,json=hunkHeader,proto3" json:"hunk_header,omitempty"`
|
||||
Lines []string `protobuf:"bytes,2,rep,name=lines,proto3" json:"lines,omitempty"`
|
||||
MergeBaseSha string `protobuf:"bytes,3,opt,name=merge_base_sha,json=mergeBaseSha,proto3" json:"merge_base_sha,omitempty"`
|
||||
LatestSourceSha string `protobuf:"bytes,4,opt,name=latest_source_sha,json=latestSourceSha,proto3" json:"latest_source_sha,omitempty"`
|
||||
}
|
||||
|
||||
func (x *DiffCutResponse) Reset() {
|
||||
*x = DiffCutResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_diff_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *DiffCutResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*DiffCutResponse) ProtoMessage() {}
|
||||
|
||||
func (x *DiffCutResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_diff_proto_msgTypes[9]
|
||||
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 DiffCutResponse.ProtoReflect.Descriptor instead.
|
||||
func (*DiffCutResponse) Descriptor() ([]byte, []int) {
|
||||
return file_diff_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *DiffCutResponse) GetHunkHeader() *HunkHeader {
|
||||
if x != nil {
|
||||
return x.HunkHeader
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *DiffCutResponse) GetLines() []string {
|
||||
if x != nil {
|
||||
return x.Lines
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *DiffCutResponse) GetMergeBaseSha() string {
|
||||
if x != nil {
|
||||
return x.MergeBaseSha
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *DiffCutResponse) GetLatestSourceSha() string {
|
||||
if x != nil {
|
||||
return x.LatestSourceSha
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_diff_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_diff_proto_rawDesc = []byte{
|
||||
@ -227,19 +716,99 @@ var file_diff_proto_rawDesc = []byte{
|
||||
0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x05, 0x52, 0x09, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1c,
|
||||
0x0a, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x05, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0x85, 0x01, 0x0a,
|
||||
0x0b, 0x44, 0x69, 0x66, 0x66, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x35, 0x0a, 0x07,
|
||||
0x52, 0x61, 0x77, 0x44, 0x69, 0x66, 0x66, 0x12, 0x10, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x69,
|
||||
0x66, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x72, 0x70, 0x63, 0x2e,
|
||||
0x52, 0x61, 0x77, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||
0x00, 0x30, 0x01, 0x12, 0x3f, 0x0a, 0x0d, 0x44, 0x69, 0x66, 0x66, 0x53, 0x68, 0x6f, 0x72, 0x74,
|
||||
0x53, 0x74, 0x61, 0x74, 0x12, 0x10, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x69, 0x66, 0x66, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x69, 0x66,
|
||||
0x66, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x00, 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,
|
||||
0x05, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x8c, 0x01, 0x0a,
|
||||
0x0a, 0x48, 0x75, 0x6e, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x6f,
|
||||
0x6c, 0x64, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x6f,
|
||||
0x6c, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x6c, 0x64, 0x5f, 0x73, 0x70,
|
||||
0x61, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x6f, 0x6c, 0x64, 0x53, 0x70, 0x61,
|
||||
0x6e, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x65, 0x77, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x05, 0x52, 0x07, 0x6e, 0x65, 0x77, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x19, 0x0a, 0x08,
|
||||
0x6e, 0x65, 0x77, 0x5f, 0x73, 0x70, 0x61, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07,
|
||||
0x6e, 0x65, 0x77, 0x53, 0x70, 0x61, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18,
|
||||
0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x22, 0x58, 0x0a, 0x0e, 0x44,
|
||||
0x69, 0x66, 0x66, 0x46, 0x69, 0x6c, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x22, 0x0a,
|
||||
0x0d, 0x6f, 0x6c, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x6c, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d,
|
||||
0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x65, 0x77, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x65, 0x77, 0x46, 0x69, 0x6c,
|
||||
0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x7f, 0x0a, 0x13, 0x44, 0x69, 0x66, 0x66, 0x46, 0x69, 0x6c,
|
||||
0x65, 0x48, 0x75, 0x6e, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x34, 0x0a, 0x0b,
|
||||
0x66, 0x69, 0x6c, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x13, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x69, 0x66, 0x66, 0x46, 0x69, 0x6c, 0x65,
|
||||
0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x48, 0x65, 0x61, 0x64,
|
||||
0x65, 0x72, 0x12, 0x32, 0x0a, 0x0c, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65,
|
||||
0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x48,
|
||||
0x75, 0x6e, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0b, 0x68, 0x75, 0x6e, 0x6b, 0x48,
|
||||
0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x22, 0x99, 0x01, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x44, 0x69,
|
||||
0x66, 0x66, 0x48, 0x75, 0x6e, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x10, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x52, 0x04, 0x62, 0x61, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x6f,
|
||||
0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x73, 0x68, 0x61, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x6d,
|
||||
0x6d, 0x69, 0x74, 0x53, 0x68, 0x61, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x73, 0x68, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x53,
|
||||
0x68, 0x61, 0x22, 0x4c, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x44, 0x69, 0x66, 0x66, 0x48, 0x75, 0x6e,
|
||||
0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x12, 0x2e, 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||
0x18, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x69, 0x66, 0x66, 0x46, 0x69, 0x6c, 0x65, 0x48, 0x75,
|
||||
0x6e, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73,
|
||||
0x22, 0xee, 0x02, 0x0a, 0x0e, 0x44, 0x69, 0x66, 0x66, 0x43, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x10, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x52, 0x04, 0x62, 0x61, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x73, 0x68, 0x61, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x6d, 0x6d,
|
||||
0x69, 0x74, 0x53, 0x68, 0x61, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f,
|
||||
0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x6f,
|
||||
0x75, 0x72, 0x63, 0x65, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x61,
|
||||
0x72, 0x67, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x73, 0x68, 0x61, 0x18,
|
||||
0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6d,
|
||||
0x6d, 0x69, 0x74, 0x53, 0x68, 0x61, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
|
||||
0x5f, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x70,
|
||||
0x61, 0x74, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12,
|
||||
0x1d, 0x0a, 0x0a, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x07, 0x20,
|
||||
0x01, 0x28, 0x05, 0x52, 0x09, 0x6c, 0x69, 0x6e, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x24,
|
||||
0x0a, 0x0e, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6e, 0x65, 0x77,
|
||||
0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6c, 0x69, 0x6e, 0x65, 0x53, 0x74, 0x61, 0x72,
|
||||
0x74, 0x4e, 0x65, 0x77, 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x65, 0x6e, 0x64,
|
||||
0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x6c, 0x69, 0x6e, 0x65, 0x45, 0x6e, 0x64, 0x12,
|
||||
0x20, 0x0a, 0x0c, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x6e, 0x65, 0x77, 0x18,
|
||||
0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x6c, 0x69, 0x6e, 0x65, 0x45, 0x6e, 0x64, 0x4e, 0x65,
|
||||
0x77, 0x22, 0xab, 0x01, 0x0a, 0x0f, 0x44, 0x69, 0x66, 0x66, 0x43, 0x75, 0x74, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x0b, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x68, 0x65,
|
||||
0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x72, 0x70, 0x63,
|
||||
0x2e, 0x48, 0x75, 0x6e, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0a, 0x68, 0x75, 0x6e,
|
||||
0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6e, 0x65, 0x73,
|
||||
0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x12, 0x24, 0x0a,
|
||||
0x0e, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x18,
|
||||
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x42, 0x61, 0x73, 0x65,
|
||||
0x53, 0x68, 0x61, 0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x6f,
|
||||
0x75, 0x72, 0x63, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f,
|
||||
0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x68, 0x61, 0x32,
|
||||
0x96, 0x02, 0x0a, 0x0b, 0x44, 0x69, 0x66, 0x66, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
|
||||
0x35, 0x0a, 0x07, 0x52, 0x61, 0x77, 0x44, 0x69, 0x66, 0x66, 0x12, 0x10, 0x2e, 0x72, 0x70, 0x63,
|
||||
0x2e, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x72,
|
||||
0x70, 0x63, 0x2e, 0x52, 0x61, 0x77, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x3f, 0x0a, 0x0d, 0x44, 0x69, 0x66, 0x66, 0x53, 0x68,
|
||||
0x6f, 0x72, 0x74, 0x53, 0x74, 0x61, 0x74, 0x12, 0x10, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x69,
|
||||
0x66, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x72, 0x70, 0x63, 0x2e,
|
||||
0x44, 0x69, 0x66, 0x66, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x61, 0x74, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x57, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x44, 0x69,
|
||||
0x66, 0x66, 0x48, 0x75, 0x6e, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x1e, 0x2e,
|
||||
0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x69, 0x66, 0x66, 0x48, 0x75, 0x6e, 0x6b, 0x48,
|
||||
0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e,
|
||||
0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x69, 0x66, 0x66, 0x48, 0x75, 0x6e, 0x6b, 0x48,
|
||||
0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
|
||||
0x12, 0x36, 0x0a, 0x07, 0x44, 0x69, 0x66, 0x66, 0x43, 0x75, 0x74, 0x12, 0x13, 0x2e, 0x72, 0x70,
|
||||
0x63, 0x2e, 0x44, 0x69, 0x66, 0x66, 0x43, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x1a, 0x14, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x69, 0x66, 0x66, 0x43, 0x75, 0x74, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 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 (
|
||||
@ -254,24 +823,41 @@ func file_diff_proto_rawDescGZIP() []byte {
|
||||
return file_diff_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_diff_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||
var file_diff_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
||||
var file_diff_proto_goTypes = []interface{}{
|
||||
(*DiffRequest)(nil), // 0: rpc.DiffRequest
|
||||
(*RawDiffResponse)(nil), // 1: rpc.RawDiffResponse
|
||||
(*DiffShortStatResponse)(nil), // 2: rpc.DiffShortStatResponse
|
||||
(*ReadRequest)(nil), // 3: rpc.ReadRequest
|
||||
(*HunkHeader)(nil), // 3: rpc.HunkHeader
|
||||
(*DiffFileHeader)(nil), // 4: rpc.DiffFileHeader
|
||||
(*DiffFileHunkHeaders)(nil), // 5: rpc.DiffFileHunkHeaders
|
||||
(*GetDiffHunkHeadersRequest)(nil), // 6: rpc.GetDiffHunkHeadersRequest
|
||||
(*GetDiffHunkHeadersResponse)(nil), // 7: rpc.GetDiffHunkHeadersResponse
|
||||
(*DiffCutRequest)(nil), // 8: rpc.DiffCutRequest
|
||||
(*DiffCutResponse)(nil), // 9: rpc.DiffCutResponse
|
||||
(*ReadRequest)(nil), // 10: rpc.ReadRequest
|
||||
}
|
||||
var file_diff_proto_depIdxs = []int32{
|
||||
3, // 0: rpc.DiffRequest.base:type_name -> rpc.ReadRequest
|
||||
0, // 1: rpc.DiffService.RawDiff:input_type -> rpc.DiffRequest
|
||||
0, // 2: rpc.DiffService.DiffShortStat:input_type -> rpc.DiffRequest
|
||||
1, // 3: rpc.DiffService.RawDiff:output_type -> rpc.RawDiffResponse
|
||||
2, // 4: rpc.DiffService.DiffShortStat:output_type -> rpc.DiffShortStatResponse
|
||||
3, // [3:5] is the sub-list for method output_type
|
||||
1, // [1:3] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
10, // 0: rpc.DiffRequest.base:type_name -> rpc.ReadRequest
|
||||
4, // 1: rpc.DiffFileHunkHeaders.file_header:type_name -> rpc.DiffFileHeader
|
||||
3, // 2: rpc.DiffFileHunkHeaders.hunk_headers:type_name -> rpc.HunkHeader
|
||||
10, // 3: rpc.GetDiffHunkHeadersRequest.base:type_name -> rpc.ReadRequest
|
||||
5, // 4: rpc.GetDiffHunkHeadersResponse.files:type_name -> rpc.DiffFileHunkHeaders
|
||||
10, // 5: rpc.DiffCutRequest.base:type_name -> rpc.ReadRequest
|
||||
3, // 6: rpc.DiffCutResponse.hunk_header:type_name -> rpc.HunkHeader
|
||||
0, // 7: rpc.DiffService.RawDiff:input_type -> rpc.DiffRequest
|
||||
0, // 8: rpc.DiffService.DiffShortStat:input_type -> rpc.DiffRequest
|
||||
6, // 9: rpc.DiffService.GetDiffHunkHeaders:input_type -> rpc.GetDiffHunkHeadersRequest
|
||||
8, // 10: rpc.DiffService.DiffCut:input_type -> rpc.DiffCutRequest
|
||||
1, // 11: rpc.DiffService.RawDiff:output_type -> rpc.RawDiffResponse
|
||||
2, // 12: rpc.DiffService.DiffShortStat:output_type -> rpc.DiffShortStatResponse
|
||||
7, // 13: rpc.DiffService.GetDiffHunkHeaders:output_type -> rpc.GetDiffHunkHeadersResponse
|
||||
9, // 14: rpc.DiffService.DiffCut:output_type -> rpc.DiffCutResponse
|
||||
11, // [11:15] is the sub-list for method output_type
|
||||
7, // [7:11] is the sub-list for method input_type
|
||||
7, // [7:7] is the sub-list for extension type_name
|
||||
7, // [7:7] is the sub-list for extension extendee
|
||||
0, // [0:7] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_diff_proto_init() }
|
||||
@ -317,6 +903,90 @@ func file_diff_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_diff_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*HunkHeader); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_diff_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*DiffFileHeader); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_diff_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*DiffFileHunkHeaders); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_diff_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*GetDiffHunkHeadersRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_diff_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*GetDiffHunkHeadersResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_diff_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*DiffCutRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_diff_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*DiffCutResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
@ -324,7 +994,7 @@ func file_diff_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_diff_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 3,
|
||||
NumMessages: 10,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
@ -24,6 +24,8 @@ const _ = grpc.SupportPackageIsVersion7
|
||||
type DiffServiceClient interface {
|
||||
RawDiff(ctx context.Context, in *DiffRequest, opts ...grpc.CallOption) (DiffService_RawDiffClient, error)
|
||||
DiffShortStat(ctx context.Context, in *DiffRequest, opts ...grpc.CallOption) (*DiffShortStatResponse, error)
|
||||
GetDiffHunkHeaders(ctx context.Context, in *GetDiffHunkHeadersRequest, opts ...grpc.CallOption) (*GetDiffHunkHeadersResponse, error)
|
||||
DiffCut(ctx context.Context, in *DiffCutRequest, opts ...grpc.CallOption) (*DiffCutResponse, error)
|
||||
}
|
||||
|
||||
type diffServiceClient struct {
|
||||
@ -75,12 +77,32 @@ func (c *diffServiceClient) DiffShortStat(ctx context.Context, in *DiffRequest,
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *diffServiceClient) GetDiffHunkHeaders(ctx context.Context, in *GetDiffHunkHeadersRequest, opts ...grpc.CallOption) (*GetDiffHunkHeadersResponse, error) {
|
||||
out := new(GetDiffHunkHeadersResponse)
|
||||
err := c.cc.Invoke(ctx, "/rpc.DiffService/GetDiffHunkHeaders", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *diffServiceClient) DiffCut(ctx context.Context, in *DiffCutRequest, opts ...grpc.CallOption) (*DiffCutResponse, error) {
|
||||
out := new(DiffCutResponse)
|
||||
err := c.cc.Invoke(ctx, "/rpc.DiffService/DiffCut", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// DiffServiceServer is the server API for DiffService service.
|
||||
// All implementations must embed UnimplementedDiffServiceServer
|
||||
// for forward compatibility
|
||||
type DiffServiceServer interface {
|
||||
RawDiff(*DiffRequest, DiffService_RawDiffServer) error
|
||||
DiffShortStat(context.Context, *DiffRequest) (*DiffShortStatResponse, error)
|
||||
GetDiffHunkHeaders(context.Context, *GetDiffHunkHeadersRequest) (*GetDiffHunkHeadersResponse, error)
|
||||
DiffCut(context.Context, *DiffCutRequest) (*DiffCutResponse, error)
|
||||
mustEmbedUnimplementedDiffServiceServer()
|
||||
}
|
||||
|
||||
@ -94,6 +116,12 @@ func (UnimplementedDiffServiceServer) RawDiff(*DiffRequest, DiffService_RawDiffS
|
||||
func (UnimplementedDiffServiceServer) DiffShortStat(context.Context, *DiffRequest) (*DiffShortStatResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DiffShortStat not implemented")
|
||||
}
|
||||
func (UnimplementedDiffServiceServer) GetDiffHunkHeaders(context.Context, *GetDiffHunkHeadersRequest) (*GetDiffHunkHeadersResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetDiffHunkHeaders not implemented")
|
||||
}
|
||||
func (UnimplementedDiffServiceServer) DiffCut(context.Context, *DiffCutRequest) (*DiffCutResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DiffCut not implemented")
|
||||
}
|
||||
func (UnimplementedDiffServiceServer) mustEmbedUnimplementedDiffServiceServer() {}
|
||||
|
||||
// UnsafeDiffServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
@ -146,6 +174,42 @@ func _DiffService_DiffShortStat_Handler(srv interface{}, ctx context.Context, de
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _DiffService_GetDiffHunkHeaders_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetDiffHunkHeadersRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(DiffServiceServer).GetDiffHunkHeaders(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/rpc.DiffService/GetDiffHunkHeaders",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(DiffServiceServer).GetDiffHunkHeaders(ctx, req.(*GetDiffHunkHeadersRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _DiffService_DiffCut_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(DiffCutRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(DiffServiceServer).DiffCut(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/rpc.DiffService/DiffCut",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(DiffServiceServer).DiffCut(ctx, req.(*DiffCutRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// DiffService_ServiceDesc is the grpc.ServiceDesc for DiffService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@ -157,6 +221,14 @@ var DiffService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "DiffShortStat",
|
||||
Handler: _DiffService_DiffShortStat_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetDiffHunkHeaders",
|
||||
Handler: _DiffService_GetDiffHunkHeaders_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "DiffCut",
|
||||
Handler: _DiffService_DiffCut_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/gitrpc"
|
||||
"github.com/harness/gitness/internal/api/usererror"
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
"github.com/harness/gitness/internal/store"
|
||||
@ -20,12 +21,57 @@ import (
|
||||
)
|
||||
|
||||
type CommentCreateInput struct {
|
||||
// ParentID is set only for replies
|
||||
ParentID int64 `json:"parent_id"`
|
||||
// Text is comment text
|
||||
Text string `json:"text"`
|
||||
Payload *types.PullRequestActivityPayloadComment `json:"payload"`
|
||||
// Used only for code comments
|
||||
TargetCommitSHA string `json:"target_commit_sha"`
|
||||
SourceCommitSHA string `json:"source_commit_sha"`
|
||||
Path string `json:"path"`
|
||||
LineStart int `json:"line_start"`
|
||||
LineStartNew bool `json:"line_start_new"`
|
||||
LineEnd int `json:"line_end"`
|
||||
LineEndNew bool `json:"line_end_new"`
|
||||
}
|
||||
|
||||
// CommentCreate creates a new pull request comment (pull request activity, type=comment).
|
||||
func (in *CommentCreateInput) IsReply() bool {
|
||||
return in.ParentID != 0
|
||||
}
|
||||
|
||||
func (in *CommentCreateInput) IsCodeComment() bool {
|
||||
return in.SourceCommitSHA != ""
|
||||
}
|
||||
|
||||
func (in *CommentCreateInput) Validate() error {
|
||||
// TODO: Validate Text size.
|
||||
|
||||
if in.SourceCommitSHA == "" && in.TargetCommitSHA == "" {
|
||||
return nil // not a code comment
|
||||
}
|
||||
|
||||
if in.SourceCommitSHA == "" || in.TargetCommitSHA == "" {
|
||||
return usererror.BadRequest("for code comments source commit SHA and target commit SHA must be provided")
|
||||
}
|
||||
|
||||
if in.ParentID != 0 {
|
||||
return usererror.BadRequest("can't create a reply that is a code comment")
|
||||
}
|
||||
|
||||
if in.Path == "" {
|
||||
return usererror.BadRequest("code comment requires file path")
|
||||
}
|
||||
|
||||
if in.LineStart <= 0 || in.LineEnd <= 0 {
|
||||
return usererror.BadRequest("code comments require line numbers")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CommentCreate creates a new pull request comment (pull request activity, type=comment/code-comment).
|
||||
//
|
||||
//nolint:gocognit // refactor if needed
|
||||
func (c *Controller) CommentCreate(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
@ -43,17 +89,77 @@ func (c *Controller) CommentCreate(
|
||||
return nil, fmt.Errorf("failed to find pull request by number: %w", err)
|
||||
}
|
||||
|
||||
if errValidate := in.Validate(); errValidate != nil {
|
||||
return nil, errValidate
|
||||
}
|
||||
|
||||
act := getCommentActivity(session, pr, in)
|
||||
|
||||
if in.ParentID != 0 {
|
||||
switch {
|
||||
case in.IsCodeComment():
|
||||
var cut gitrpc.DiffCutOutput
|
||||
|
||||
cut, err = c.gitRPCClient.DiffCut(ctx, &gitrpc.DiffCutParams{
|
||||
ReadParams: gitrpc.ReadParams{RepoUID: repo.GitUID},
|
||||
SourceCommitSHA: in.SourceCommitSHA,
|
||||
SourceBranch: pr.SourceBranch,
|
||||
TargetCommitSHA: in.TargetCommitSHA,
|
||||
TargetBranch: pr.TargetBranch,
|
||||
Path: in.Path,
|
||||
LineStart: in.LineStart,
|
||||
LineStartNew: in.LineStartNew,
|
||||
LineEnd: in.LineEnd,
|
||||
LineEndNew: in.LineEndNew,
|
||||
})
|
||||
if gitrpc.ErrorStatus(err) == gitrpc.StatusNotFound {
|
||||
return nil, usererror.BadRequest(gitrpc.ErrorMessage(err))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
setAsCodeComment(act, cut, in.Path, in.SourceCommitSHA)
|
||||
_ = act.SetPayload(&types.PullRequestActivityPayloadCodeComment{
|
||||
Title: cut.Header.Text,
|
||||
Lines: cut.Lines,
|
||||
AnyNew: cut.AnyNew,
|
||||
})
|
||||
|
||||
err = c.writeActivity(ctx, pr, act)
|
||||
|
||||
// Migrate the comment if necessary... Note: we still need to return the code comment as is.
|
||||
needsNewLineMigrate := in.SourceCommitSHA != cut.LatestSourceSHA
|
||||
needsOldLineMigrate := pr.MergeBaseSHA != nil && *pr.MergeBaseSHA != cut.MergeBaseSHA
|
||||
if err == nil && (needsNewLineMigrate || needsOldLineMigrate) {
|
||||
comments := []*types.CodeComment{act.AsCodeComment()}
|
||||
|
||||
if needsNewLineMigrate {
|
||||
c.codeCommentMigrator.MigrateNew(ctx, repo.GitUID, cut.LatestSourceSHA, comments)
|
||||
}
|
||||
if needsOldLineMigrate {
|
||||
c.codeCommentMigrator.MigrateOld(ctx, repo.GitUID, cut.MergeBaseSHA, comments)
|
||||
}
|
||||
|
||||
if errMigrateUpdate := c.codeCommentView.UpdateAll(ctx, comments); errMigrateUpdate != nil {
|
||||
// non-critical error
|
||||
log.Ctx(ctx).Err(errMigrateUpdate).
|
||||
Msgf("failed to migrate code comment to the latest source/merge-base commit SHA")
|
||||
}
|
||||
}
|
||||
case in.ParentID != 0:
|
||||
var parentAct *types.PullReqActivity
|
||||
parentAct, err = c.checkIsReplyable(ctx, pr, in.ParentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
act.ParentID = &parentAct.ID
|
||||
act.Kind = parentAct.Kind
|
||||
_ = act.SetPayload(types.PullRequestActivityPayloadComment{})
|
||||
|
||||
err = c.writeReplyActivity(ctx, parentAct, act)
|
||||
} else {
|
||||
default:
|
||||
_ = act.SetPayload(types.PullRequestActivityPayloadComment{})
|
||||
err = c.writeActivity(ctx, pr, act)
|
||||
}
|
||||
if err != nil {
|
||||
@ -162,7 +268,24 @@ func getCommentActivity(session *auth.Session, pr *types.PullReq, in *CommentCre
|
||||
Author: *session.Principal.ToPrincipalInfo(),
|
||||
}
|
||||
|
||||
_ = act.SetPayload(in.Payload)
|
||||
|
||||
return act
|
||||
}
|
||||
|
||||
func setAsCodeComment(a *types.PullReqActivity, cut gitrpc.DiffCutOutput, path, sourceCommitSHA string) {
|
||||
var falseBool bool
|
||||
newLine := int64(cut.Header.NewLine)
|
||||
newSpan := int64(cut.Header.NewSpan)
|
||||
oldLine := int64(cut.Header.OldLine)
|
||||
oldSpan := int64(cut.Header.OldSpan)
|
||||
|
||||
a.Type = enum.PullReqActivityTypeCodeComment
|
||||
a.Kind = enum.PullReqActivityKindChangeComment
|
||||
a.Outdated = &falseBool
|
||||
a.CodeCommentMergeBaseSHA = &cut.MergeBaseSHA
|
||||
a.CodeCommentSourceSHA = &sourceCommitSHA
|
||||
a.CodeCommentPath = &path
|
||||
a.CodeCommentLineNew = &newLine
|
||||
a.CodeCommentSpanNew = &newSpan
|
||||
a.CodeCommentLineOld = &oldLine
|
||||
a.CodeCommentSpanOld = &oldSpan
|
||||
}
|
||||
|
@ -6,9 +6,7 @@ package pullreq
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
@ -17,30 +15,11 @@ import (
|
||||
)
|
||||
|
||||
type CommentUpdateInput struct {
|
||||
Text *string `json:"text"`
|
||||
Payload *types.PullRequestActivityPayloadComment `json:"payload"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
func (in *CommentUpdateInput) hasChanges(act *types.PullReqActivity) (bool, error) {
|
||||
if in.Text != nil && *in.Text != act.Text {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if in.Payload != nil {
|
||||
oldPayload, err := act.GetPayload()
|
||||
if errors.Is(err, types.ErrNoPayload) {
|
||||
return true, nil
|
||||
}
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to get old payload: %w", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(oldPayload, in.Payload) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
func (in *CommentUpdateInput) hasChanges(act *types.PullReqActivity) bool {
|
||||
return in.Text != act.Text
|
||||
}
|
||||
|
||||
// CommentUpdate updates a pull request comment.
|
||||
@ -67,23 +46,14 @@ func (c *Controller) CommentUpdate(
|
||||
return nil, fmt.Errorf("failed to get comment: %w", err)
|
||||
}
|
||||
|
||||
hasChanges, err := in.hasChanges(act)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to verify if input has changes: %w", err)
|
||||
}
|
||||
if !hasChanges {
|
||||
if !in.hasChanges(act) {
|
||||
return act, nil
|
||||
}
|
||||
|
||||
now := time.Now().UnixMilli()
|
||||
act.Edited = now
|
||||
|
||||
if in.Text != nil {
|
||||
act.Text = *in.Text
|
||||
}
|
||||
if in.Payload != nil {
|
||||
_ = act.SetPayload(in.Payload)
|
||||
}
|
||||
act.Text = in.Text
|
||||
|
||||
err = c.activityStore.Update(ctx, act)
|
||||
if err != nil {
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
"github.com/harness/gitness/internal/auth/authz"
|
||||
pullreqevents "github.com/harness/gitness/internal/events/pullreq"
|
||||
"github.com/harness/gitness/internal/services/codecomments"
|
||||
"github.com/harness/gitness/internal/store"
|
||||
"github.com/harness/gitness/internal/url"
|
||||
"github.com/harness/gitness/lock"
|
||||
@ -30,6 +31,7 @@ type Controller struct {
|
||||
authorizer authz.Authorizer
|
||||
pullreqStore store.PullReqStore
|
||||
activityStore store.PullReqActivityStore
|
||||
codeCommentView store.CodeCommentView
|
||||
reviewStore store.PullReqReviewStore
|
||||
reviewerStore store.PullReqReviewerStore
|
||||
repoStore store.RepoStore
|
||||
@ -37,6 +39,7 @@ type Controller struct {
|
||||
gitRPCClient gitrpc.Interface
|
||||
eventReporter *pullreqevents.Reporter
|
||||
mtxManager lock.MutexManager
|
||||
codeCommentMigrator *codecomments.Migrator
|
||||
}
|
||||
|
||||
func NewController(
|
||||
@ -45,6 +48,7 @@ func NewController(
|
||||
authorizer authz.Authorizer,
|
||||
pullreqStore store.PullReqStore,
|
||||
pullreqActivityStore store.PullReqActivityStore,
|
||||
codeCommentView store.CodeCommentView,
|
||||
pullreqReviewStore store.PullReqReviewStore,
|
||||
pullreqReviewerStore store.PullReqReviewerStore,
|
||||
repoStore store.RepoStore,
|
||||
@ -52,6 +56,7 @@ func NewController(
|
||||
gitRPCClient gitrpc.Interface,
|
||||
eventReporter *pullreqevents.Reporter,
|
||||
mtxManager lock.MutexManager,
|
||||
codeCommentMigrator *codecomments.Migrator,
|
||||
) *Controller {
|
||||
return &Controller{
|
||||
db: db,
|
||||
@ -59,11 +64,13 @@ func NewController(
|
||||
authorizer: authorizer,
|
||||
pullreqStore: pullreqStore,
|
||||
activityStore: pullreqActivityStore,
|
||||
codeCommentView: codeCommentView,
|
||||
reviewStore: pullreqReviewStore,
|
||||
reviewerStore: pullreqReviewerStore,
|
||||
repoStore: repoStore,
|
||||
principalStore: principalStore,
|
||||
gitRPCClient: gitRPCClient,
|
||||
codeCommentMigrator: codeCommentMigrator,
|
||||
eventReporter: eventReporter,
|
||||
mtxManager: mtxManager,
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ func (c *Controller) Commits(
|
||||
gitRef = pr.SourceSHA
|
||||
}
|
||||
afterRef := pr.TargetBranch
|
||||
if pr.State == enum.PullReqStateMerged {
|
||||
if pr.MergeBaseSHA != nil {
|
||||
afterRef = *pr.MergeBaseSHA
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ func (c *Controller) RawDiff(
|
||||
headRef = pr.SourceSHA
|
||||
}
|
||||
baseRef := pr.TargetBranch
|
||||
if pr.State == enum.PullReqStateMerged {
|
||||
if pr.MergeBaseSHA != nil {
|
||||
baseRef = *pr.MergeBaseSHA
|
||||
}
|
||||
|
||||
|
@ -124,8 +124,6 @@ func (c *Controller) State(ctx context.Context,
|
||||
if in.State == enum.PullReqStateClosed {
|
||||
// clear all merge (check) related fields
|
||||
pr.MergeCheckStatus = enum.MergeCheckStatusUnchecked
|
||||
pr.MergeTargetSHA = nil
|
||||
pr.MergeBaseSHA = nil
|
||||
pr.MergeSHA = nil
|
||||
pr.MergeConflicts = nil
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/harness/gitness/gitrpc"
|
||||
"github.com/harness/gitness/internal/auth/authz"
|
||||
pullreqevents "github.com/harness/gitness/internal/events/pullreq"
|
||||
"github.com/harness/gitness/internal/services/codecomments"
|
||||
"github.com/harness/gitness/internal/store"
|
||||
"github.com/harness/gitness/internal/url"
|
||||
"github.com/harness/gitness/lock"
|
||||
@ -23,13 +24,16 @@ var WireSet = wire.NewSet(
|
||||
|
||||
func ProvideController(db *sqlx.DB, urlProvider *url.Provider, authorizer authz.Authorizer,
|
||||
pullReqStore store.PullReqStore, pullReqActivityStore store.PullReqActivityStore,
|
||||
codeCommentsView store.CodeCommentView,
|
||||
pullReqReviewStore store.PullReqReviewStore, pullReqReviewerStore store.PullReqReviewerStore,
|
||||
repoStore store.RepoStore, principalStore store.PrincipalStore,
|
||||
rpcClient gitrpc.Interface, eventReporter *pullreqevents.Reporter,
|
||||
mtxManager lock.MutexManager) *Controller {
|
||||
mtxManager lock.MutexManager, codeCommentMigrator *codecomments.Migrator) *Controller {
|
||||
return NewController(db, urlProvider, authorizer,
|
||||
pullReqStore, pullReqActivityStore,
|
||||
codeCommentsView,
|
||||
pullReqReviewStore, pullReqReviewerStore,
|
||||
repoStore, principalStore,
|
||||
rpcClient, eventReporter, mtxManager)
|
||||
rpcClient, eventReporter,
|
||||
mtxManager, codeCommentMigrator)
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/check"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
|
200
internal/services/codecomments/migrator.go
Normal file
200
internal/services/codecomments/migrator.go
Normal file
@ -0,0 +1,200 @@
|
||||
// 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 codecomments
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/harness/gitness/gitrpc"
|
||||
"github.com/harness/gitness/types"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// Migrator is a utility used to migrate code comments after update of the pull request's source branch.
|
||||
type Migrator struct {
|
||||
gitRPCClient gitrpc.Interface
|
||||
}
|
||||
|
||||
// MigrateNew updates the "+" (the added lines) part of code comments
|
||||
// after a new commit on the pull request's source branch.
|
||||
// The parameter newSHA should contain the latest commit SHA of the pull request's source branch.
|
||||
func (migrator *Migrator) MigrateNew(
|
||||
ctx context.Context,
|
||||
repoGitUID string,
|
||||
newSHA string,
|
||||
comments []*types.CodeComment,
|
||||
) {
|
||||
migrator.migrate(
|
||||
ctx,
|
||||
repoGitUID,
|
||||
newSHA,
|
||||
comments,
|
||||
func(codeComment *types.CodeComment) string {
|
||||
return codeComment.SourceSHA
|
||||
},
|
||||
func(codeComment *types.CodeComment, sha string) {
|
||||
codeComment.SourceSHA = sha
|
||||
},
|
||||
func(codeComment *types.CodeComment) (int, int) {
|
||||
return codeComment.LineNew, codeComment.LineNew + codeComment.SpanNew - 1
|
||||
},
|
||||
func(codeComment *types.CodeComment, line int) {
|
||||
codeComment.LineNew += line
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// MigrateOld updates the "-" (the removes lines) part of code comments
|
||||
// after the pull request's change of the merge base commit.
|
||||
func (migrator *Migrator) MigrateOld(
|
||||
ctx context.Context,
|
||||
repoGitUID string,
|
||||
newSHA string,
|
||||
comments []*types.CodeComment,
|
||||
) {
|
||||
migrator.migrate(
|
||||
ctx,
|
||||
repoGitUID,
|
||||
newSHA,
|
||||
comments,
|
||||
func(codeComment *types.CodeComment) string {
|
||||
return codeComment.MergeBaseSHA
|
||||
},
|
||||
func(codeComment *types.CodeComment, sha string) {
|
||||
codeComment.MergeBaseSHA = sha
|
||||
},
|
||||
func(codeComment *types.CodeComment) (int, int) {
|
||||
return codeComment.LineOld, codeComment.LineOld + codeComment.SpanOld - 1
|
||||
},
|
||||
func(codeComment *types.CodeComment, line int) {
|
||||
codeComment.LineOld += line
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
//nolint:gocognit // refactor if needed
|
||||
func (migrator *Migrator) migrate(
|
||||
ctx context.Context,
|
||||
repoGitUID string,
|
||||
newSHA string,
|
||||
comments []*types.CodeComment,
|
||||
getSHA func(codeComment *types.CodeComment) string,
|
||||
setSHA func(codeComment *types.CodeComment, sha string),
|
||||
getCommentStartEnd func(codeComment *types.CodeComment) (int, int),
|
||||
updateCommentLine func(codeComment *types.CodeComment, line int),
|
||||
) {
|
||||
if len(comments) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
commitMap := mapCodeComments(comments, getSHA)
|
||||
|
||||
for commentSHA, fileMap := range commitMap {
|
||||
// get all hunk headers for the diff between the SHA that's stored in the comment and the new SHA.
|
||||
diffSummary, errDiff := migrator.gitRPCClient.GetDiffHunkHeaders(ctx, gitrpc.GetDiffHunkHeadersParams{
|
||||
ReadParams: gitrpc.ReadParams{
|
||||
RepoUID: repoGitUID,
|
||||
},
|
||||
SourceCommitSHA: commentSHA,
|
||||
TargetCommitSHA: newSHA,
|
||||
})
|
||||
if gitrpc.ErrorStatus(errDiff) == gitrpc.StatusNotFound {
|
||||
// Handle the commit SHA not found error and mark all code comments as outdated.
|
||||
for _, codeComments := range fileMap {
|
||||
for _, codeComment := range codeComments {
|
||||
codeComment.Outdated = true
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
if errDiff != nil {
|
||||
log.Ctx(ctx).Err(errDiff).
|
||||
Msgf("failed to get git diff between comment's sha %s and the latest %s", commentSHA, newSHA)
|
||||
continue
|
||||
}
|
||||
|
||||
// Traverse all the changed files
|
||||
for _, file := range diffSummary.Files {
|
||||
var codeComments []*types.CodeComment
|
||||
|
||||
codeComments = fileMap[file.FileHeader.OldName]
|
||||
|
||||
// Handle file renames
|
||||
if file.FileHeader.OldName != file.FileHeader.NewName {
|
||||
if len(codeComments) == 0 {
|
||||
// If the code comments are not found using the old name of the file, try with the new name.
|
||||
codeComments = fileMap[file.FileHeader.NewName]
|
||||
} else {
|
||||
// Update the code comment's path to the new file name
|
||||
for _, cc := range codeComments {
|
||||
cc.Path = file.FileHeader.NewName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle file delete
|
||||
if len(file.HunkHeaders) == 1 && file.HunkHeaders[0].NewLine == 0 && file.HunkHeaders[0].NewSpan == 0 {
|
||||
for _, codeComment := range codeComments {
|
||||
codeComment.Outdated = true
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
for _, hunk := range file.HunkHeaders {
|
||||
hunkStart := hunk.NewLine
|
||||
hunkEnd := hunk.NewLine + hunk.NewSpan - 1
|
||||
for _, cc := range codeComments {
|
||||
commentStart, commentEnd := getCommentStartEnd(cc)
|
||||
if commentEnd < hunkStart {
|
||||
continue
|
||||
}
|
||||
|
||||
outdated := commentStart <= hunkEnd
|
||||
cc.Outdated = outdated
|
||||
|
||||
if outdated {
|
||||
continue
|
||||
}
|
||||
|
||||
updateCommentLine(cc, hunk.NewSpan-hunk.OldSpan)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, codeComments := range fileMap {
|
||||
for _, codeComment := range codeComments {
|
||||
if codeComment.Outdated {
|
||||
continue
|
||||
}
|
||||
setSHA(codeComment, newSHA)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mapCodeComments groups code comments to maps, first by commit SHA and then by file name.
|
||||
// It assumes the incoming list is already sorted.
|
||||
func mapCodeComments(
|
||||
comments []*types.CodeComment,
|
||||
extractSHA func(*types.CodeComment) string,
|
||||
) map[string]map[string][]*types.CodeComment {
|
||||
commitMap := map[string]map[string][]*types.CodeComment{}
|
||||
for _, comment := range comments {
|
||||
commitSHA := extractSHA(comment)
|
||||
|
||||
fileMap := commitMap[commitSHA]
|
||||
if fileMap == nil {
|
||||
fileMap = map[string][]*types.CodeComment{}
|
||||
}
|
||||
|
||||
fileComments := fileMap[comment.Path]
|
||||
fileComments = append(fileComments, comment)
|
||||
fileMap[comment.Path] = fileComments
|
||||
|
||||
commitMap[commitSHA] = fileMap
|
||||
}
|
||||
|
||||
return commitMap
|
||||
}
|
23
internal/services/codecomments/wire.go
Normal file
23
internal/services/codecomments/wire.go
Normal file
@ -0,0 +1,23 @@
|
||||
// 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 codecomments
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/gitrpc"
|
||||
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
var WireSet = wire.NewSet(
|
||||
ProvideMigrator,
|
||||
)
|
||||
|
||||
func ProvideMigrator(
|
||||
gitRPCClient gitrpc.Interface,
|
||||
) *Migrator {
|
||||
return &Migrator{
|
||||
gitRPCClient: gitRPCClient,
|
||||
}
|
||||
}
|
@ -36,8 +36,6 @@ func (s *Service) triggerPREventOnBranchUpdate(ctx context.Context,
|
||||
|
||||
// reset merge-check fields for new run
|
||||
pr.MergeCheckStatus = enum.MergeCheckStatusUnchecked
|
||||
pr.MergeTargetSHA = nil
|
||||
pr.MergeBaseSHA = nil
|
||||
pr.MergeSHA = nil
|
||||
pr.MergeConflicts = nil
|
||||
return nil
|
||||
@ -85,8 +83,6 @@ func (s *Service) closePullReqOnBranchDelete(ctx context.Context,
|
||||
|
||||
pr.State = enum.PullReqStateClosed
|
||||
pr.MergeCheckStatus = enum.MergeCheckStatusUnchecked
|
||||
pr.MergeTargetSHA = nil
|
||||
pr.MergeBaseSHA = nil
|
||||
pr.MergeSHA = nil
|
||||
pr.MergeConflicts = nil
|
||||
|
||||
|
72
internal/services/pullreq/handlers_code_comments.go
Normal file
72
internal/services/pullreq/handlers_code_comments.go
Normal file
@ -0,0 +1,72 @@
|
||||
// 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 pullreq
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/events"
|
||||
pullreqevents "github.com/harness/gitness/internal/events/pullreq"
|
||||
"github.com/harness/gitness/types"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func (s *Service) updateCodeCommentsOnBranchUpdate(ctx context.Context,
|
||||
event *events.Event[*pullreqevents.BranchUpdatedPayload],
|
||||
) error {
|
||||
oldSourceSHA := event.Payload.OldSHA // NOTE: we're ignoring the old value and instead try to update all
|
||||
newSourceSHA := event.Payload.NewSHA
|
||||
|
||||
log.Ctx(ctx).Debug().
|
||||
Str("oldSHA", oldSourceSHA).
|
||||
Str("newSHA", newSourceSHA).
|
||||
Msgf("code comment update after source branch update")
|
||||
|
||||
repoGit, err := s.repoGitInfoCache.Get(ctx, event.Payload.SourceRepoID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get repo git info: %w", err)
|
||||
}
|
||||
|
||||
codeComments, err := s.codeCommentView.ListNotAtSourceSHA(ctx, event.Payload.PullReqID, newSourceSHA)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get list of code comments for update after source branch update: %w", err)
|
||||
}
|
||||
|
||||
s.codeCommentMigrator.MigrateNew(ctx, repoGit.GitUID, newSourceSHA, codeComments)
|
||||
|
||||
err = s.codeCommentView.UpdateAll(ctx, codeComments)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update code comments after source branch update: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) updateCodeCommentsOnMergeBaseUpdate(ctx context.Context,
|
||||
pr *types.PullReq,
|
||||
gitUID string,
|
||||
oldMergeBaseSHA, newMergeBaseSHA string,
|
||||
) error {
|
||||
log.Ctx(ctx).Debug().
|
||||
Str("oldSHA", oldMergeBaseSHA).
|
||||
Str("newSHA", newMergeBaseSHA).
|
||||
Msgf("code comment update after merge base update")
|
||||
|
||||
codeComments, err := s.codeCommentView.ListNotAtMergeBaseSHA(ctx, pr.ID, newMergeBaseSHA)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get list of code comments for update after merge base update: %w", err)
|
||||
}
|
||||
|
||||
s.codeCommentMigrator.MigrateOld(ctx, gitUID, newMergeBaseSHA, codeComments)
|
||||
|
||||
err = s.codeCommentView.UpdateAll(ctx, codeComments)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update code comments after merge base update: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -122,7 +122,7 @@ func (s *Service) deleteMergeRef(ctx context.Context, principalID int64, repoID
|
||||
return nil
|
||||
}
|
||||
|
||||
//nolint:funlen // refactor if required.
|
||||
//nolint:funlen,gocognit // refactor if required.
|
||||
func (s *Service) updateMergeData(
|
||||
ctx context.Context,
|
||||
principalID int64,
|
||||
@ -161,14 +161,14 @@ func (s *Service) updateMergeData(
|
||||
}()
|
||||
|
||||
// load repository objects
|
||||
targetRepo, err := s.repoStore.Find(ctx, pr.TargetRepoID)
|
||||
targetRepo, err := s.repoGitInfoCache.Get(ctx, pr.TargetRepoID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sourceRepo := targetRepo
|
||||
if pr.TargetRepoID != pr.SourceRepoID {
|
||||
sourceRepo, err = s.repoStore.Find(ctx, pr.SourceRepoID)
|
||||
sourceRepo, err = s.repoGitInfoCache.Get(ctx, pr.SourceRepoID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -187,8 +187,7 @@ func (s *Service) updateMergeData(
|
||||
}
|
||||
|
||||
// call merge and store output in pr merge reference.
|
||||
var output gitrpc.MergeOutput
|
||||
output, err = s.gitRPCClient.Merge(ctx, &gitrpc.MergeParams{
|
||||
output, err := s.gitRPCClient.Merge(ctx, &gitrpc.MergeParams{
|
||||
WriteParams: gitrpc.WriteParams{
|
||||
RepoUID: targetRepo.GitUID,
|
||||
Actor: gitrpc.Identity{
|
||||
@ -212,8 +211,10 @@ func (s *Service) updateMergeData(
|
||||
|
||||
isNotMergeableError := gitrpc.ErrorStatus(err) == gitrpc.StatusNotMergeable
|
||||
if err != nil && !isNotMergeableError {
|
||||
return fmt.Errorf("merge check failed for %s and %s with err: %w",
|
||||
targetRepo.UID+":"+pr.TargetBranch, sourceRepo.UID+":"+pr.SourceBranch, err)
|
||||
return fmt.Errorf("merge check failed for %d:%s and %d:%s with err: %w",
|
||||
targetRepo.ID, pr.TargetBranch,
|
||||
sourceRepo.ID, pr.SourceBranch,
|
||||
err)
|
||||
}
|
||||
|
||||
// Update DB in both cases (failure or success)
|
||||
@ -225,8 +226,8 @@ func (s *Service) updateMergeData(
|
||||
if isNotMergeableError {
|
||||
// TODO: gitrpc should return sha's either way, and also conflicting files!
|
||||
pr.MergeCheckStatus = enum.MergeCheckStatusConflict
|
||||
pr.MergeTargetSHA = nil
|
||||
pr.MergeBaseSHA = nil
|
||||
pr.MergeTargetSHA = &output.BaseSHA
|
||||
pr.MergeBaseSHA = &output.MergeBaseSHA
|
||||
pr.MergeSHA = nil
|
||||
pr.MergeConflicts = nil
|
||||
} else {
|
||||
@ -242,5 +243,14 @@ func (s *Service) updateMergeData(
|
||||
return fmt.Errorf("failed to update PR merge ref in db with error: %w", err)
|
||||
}
|
||||
|
||||
if pr.MergeBaseSHA != nil && *pr.MergeBaseSHA != output.MergeBaseSHA {
|
||||
oldMergeBaseSHA := *pr.MergeBaseSHA
|
||||
newMergeBaseSHA := output.MergeBaseSHA
|
||||
err = s.updateCodeCommentsOnMergeBaseUpdate(ctx, pr, sourceRepo.GitUID, oldMergeBaseSHA, newMergeBaseSHA)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update code comment after merge base SHA change: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"github.com/harness/gitness/gitrpc"
|
||||
gitevents "github.com/harness/gitness/internal/events/git"
|
||||
pullreqevents "github.com/harness/gitness/internal/events/pullreq"
|
||||
"github.com/harness/gitness/internal/services/codecomments"
|
||||
"github.com/harness/gitness/internal/store"
|
||||
"github.com/harness/gitness/pubsub"
|
||||
"github.com/harness/gitness/stream"
|
||||
@ -30,6 +31,8 @@ type Service struct {
|
||||
repoStore store.RepoStore
|
||||
pullreqStore store.PullReqStore
|
||||
activityStore store.PullReqActivityStore
|
||||
codeCommentView store.CodeCommentView
|
||||
codeCommentMigrator *codecomments.Migrator
|
||||
|
||||
cancelMutex sync.Mutex
|
||||
cancelMergability map[string]context.CancelFunc
|
||||
@ -50,6 +53,8 @@ func New(ctx context.Context,
|
||||
repoStore store.RepoStore,
|
||||
pullreqStore store.PullReqStore,
|
||||
activityStore store.PullReqActivityStore,
|
||||
codeCommentView store.CodeCommentView,
|
||||
codeCommentMigrator *codecomments.Migrator,
|
||||
bus pubsub.PubSub,
|
||||
) (*Service, error) {
|
||||
service := &Service{
|
||||
@ -61,6 +66,8 @@ func New(ctx context.Context,
|
||||
repoStore: repoStore,
|
||||
pullreqStore: pullreqStore,
|
||||
activityStore: activityStore,
|
||||
codeCommentView: codeCommentView,
|
||||
codeCommentMigrator: codeCommentMigrator,
|
||||
cancelMergability: make(map[string]context.CancelFunc),
|
||||
pubsub: bus,
|
||||
}
|
||||
@ -179,5 +186,25 @@ func New(ctx context.Context,
|
||||
return nil
|
||||
}, pubsub.WithChannelNamespace("pullreq"))
|
||||
|
||||
// mergability check
|
||||
const groupPullReqCodeComments = "gitness:pullreq:codecomments"
|
||||
_, err = pullreqEvReaderFactory.Launch(ctx, groupPullReqCodeComments, config.InstanceID,
|
||||
func(r *pullreqevents.Reader) error {
|
||||
const idleTimeout = 10 * time.Second
|
||||
r.Configure(
|
||||
stream.WithConcurrency(3),
|
||||
stream.WithHandlerOptions(
|
||||
stream.WithIdleTimeout(idleTimeout),
|
||||
stream.WithMaxRetries(2),
|
||||
))
|
||||
|
||||
_ = r.RegisterBranchUpdated(service.updateCodeCommentsOnBranchUpdate)
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return service, nil
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"github.com/harness/gitness/gitrpc"
|
||||
gitevents "github.com/harness/gitness/internal/events/git"
|
||||
pullreqevents "github.com/harness/gitness/internal/events/pullreq"
|
||||
"github.com/harness/gitness/internal/services/codecomments"
|
||||
"github.com/harness/gitness/internal/store"
|
||||
"github.com/harness/gitness/pubsub"
|
||||
"github.com/harness/gitness/types"
|
||||
@ -35,8 +36,11 @@ func ProvideService(ctx context.Context,
|
||||
repoStore store.RepoStore,
|
||||
pullreqStore store.PullReqStore,
|
||||
activityStore store.PullReqActivityStore,
|
||||
codeCommentView store.CodeCommentView,
|
||||
codeCommentMigrator *codecomments.Migrator,
|
||||
pubsub pubsub.PubSub,
|
||||
) (*Service, error) {
|
||||
return New(ctx, config, gitReaderFactory, pullReqEvFactory, pullReqEvReporter, gitRPCClient,
|
||||
db, repoGitInfoCache, principalCache, repoStore, pullreqStore, activityStore, pubsub)
|
||||
db, repoGitInfoCache, principalCache, repoStore, pullreqStore, activityStore,
|
||||
codeCommentView, codeCommentMigrator, pubsub)
|
||||
}
|
||||
|
@ -20,7 +20,10 @@ type Services struct {
|
||||
bms *pullreq.Service
|
||||
}
|
||||
|
||||
func ProvideServices(ws *webhook.Service, bms *pullreq.Service) Services {
|
||||
func ProvideServices(
|
||||
ws *webhook.Service,
|
||||
bms *pullreq.Service,
|
||||
) Services {
|
||||
return Services{
|
||||
ws: ws,
|
||||
bms: bms,
|
||||
|
@ -302,6 +302,22 @@ type (
|
||||
List(ctx context.Context, prID int64, opts *types.PullReqActivityFilter) ([]*types.PullReqActivity, error)
|
||||
}
|
||||
|
||||
// CodeCommentView is to manipulate only code-comment subset of PullReqActivity.
|
||||
// It's used by internal service that migrates code comment line numbers after new commits.
|
||||
CodeCommentView interface {
|
||||
// ListNotAtSourceSHA loads code comments that need to be updated after a new commit.
|
||||
// Resulting list is ordered by the file name and the relevant line number.
|
||||
ListNotAtSourceSHA(ctx context.Context, prID int64, sourceSHA string) ([]*types.CodeComment, error)
|
||||
|
||||
// ListNotAtMergeBaseSHA loads code comments that need to be updated after merge base update.
|
||||
// Resulting list is ordered by the file name and the relevant line number.
|
||||
ListNotAtMergeBaseSHA(ctx context.Context, prID int64, targetSHA string) ([]*types.CodeComment, error)
|
||||
|
||||
// UpdateAll updates code comments (pull request activity of types code-comment).
|
||||
// entities coming from the input channel.
|
||||
UpdateAll(ctx context.Context, codeComments []*types.CodeComment) error
|
||||
}
|
||||
|
||||
// PullReqReviewStore defines the pull request review storage.
|
||||
PullReqReviewStore interface {
|
||||
// Find returns the pull request review entity or an error if it doesn't exist.
|
||||
|
151
internal/store/database/code_comment.go
Normal file
151
internal/store/database/code_comment.go
Normal file
@ -0,0 +1,151 @@
|
||||
// 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 database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/internal/store"
|
||||
"github.com/harness/gitness/internal/store/database/dbtx"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var _ store.CodeCommentView = (*CodeCommentView)(nil)
|
||||
|
||||
// NewCodeCommentView returns a new CodeCommentView.
|
||||
func NewCodeCommentView(db *sqlx.DB) *CodeCommentView {
|
||||
return &CodeCommentView{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
// CodeCommentView implements store.CodeCommentView backed by a relational database.
|
||||
type CodeCommentView struct {
|
||||
db *sqlx.DB
|
||||
}
|
||||
|
||||
// ListNotAtSourceSHA lists all code comments not already at the provided source SHA.
|
||||
func (s *CodeCommentView) ListNotAtSourceSHA(ctx context.Context,
|
||||
prID int64, sourceSHA string,
|
||||
) ([]*types.CodeComment, error) {
|
||||
return s.list(ctx, prID, "", sourceSHA)
|
||||
}
|
||||
|
||||
// ListNotAtMergeBaseSHA lists all code comments not already at the provided merge base SHA.
|
||||
func (s *CodeCommentView) ListNotAtMergeBaseSHA(ctx context.Context,
|
||||
prID int64, mergeBaseSHA string,
|
||||
) ([]*types.CodeComment, error) {
|
||||
return s.list(ctx, prID, mergeBaseSHA, "")
|
||||
}
|
||||
|
||||
// list is used by internal service that updates line numbers of code comments after
|
||||
// branch updates and requires either mergeBaseSHA or sourceSHA but not both.
|
||||
// Resulting list is ordered by the file name and the relevant line number.
|
||||
func (s *CodeCommentView) list(ctx context.Context,
|
||||
prID int64, mergeBaseSHA, sourceSHA string,
|
||||
) ([]*types.CodeComment, error) {
|
||||
const codeCommentColumns = `
|
||||
pullreq_activity_id
|
||||
,pullreq_activity_version
|
||||
,pullreq_activity_updated
|
||||
,coalesce(pullreq_activity_outdated, false) as "pullreq_activity_outdated"
|
||||
,coalesce(pullreq_activity_code_comment_merge_base_sha, '') as "pullreq_activity_code_comment_merge_base_sha"
|
||||
,coalesce(pullreq_activity_code_comment_source_sha, '') as "pullreq_activity_code_comment_source_sha"
|
||||
,coalesce(pullreq_activity_code_comment_path, '') as "pullreq_activity_code_comment_path"
|
||||
,coalesce(pullreq_activity_code_comment_line_new, 1) as "pullreq_activity_code_comment_line_new"
|
||||
,coalesce(pullreq_activity_code_comment_span_new, 0) as "pullreq_activity_code_comment_span_new"
|
||||
,coalesce(pullreq_activity_code_comment_line_old, 1) as "pullreq_activity_code_comment_line_old"
|
||||
,coalesce(pullreq_activity_code_comment_span_old, 0) as "pullreq_activity_code_comment_span_old"`
|
||||
|
||||
stmt := builder.
|
||||
Select(codeCommentColumns).
|
||||
From("pullreq_activities").
|
||||
Where("pullreq_activity_pullreq_id = ?", prID).
|
||||
Where("not pullreq_activity_outdated").
|
||||
Where("pullreq_activity_type = ?", enum.PullReqActivityTypeCodeComment).
|
||||
Where("pullreq_activity_kind = ?", enum.PullReqActivityKindChangeComment).
|
||||
Where("pullreq_activity_deleted is null and pullreq_activity_parent_id is null")
|
||||
|
||||
if mergeBaseSHA != "" {
|
||||
stmt = stmt.
|
||||
Where("pullreq_activity_code_comment_merge_base_sha <> ?", mergeBaseSHA)
|
||||
} else {
|
||||
stmt = stmt.
|
||||
Where("pullreq_activity_code_comment_source_sha <> ?", sourceSHA)
|
||||
}
|
||||
|
||||
stmt = stmt.OrderBy("pullreq_activity_code_comment_path asc",
|
||||
"pullreq_activity_code_comment_line_new asc")
|
||||
|
||||
sql, args, err := stmt.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to convert pull request activity query to sql")
|
||||
}
|
||||
|
||||
result := make([]*types.CodeComment, 0)
|
||||
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
if err = db.SelectContext(ctx, &result, sql, args...); err != nil {
|
||||
return nil, processSQLErrorf(err, "Failed executing code comment list query")
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// UpdateAll updates all code comments provided in the slice.
|
||||
func (s *CodeCommentView) UpdateAll(ctx context.Context, codeComments []*types.CodeComment) error {
|
||||
const sqlQuery = `
|
||||
UPDATE pullreq_activities
|
||||
SET
|
||||
pullreq_activity_version = :pullreq_activity_version
|
||||
,pullreq_activity_updated = :pullreq_activity_updated
|
||||
,pullreq_activity_outdated = :pullreq_activity_outdated
|
||||
,pullreq_activity_code_comment_merge_base_sha = :pullreq_activity_code_comment_merge_base_sha
|
||||
,pullreq_activity_code_comment_source_sha = :pullreq_activity_code_comment_source_sha
|
||||
,pullreq_activity_code_comment_path = :pullreq_activity_code_comment_path
|
||||
,pullreq_activity_code_comment_line_new = :pullreq_activity_code_comment_line_new
|
||||
,pullreq_activity_code_comment_span_new = :pullreq_activity_code_comment_span_new
|
||||
,pullreq_activity_code_comment_line_old = :pullreq_activity_code_comment_line_old
|
||||
,pullreq_activity_code_comment_span_old = :pullreq_activity_code_comment_span_old
|
||||
WHERE pullreq_activity_id = :pullreq_activity_id AND pullreq_activity_version = :pullreq_activity_version - 1`
|
||||
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
stmt, err := db.PrepareNamedContext(ctx, sqlQuery)
|
||||
if err != nil {
|
||||
return processSQLErrorf(err, "Failed to prepare update statement for update code comments")
|
||||
}
|
||||
|
||||
updatedAt := time.Now()
|
||||
|
||||
for _, codeComment := range codeComments {
|
||||
codeComment.Version++
|
||||
codeComment.Updated = updatedAt.UnixMilli()
|
||||
|
||||
result, err := stmt.ExecContext(ctx, codeComment)
|
||||
if err != nil {
|
||||
return processSQLErrorf(err, "Failed to update code comment=%d", codeComment.ID)
|
||||
}
|
||||
|
||||
count, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return processSQLErrorf(err, "Failed to get number of updated rows for code comment=%d", codeComment.ID)
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
log.Ctx(ctx).Warn().Msgf("Version conflict when trying to update code comment=%d", codeComment.ID)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
-- Can't migrate down from this point.
|
||||
-- This file must be present here.
|
@ -0,0 +1,9 @@
|
||||
ALTER TABLE pullreq_activities
|
||||
DROP COLUMN pullreq_activity_outdated,
|
||||
DROP COLUMN pullreq_activity_code_comment_merge_base_sha,
|
||||
DROP COLUMN pullreq_activity_code_comment_source_sha,
|
||||
DROP COLUMN pullreq_activity_code_comment_path,
|
||||
DROP COLUMN pullreq_activity_code_comment_line_new,
|
||||
DROP COLUMN pullreq_activity_code_comment_span_new,
|
||||
DROP COLUMN pullreq_activity_code_comment_line_old,
|
||||
DROP COLUMN pullreq_activity_code_comment_span_old;
|
@ -0,0 +1,9 @@
|
||||
ALTER TABLE pullreq_activities
|
||||
ADD COLUMN pullreq_activity_outdated BOOLEAN,
|
||||
ADD COLUMN pullreq_activity_code_comment_merge_base_sha TEXT,
|
||||
ADD COLUMN pullreq_activity_code_comment_source_sha TEXT,
|
||||
ADD COLUMN pullreq_activity_code_comment_path TEXT,
|
||||
ADD COLUMN pullreq_activity_code_comment_line_new INTEGER,
|
||||
ADD COLUMN pullreq_activity_code_comment_span_new INTEGER,
|
||||
ADD COLUMN pullreq_activity_code_comment_line_old INTEGER,
|
||||
ADD COLUMN pullreq_activity_code_comment_span_old INTEGER;
|
@ -0,0 +1,2 @@
|
||||
-- Can't migrate down from this point.
|
||||
-- This file must be present here.
|
@ -0,0 +1,8 @@
|
||||
ALTER TABLE pullreq_activities DROP COLUMN pullreq_activity_outdated;
|
||||
ALTER TABLE pullreq_activities DROP COLUMN pullreq_activity_code_comment_merge_base_sha;
|
||||
ALTER TABLE pullreq_activities DROP COLUMN pullreq_activity_code_comment_source_sha;
|
||||
ALTER TABLE pullreq_activities DROP COLUMN pullreq_activity_code_comment_path;
|
||||
ALTER TABLE pullreq_activities DROP COLUMN pullreq_activity_code_comment_line_new;
|
||||
ALTER TABLE pullreq_activities DROP COLUMN pullreq_activity_code_comment_span_new;
|
||||
ALTER TABLE pullreq_activities DROP COLUMN pullreq_activity_code_comment_line_old;
|
||||
ALTER TABLE pullreq_activities DROP COLUMN pullreq_activity_code_comment_span_old;
|
@ -0,0 +1,8 @@
|
||||
ALTER TABLE pullreq_activities ADD COLUMN pullreq_activity_outdated BOOLEAN;
|
||||
ALTER TABLE pullreq_activities ADD COLUMN pullreq_activity_code_comment_merge_base_sha TEXT;
|
||||
ALTER TABLE pullreq_activities ADD COLUMN pullreq_activity_code_comment_source_sha TEXT;
|
||||
ALTER TABLE pullreq_activities ADD COLUMN pullreq_activity_code_comment_path TEXT;
|
||||
ALTER TABLE pullreq_activities ADD COLUMN pullreq_activity_code_comment_line_new INTEGER;
|
||||
ALTER TABLE pullreq_activities ADD COLUMN pullreq_activity_code_comment_span_new INTEGER;
|
||||
ALTER TABLE pullreq_activities ADD COLUMN pullreq_activity_code_comment_line_old INTEGER;
|
||||
ALTER TABLE pullreq_activities ADD COLUMN pullreq_activity_code_comment_span_old INTEGER;
|
@ -68,6 +68,15 @@ type pullReqActivity struct {
|
||||
|
||||
ResolvedBy null.Int `db:"pullreq_activity_resolved_by"`
|
||||
Resolved null.Int `db:"pullreq_activity_resolved"`
|
||||
|
||||
Outdated null.Bool `db:"pullreq_activity_outdated"`
|
||||
CodeCommentMergeBaseSHA null.String `db:"pullreq_activity_code_comment_merge_base_sha"`
|
||||
CodeCommentSourceSHA null.String `db:"pullreq_activity_code_comment_source_sha"`
|
||||
CodeCommentPath null.String `db:"pullreq_activity_code_comment_path"`
|
||||
CodeCommentLineNew null.Int `db:"pullreq_activity_code_comment_line_new"`
|
||||
CodeCommentSpanNew null.Int `db:"pullreq_activity_code_comment_span_new"`
|
||||
CodeCommentLineOld null.Int `db:"pullreq_activity_code_comment_line_old"`
|
||||
CodeCommentSpanOld null.Int `db:"pullreq_activity_code_comment_span_old"`
|
||||
}
|
||||
|
||||
const (
|
||||
@ -91,7 +100,15 @@ const (
|
||||
,pullreq_activity_payload
|
||||
,pullreq_activity_metadata
|
||||
,pullreq_activity_resolved_by
|
||||
,pullreq_activity_resolved`
|
||||
,pullreq_activity_resolved
|
||||
,pullreq_activity_outdated
|
||||
,pullreq_activity_code_comment_merge_base_sha
|
||||
,pullreq_activity_code_comment_source_sha
|
||||
,pullreq_activity_code_comment_path
|
||||
,pullreq_activity_code_comment_line_new
|
||||
,pullreq_activity_code_comment_span_new
|
||||
,pullreq_activity_code_comment_line_old
|
||||
,pullreq_activity_code_comment_span_old`
|
||||
|
||||
pullreqActivitySelectBase = `
|
||||
SELECT` + pullreqActivityColumns + `
|
||||
@ -136,6 +153,14 @@ func (s *PullReqActivityStore) Create(ctx context.Context, act *types.PullReqAct
|
||||
,pullreq_activity_metadata
|
||||
,pullreq_activity_resolved_by
|
||||
,pullreq_activity_resolved
|
||||
,pullreq_activity_outdated
|
||||
,pullreq_activity_code_comment_merge_base_sha
|
||||
,pullreq_activity_code_comment_source_sha
|
||||
,pullreq_activity_code_comment_path
|
||||
,pullreq_activity_code_comment_line_new
|
||||
,pullreq_activity_code_comment_span_new
|
||||
,pullreq_activity_code_comment_line_old
|
||||
,pullreq_activity_code_comment_span_old
|
||||
) values (
|
||||
:pullreq_activity_version
|
||||
,:pullreq_activity_created_by
|
||||
@ -156,6 +181,14 @@ func (s *PullReqActivityStore) Create(ctx context.Context, act *types.PullReqAct
|
||||
,:pullreq_activity_metadata
|
||||
,:pullreq_activity_resolved_by
|
||||
,:pullreq_activity_resolved
|
||||
,:pullreq_activity_outdated
|
||||
,:pullreq_activity_code_comment_merge_base_sha
|
||||
,:pullreq_activity_code_comment_source_sha
|
||||
,:pullreq_activity_code_comment_path
|
||||
,:pullreq_activity_code_comment_line_new
|
||||
,:pullreq_activity_code_comment_span_new
|
||||
,:pullreq_activity_code_comment_line_old
|
||||
,:pullreq_activity_code_comment_span_old
|
||||
) RETURNING pullreq_activity_id`
|
||||
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
@ -217,6 +250,14 @@ func (s *PullReqActivityStore) Update(ctx context.Context, act *types.PullReqAct
|
||||
,pullreq_activity_metadata = :pullreq_activity_metadata
|
||||
,pullreq_activity_resolved_by = :pullreq_activity_resolved_by
|
||||
,pullreq_activity_resolved = :pullreq_activity_resolved
|
||||
,pullreq_activity_outdated = :pullreq_activity_outdated
|
||||
,pullreq_activity_code_comment_merge_base_sha = :pullreq_activity_code_comment_merge_base_sha
|
||||
,pullreq_activity_code_comment_source_sha = :pullreq_activity_code_comment_source_sha
|
||||
,pullreq_activity_code_comment_path = :pullreq_activity_code_comment_path
|
||||
,pullreq_activity_code_comment_line_new = :pullreq_activity_code_comment_line_new
|
||||
,pullreq_activity_code_comment_span_new = :pullreq_activity_code_comment_span_new
|
||||
,pullreq_activity_code_comment_line_old = :pullreq_activity_code_comment_line_old
|
||||
,pullreq_activity_code_comment_span_old = :pullreq_activity_code_comment_span_old
|
||||
WHERE pullreq_activity_id = :pullreq_activity_id AND pullreq_activity_version = :pullreq_activity_version - 1`
|
||||
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
@ -397,6 +438,14 @@ func mapPullReqActivity(act *pullReqActivity) *types.PullReqActivity {
|
||||
Resolved: act.Resolved.Ptr(),
|
||||
Author: types.PrincipalInfo{},
|
||||
Resolver: nil,
|
||||
Outdated: act.Outdated.Ptr(),
|
||||
CodeCommentMergeBaseSHA: act.CodeCommentMergeBaseSHA.Ptr(),
|
||||
CodeCommentSourceSHA: act.CodeCommentSourceSHA.Ptr(),
|
||||
CodeCommentPath: act.CodeCommentPath.Ptr(),
|
||||
CodeCommentLineNew: act.CodeCommentLineNew.Ptr(),
|
||||
CodeCommentSpanNew: act.CodeCommentSpanNew.Ptr(),
|
||||
CodeCommentLineOld: act.CodeCommentLineOld.Ptr(),
|
||||
CodeCommentSpanOld: act.CodeCommentSpanOld.Ptr(),
|
||||
}
|
||||
|
||||
_ = json.Unmarshal(act.Metadata, &m.Metadata)
|
||||
@ -426,6 +475,14 @@ func mapInternalPullReqActivity(act *types.PullReqActivity) *pullReqActivity {
|
||||
Metadata: nil,
|
||||
ResolvedBy: null.IntFromPtr(act.ResolvedBy),
|
||||
Resolved: null.IntFromPtr(act.Resolved),
|
||||
Outdated: null.BoolFromPtr(act.Outdated),
|
||||
CodeCommentMergeBaseSHA: null.StringFromPtr(act.CodeCommentMergeBaseSHA),
|
||||
CodeCommentSourceSHA: null.StringFromPtr(act.CodeCommentSourceSHA),
|
||||
CodeCommentPath: null.StringFromPtr(act.CodeCommentPath),
|
||||
CodeCommentLineNew: null.IntFromPtr(act.CodeCommentLineNew),
|
||||
CodeCommentSpanNew: null.IntFromPtr(act.CodeCommentSpanNew),
|
||||
CodeCommentLineOld: null.IntFromPtr(act.CodeCommentLineOld),
|
||||
CodeCommentSpanOld: null.IntFromPtr(act.CodeCommentSpanOld),
|
||||
}
|
||||
|
||||
m.Metadata, _ = json.Marshal(act.Metadata)
|
||||
|
@ -26,6 +26,7 @@ var WireSet = wire.NewSet(
|
||||
ProvideTokenStore,
|
||||
ProvidePullReqStore,
|
||||
ProvidePullReqActivityStore,
|
||||
ProvideCodeCommentView,
|
||||
ProvidePullReqReviewStore,
|
||||
ProvidePullReqReviewerStore,
|
||||
ProvideWebhookStore,
|
||||
@ -88,6 +89,11 @@ func ProvidePullReqActivityStore(db *sqlx.DB,
|
||||
return NewPullReqActivityStore(db, principalInfoCache)
|
||||
}
|
||||
|
||||
// ProvideCodeCommentView provides a code comment view.
|
||||
func ProvideCodeCommentView(db *sqlx.DB) store.CodeCommentView {
|
||||
return NewCodeCommentView(db)
|
||||
}
|
||||
|
||||
// ProvidePullReqReviewStore provides a pull request review store.
|
||||
func ProvidePullReqReviewStore(db *sqlx.DB) store.PullReqReviewStore {
|
||||
return NewPullReqReviewStore(db)
|
||||
|
20
types/code_comment.go
Normal file
20
types/code_comment.go
Normal file
@ -0,0 +1,20 @@
|
||||
// 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 types
|
||||
|
||||
type CodeComment struct {
|
||||
ID int64 `db:"pullreq_activity_id"`
|
||||
Version int64 `db:"pullreq_activity_version"`
|
||||
Updated int64 `db:"pullreq_activity_updated"`
|
||||
|
||||
Outdated bool `db:"pullreq_activity_outdated"`
|
||||
MergeBaseSHA string `db:"pullreq_activity_code_comment_merge_base_sha"`
|
||||
SourceSHA string `db:"pullreq_activity_code_comment_source_sha"`
|
||||
Path string `db:"pullreq_activity_code_comment_path"`
|
||||
LineNew int `db:"pullreq_activity_code_comment_line_new"`
|
||||
SpanNew int `db:"pullreq_activity_code_comment_span_new"`
|
||||
LineOld int `db:"pullreq_activity_code_comment_line_old"`
|
||||
SpanOld int `db:"pullreq_activity_code_comment_span_old"`
|
||||
}
|
@ -102,13 +102,13 @@ func GetAllPullReqActivityKinds() ([]PullReqActivityKind, PullReqActivityKind) {
|
||||
const (
|
||||
PullReqActivityKindSystem PullReqActivityKind = "system"
|
||||
PullReqActivityKindComment PullReqActivityKind = "comment"
|
||||
PullReqActivityKindCodeComment PullReqActivityKind = "code"
|
||||
PullReqActivityKindChangeComment PullReqActivityKind = "change-comment"
|
||||
)
|
||||
|
||||
var pullReqActivityKinds = sortEnum([]PullReqActivityKind{
|
||||
PullReqActivityKindSystem,
|
||||
PullReqActivityKindComment,
|
||||
PullReqActivityKindCodeComment,
|
||||
PullReqActivityKindChangeComment,
|
||||
})
|
||||
|
||||
// PullReqReviewDecision defines state of a pull request review.
|
||||
|
@ -52,6 +52,46 @@ type PullReqActivity struct {
|
||||
|
||||
Author PrincipalInfo `json:"author"`
|
||||
Resolver *PrincipalInfo `json:"resolver"`
|
||||
|
||||
Outdated *bool `json:"outdated"`
|
||||
CodeCommentMergeBaseSHA *string `json:"code_comment_merge_base_sha"`
|
||||
CodeCommentSourceSHA *string `json:"code_comment_source_sha"`
|
||||
CodeCommentPath *string `json:"code_comment_path"`
|
||||
CodeCommentLineNew *int64 `json:"code_comment_line_new"`
|
||||
CodeCommentSpanNew *int64 `json:"code_comment_span_new"`
|
||||
CodeCommentLineOld *int64 `json:"code_comment_line_old"`
|
||||
CodeCommentSpanOld *int64 `json:"code_comment_span_old"`
|
||||
}
|
||||
|
||||
func (a *PullReqActivity) IsValidCodeComment() bool {
|
||||
return a.Type == enum.PullReqActivityTypeCodeComment &&
|
||||
a.Kind == enum.PullReqActivityKindChangeComment &&
|
||||
a.CodeCommentMergeBaseSHA != nil &&
|
||||
a.CodeCommentSourceSHA != nil &&
|
||||
a.CodeCommentPath != nil &&
|
||||
a.CodeCommentLineNew != nil &&
|
||||
a.CodeCommentSpanNew != nil &&
|
||||
a.CodeCommentLineOld != nil &&
|
||||
a.CodeCommentSpanOld != nil
|
||||
}
|
||||
|
||||
func (a *PullReqActivity) AsCodeComment() *CodeComment {
|
||||
if !a.IsValidCodeComment() {
|
||||
return &CodeComment{}
|
||||
}
|
||||
return &CodeComment{
|
||||
ID: a.ID,
|
||||
Version: a.Version,
|
||||
Updated: a.Updated,
|
||||
Outdated: *a.Outdated,
|
||||
MergeBaseSHA: *a.CodeCommentMergeBaseSHA,
|
||||
SourceSHA: *a.CodeCommentSourceSHA,
|
||||
Path: *a.CodeCommentPath,
|
||||
LineNew: int(*a.CodeCommentLineNew),
|
||||
SpanNew: int(*a.CodeCommentSpanNew),
|
||||
LineOld: int(*a.CodeCommentLineOld),
|
||||
SpanOld: int(*a.CodeCommentSpanOld),
|
||||
}
|
||||
}
|
||||
|
||||
func (a *PullReqActivity) IsReplyable() bool {
|
||||
@ -130,14 +170,16 @@ type activityPayloadFactoryMethod func() PullReqActivityPayload
|
||||
|
||||
// allPullReqActivityPayloads is a map that contains the payload factory methods for all activity types with payload.
|
||||
var allPullReqActivityPayloads = func(
|
||||
factoryMethods []activityPayloadFactoryMethod) map[enum.PullReqActivityType]activityPayloadFactoryMethod {
|
||||
factoryMethods []activityPayloadFactoryMethod,
|
||||
) map[enum.PullReqActivityType]activityPayloadFactoryMethod {
|
||||
payloadMap := make(map[enum.PullReqActivityType]activityPayloadFactoryMethod)
|
||||
for _, factoryMethod := range factoryMethods {
|
||||
payloadMap[factoryMethod().ActivityType()] = factoryMethod
|
||||
}
|
||||
return payloadMap
|
||||
}([]activityPayloadFactoryMethod{
|
||||
func() PullReqActivityPayload { return &PullRequestActivityPayloadComment{} },
|
||||
func() PullReqActivityPayload { return PullRequestActivityPayloadComment{} },
|
||||
func() PullReqActivityPayload { return &PullRequestActivityPayloadCodeComment{} },
|
||||
func() PullReqActivityPayload { return &PullRequestActivityPayloadMerge{} },
|
||||
func() PullReqActivityPayload { return &PullRequestActivityPayloadStateChange{} },
|
||||
func() PullReqActivityPayload { return &PullRequestActivityPayloadTitleChange{} },
|
||||
@ -156,14 +198,22 @@ func newPayloadForActivity(t enum.PullReqActivityType) (PullReqActivityPayload,
|
||||
return payloadFactoryMethod(), nil
|
||||
}
|
||||
|
||||
// PullRequestActivityPayloadComment represents the payload for a comment.
|
||||
// NOTE: Allow UI to store whatever needed for code comments until we have a proper solution.
|
||||
type PullRequestActivityPayloadComment map[string]interface{}
|
||||
type PullRequestActivityPayloadComment struct{}
|
||||
|
||||
func (a *PullRequestActivityPayloadComment) ActivityType() enum.PullReqActivityType {
|
||||
func (a PullRequestActivityPayloadComment) ActivityType() enum.PullReqActivityType {
|
||||
return enum.PullReqActivityTypeComment
|
||||
}
|
||||
|
||||
type PullRequestActivityPayloadCodeComment struct {
|
||||
Title string `json:"title"`
|
||||
Lines []string `json:"lines"`
|
||||
AnyNew bool `json:"any_new"`
|
||||
}
|
||||
|
||||
func (a *PullRequestActivityPayloadCodeComment) ActivityType() enum.PullReqActivityType {
|
||||
return enum.PullReqActivityTypeCodeComment
|
||||
}
|
||||
|
||||
type PullRequestActivityPayloadMerge struct {
|
||||
MergeMethod enum.MergeMethod `json:"merge_method"`
|
||||
MergeSHA string `json:"merge_sha"`
|
||||
|
Loading…
Reference in New Issue
Block a user