From 6bde210adf52c2f87d3093cc4621e0b80bc0a7b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ga=C4=87e=C5=A1a?= Date: Fri, 9 Dec 2022 15:45:02 +0100 Subject: [PATCH] added branch params to PR list API (#119) --- internal/api/controller/pullreq/controller.go | 4 ++ internal/api/controller/pullreq/create.go | 16 ++++++ internal/api/controller/pullreq/list.go | 11 +++++ internal/api/openapi/pullreq.go | 49 +++++++++++++++++-- internal/api/request/pullreq.go | 19 ++++--- internal/store/database/pullreq.go | 24 +++++++++ types/pullreq.go | 18 ++++--- 7 files changed, 123 insertions(+), 18 deletions(-) diff --git a/internal/api/controller/pullreq/controller.go b/internal/api/controller/pullreq/controller.go index 618765e5e..7b28dc18d 100644 --- a/internal/api/controller/pullreq/controller.go +++ b/internal/api/controller/pullreq/controller.go @@ -49,6 +49,10 @@ func NewController( } func (c *Controller) verifyBranchExistence(ctx context.Context, repo *types.Repository, branch string) error { + if branch == "" { + return usererror.BadRequest("branch name can't be empty") + } + _, err := c.gitRPCClient.GetRef(ctx, &gitrpc.GetRefParams{RepoUID: repo.GitUID, Name: branch, Type: gitrpc.RefTypeBranch}) if errors.Is(err, gitrpc.ErrNotFound) { diff --git a/internal/api/controller/pullreq/create.go b/internal/api/controller/pullreq/create.go index bfbe1f7e5..dfed443eb 100644 --- a/internal/api/controller/pullreq/create.go +++ b/internal/api/controller/pullreq/create.go @@ -6,6 +6,7 @@ package pullreq import ( "context" + "fmt" "time" "github.com/harness/gitness/internal/api/usererror" @@ -60,6 +61,21 @@ func (c *Controller) Create( var pr *types.PullReq err = dbtx.New(c.db).WithTx(ctx, func(ctx context.Context) error { + var existing int64 + existing, err = c.pullreqStore.Count(ctx, targetRepo.ID, &types.PullReqFilter{ + SourceRepoID: sourceRepo.ID, + SourceBranch: in.SourceBranch, + TargetBranch: in.TargetBranch, + States: []enum.PullReqState{enum.PullReqStateOpen}, + }) + if err != nil { + return fmt.Errorf("failed to count existing pull requests: %w", err) + } + + if existing > 0 { + return usererror.BadRequest("a pull request for this target and source branch already exists") + } + var lastNumber int64 lastNumber, err = c.pullreqStore.LastNumber(ctx, targetRepo.ID) diff --git a/internal/api/controller/pullreq/list.go b/internal/api/controller/pullreq/list.go index f14726c80..f922390c8 100644 --- a/internal/api/controller/pullreq/list.go +++ b/internal/api/controller/pullreq/list.go @@ -24,5 +24,16 @@ func (c *Controller) List( return nil, err } + if filter.SourceRepoRef == repoRef { + filter.SourceRepoID = repo.ID + } else if filter.SourceRepoRef != "" { + var sourceRepo *types.Repository + sourceRepo, err = c.getRepoCheckAccess(ctx, session, filter.SourceRepoRef, enum.PermissionRepoView) + if err != nil { + return nil, err + } + filter.SourceRepoID = sourceRepo.ID + } + return c.pullreqStore.List(ctx, repo.ID, filter) } diff --git a/internal/api/openapi/pullreq.go b/internal/api/openapi/pullreq.go index f788fa384..8e9614d7e 100644 --- a/internal/api/openapi/pullreq.go +++ b/internal/api/openapi/pullreq.go @@ -28,7 +28,7 @@ type listPullReqRequest struct { type pullReqRequest struct { repoRequest - ID int64 `path:"pullreqNumber"` + ID int64 `path:"pullreq_number"` } type getPullReqRequest struct { @@ -49,6 +49,48 @@ var queryParameterQueryPullRequest = openapi3.ParameterOrRef{ }, } +var queryParameterSourceRepoRefPullRequest = openapi3.ParameterOrRef{ + Parameter: &openapi3.Parameter{ + Name: "source_repo_ref", + In: openapi3.ParameterInQuery, + Description: ptr.String("Source repository ref of the pull requests."), + Required: ptr.Bool(false), + Schema: &openapi3.SchemaOrRef{ + Schema: &openapi3.Schema{ + Type: ptrSchemaType(openapi3.SchemaTypeString), + }, + }, + }, +} + +var queryParameterSourceBranchPullRequest = openapi3.ParameterOrRef{ + Parameter: &openapi3.Parameter{ + Name: "source_branch", + In: openapi3.ParameterInQuery, + Description: ptr.String("Source branch of the pull requests."), + Required: ptr.Bool(false), + Schema: &openapi3.SchemaOrRef{ + Schema: &openapi3.Schema{ + Type: ptrSchemaType(openapi3.SchemaTypeString), + }, + }, + }, +} + +var queryParameterTargetBranchPullRequest = openapi3.ParameterOrRef{ + Parameter: &openapi3.Parameter{ + Name: "target_branch", + In: openapi3.ParameterInQuery, + Description: ptr.String("Target branch of the pull requests."), + Required: ptr.Bool(false), + Schema: &openapi3.SchemaOrRef{ + Schema: &openapi3.Schema{ + Type: ptrSchemaType(openapi3.SchemaTypeString), + }, + }, + }, +} + var queryParameterCreatedByPullRequest = openapi3.ParameterOrRef{ Parameter: &openapi3.Parameter{ Name: request.QueryParamCreatedBy, @@ -125,7 +167,8 @@ func pullReqOperations(reflector *openapi3.Reflector) { listPullReq.WithTags("pullreq") listPullReq.WithMapOfAnything(map[string]interface{}{"operationId": "listPullReq"}) listPullReq.WithParameters( - queryParameterStatePullRequest, + queryParameterStatePullRequest, queryParameterSourceRepoRefPullRequest, + queryParameterSourceBranchPullRequest, queryParameterTargetBranchPullRequest, queryParameterQueryPullRequest, queryParameterCreatedByPullRequest, queryParameterDirection, queryParameterSortPullRequest, queryParameterPage, queryParameterPerPage) @@ -146,5 +189,5 @@ func pullReqOperations(reflector *openapi3.Reflector) { _ = reflector.SetJSONResponse(&getPullReq, new(usererror.Error), http.StatusInternalServerError) _ = reflector.SetJSONResponse(&getPullReq, new(usererror.Error), http.StatusUnauthorized) _ = reflector.SetJSONResponse(&getPullReq, new(usererror.Error), http.StatusForbidden) - _ = reflector.Spec.AddOperation(http.MethodGet, "/repos/{repoRef}/pullreq/{pullreqNumber}", getPullReq) + _ = reflector.Spec.AddOperation(http.MethodGet, "/repos/{repoRef}/pullreq/{pullreq_number}", getPullReq) } diff --git a/internal/api/request/pullreq.go b/internal/api/request/pullreq.go index 56185fcca..f787b21c5 100644 --- a/internal/api/request/pullreq.go +++ b/internal/api/request/pullreq.go @@ -12,7 +12,7 @@ import ( ) const ( - PathParamPullReqNumber = "pullreqNumber" + PathParamPullReqNumber = "pullreq_number" ) func GetPullReqNumberFromPath(r *http.Request) (int64, error) { @@ -58,12 +58,15 @@ func ParsePullReqFilter(r *http.Request) (*types.PullReqFilter, error) { return nil, err } return &types.PullReqFilter{ - Page: ParsePage(r), - Size: ParseSize(r), - Query: ParseQuery(r), - CreatedBy: createdBy, - States: ParsePullReqStates(r), - Sort: ParseSortPullReq(r), - Order: ParseOrder(r), + Page: ParsePage(r), + Size: ParseSize(r), + Query: ParseQuery(r), + CreatedBy: createdBy, + SourceRepoRef: r.FormValue("source_repo_ref"), + SourceBranch: r.FormValue("source_branch"), + TargetBranch: r.FormValue("target_branch"), + States: ParsePullReqStates(r), + Sort: ParseSortPullReq(r), + Order: ParseOrder(r), }, nil } diff --git a/internal/store/database/pullreq.go b/internal/store/database/pullreq.go index d98e0f175..9aa64a8af 100644 --- a/internal/store/database/pullreq.go +++ b/internal/store/database/pullreq.go @@ -245,6 +245,18 @@ func (s *PullReqStore) Count(ctx context.Context, repoID int64, opts *types.Pull stmt = stmt.Where(squirrel.Eq{"pullreq_state": opts.States}) } + if opts.SourceRepoID != 0 { + stmt = stmt.Where("pullreq_source_repo_id = ?", opts.SourceRepoID) + } + + if opts.SourceBranch != "" { + stmt = stmt.Where("pullreq_source_branch = ?", opts.SourceBranch) + } + + if opts.TargetBranch != "" { + stmt = stmt.Where("pullreq_target_branch = ?", opts.TargetBranch) + } + if opts.CreatedBy != 0 { stmt = stmt.Where("pullreq_created_by = ?", opts.CreatedBy) } @@ -280,6 +292,18 @@ func (s *PullReqStore) List(ctx context.Context, repoID int64, opts *types.PullR stmt = stmt.Where(squirrel.Eq{"pullreq_state": opts.States}) } + if opts.SourceRepoID != 0 { + stmt = stmt.Where("pullreq_source_repo_id = ?", opts.SourceRepoID) + } + + if opts.SourceBranch != "" { + stmt = stmt.Where("pullreq_source_branch = ?", opts.SourceBranch) + } + + if opts.TargetBranch != "" { + stmt = stmt.Where("pullreq_target_branch = ?", opts.TargetBranch) + } + if opts.Query != "" { stmt = stmt.Where("pullreq_title LIKE ?", "%"+opts.Query+"%") } diff --git a/types/pullreq.go b/types/pullreq.go index c63a28fa6..454d98dcc 100644 --- a/types/pullreq.go +++ b/types/pullreq.go @@ -36,11 +36,15 @@ type PullReq struct { // PullReqFilter stores pull request query parameters. type PullReqFilter struct { - Page int `json:"page"` - Size int `json:"size"` - Query string `json:"query"` - CreatedBy int64 `json:"created_by"` - States []enum.PullReqState `json:"state"` - Sort enum.PullReqSort `json:"sort"` - Order enum.Order `json:"direction"` + Page int `json:"page"` + Size int `json:"size"` + Query string `json:"query"` + CreatedBy int64 `json:"created_by"` + SourceRepoID int64 `json:"-"` // caller should use source_repo_ref + SourceRepoRef string `json:"source_repo_ref"` + SourceBranch string `json:"source_branch"` + TargetBranch string `json:"target_branch"` + States []enum.PullReqState `json:"state"` + Sort enum.PullReqSort `json:"sort"` + Order enum.Order `json:"direction"` }