mirror of https://github.com/harness/drone.git
add user filters to the pull request list API (#2624)
* add user filters to the pull request list APIpull/3558/head
parent
ccf267f1cc
commit
a2d2ba07aa
|
@ -393,6 +393,71 @@ var queryParameterIncludeDescription = openapi3.ParameterOrRef{
|
|||
},
|
||||
}
|
||||
|
||||
var queryParameterAuthorID = openapi3.ParameterOrRef{
|
||||
Parameter: &openapi3.Parameter{
|
||||
Name: request.QueryParamAuthorID,
|
||||
In: openapi3.ParameterInQuery,
|
||||
Description: ptr.String("Return only pull requests where this user is the author."),
|
||||
Required: ptr.Bool(false),
|
||||
Schema: &openapi3.SchemaOrRef{
|
||||
Schema: &openapi3.Schema{
|
||||
Type: ptrSchemaType(openapi3.SchemaTypeInteger),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var queryParameterCommenterID = openapi3.ParameterOrRef{
|
||||
Parameter: &openapi3.Parameter{
|
||||
Name: request.QueryParamCommenterID,
|
||||
In: openapi3.ParameterInQuery,
|
||||
Description: ptr.String("Return only pull requests where this user has created at least one comment."),
|
||||
Required: ptr.Bool(false),
|
||||
Schema: &openapi3.SchemaOrRef{
|
||||
Schema: &openapi3.Schema{
|
||||
Type: ptrSchemaType(openapi3.SchemaTypeInteger),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var queryParameterReviewerID = openapi3.ParameterOrRef{
|
||||
Parameter: &openapi3.Parameter{
|
||||
Name: request.QueryParamReviewerID,
|
||||
In: openapi3.ParameterInQuery,
|
||||
Description: ptr.String("Return only pull requests where this user has been added as a reviewer."),
|
||||
Required: ptr.Bool(false),
|
||||
Schema: &openapi3.SchemaOrRef{
|
||||
Schema: &openapi3.Schema{
|
||||
Type: ptrSchemaType(openapi3.SchemaTypeInteger),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var queryParameterReviewDecision = openapi3.ParameterOrRef{
|
||||
Parameter: &openapi3.Parameter{
|
||||
Name: request.QueryParamReviewDecision,
|
||||
In: openapi3.ParameterInQuery,
|
||||
Description: ptr.String("Require only this review decision of the reviewer. " +
|
||||
"Requires " + request.QueryParamReviewerID + " parameter."),
|
||||
Required: ptr.Bool(false),
|
||||
Schema: &openapi3.SchemaOrRef{
|
||||
Schema: &openapi3.Schema{
|
||||
Type: ptrSchemaType(openapi3.SchemaTypeArray),
|
||||
Items: &openapi3.SchemaOrRef{
|
||||
Schema: &openapi3.Schema{
|
||||
Type: ptrSchemaType(openapi3.SchemaTypeString),
|
||||
Enum: enum.PullReqReviewDecision("").Enum(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Style: ptr.String(string(openapi3.EncodingStyleForm)),
|
||||
Explode: ptr.Bool(true),
|
||||
},
|
||||
}
|
||||
|
||||
//nolint:funlen
|
||||
func pullReqOperations(reflector *openapi3.Reflector) {
|
||||
createPullReq := openapi3.Operation{}
|
||||
|
@ -417,7 +482,8 @@ func pullReqOperations(reflector *openapi3.Reflector) {
|
|||
queryParameterCreatedLt, queryParameterCreatedGt, queryParameterEditedLt, queryParameterEditedGt,
|
||||
queryParameterIncludeDescription,
|
||||
QueryParameterPage, QueryParameterLimit,
|
||||
QueryParameterLabelID, QueryParameterValueID)
|
||||
QueryParameterLabelID, QueryParameterValueID,
|
||||
queryParameterAuthorID, queryParameterCommenterID, queryParameterReviewerID, queryParameterReviewDecision)
|
||||
_ = reflector.SetRequest(&listPullReq, new(listPullReqRequest), http.MethodGet)
|
||||
_ = reflector.SetJSONResponse(&listPullReq, new([]types.PullReq), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&listPullReq, new(usererror.Error), http.StatusBadRequest)
|
||||
|
|
|
@ -611,7 +611,8 @@ func spaceOperations(reflector *openapi3.Reflector) {
|
|||
queryParameterCreatedLt, queryParameterCreatedGt, queryParameterEditedLt,
|
||||
queryParameterIncludeDescription, queryParameterIncludeSubspaces,
|
||||
QueryParameterLimit,
|
||||
QueryParameterLabelID, QueryParameterValueID)
|
||||
QueryParameterLabelID, QueryParameterValueID,
|
||||
queryParameterAuthorID, queryParameterCommenterID, queryParameterReviewerID, queryParameterReviewDecision)
|
||||
_ = reflector.SetRequest(&listPullReq, new(listPullReqRequest), http.MethodGet)
|
||||
_ = reflector.SetJSONResponse(&listPullReq, new([]types.PullReq), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&listPullReq, new(usererror.Error), http.StatusBadRequest)
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/errors"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
@ -28,6 +29,10 @@ const (
|
|||
PathParamReviewerID = "pullreq_reviewer_id"
|
||||
PathParamUserGroupID = "user_group_id"
|
||||
|
||||
QueryParamAuthorID = "author_id"
|
||||
QueryParamCommenterID = "commenter_id"
|
||||
QueryParamReviewerID = "reviewer_id"
|
||||
QueryParamReviewDecision = "review_decision"
|
||||
QueryParamIncludeDescription = "include_description"
|
||||
)
|
||||
|
||||
|
@ -70,6 +75,24 @@ func parsePullReqStates(r *http.Request) []enum.PullReqState {
|
|||
return states
|
||||
}
|
||||
|
||||
// parseReviewDecisions extracts the pull request reviewer decisions from the url.
|
||||
func parseReviewDecisions(r *http.Request) []enum.PullReqReviewDecision {
|
||||
strReviewDecisions, _ := QueryParamList(r, QueryParamReviewDecision)
|
||||
m := make(map[enum.PullReqReviewDecision]struct{}) // use map to eliminate duplicates
|
||||
for _, s := range strReviewDecisions {
|
||||
if state, ok := enum.PullReqReviewDecision(s).Sanitize(); ok {
|
||||
m[state] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
reviewDecisions := make([]enum.PullReqReviewDecision, 0, len(m))
|
||||
for s := range m {
|
||||
reviewDecisions = append(reviewDecisions, s)
|
||||
}
|
||||
|
||||
return reviewDecisions
|
||||
}
|
||||
|
||||
// ParsePullReqFilter extracts the pull request query parameter from the url.
|
||||
func ParsePullReqFilter(r *http.Request) (*types.PullReqFilter, error) {
|
||||
createdBy, err := QueryParamListAsPositiveInt64(r, QueryParamCreatedBy)
|
||||
|
@ -101,6 +124,26 @@ func ParsePullReqFilter(r *http.Request) (*types.PullReqFilter, error) {
|
|||
return nil, fmt.Errorf("encountered error parsing include description filter: %w", err)
|
||||
}
|
||||
|
||||
authorID, err := QueryParamAsPositiveInt64OrDefault(r, QueryParamAuthorID, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("encountered error parsing author ID filter: %w", err)
|
||||
}
|
||||
|
||||
commenterID, err := QueryParamAsPositiveInt64OrDefault(r, QueryParamCommenterID, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("encountered error parsing commenter ID filter: %w", err)
|
||||
}
|
||||
|
||||
reviewerID, err := QueryParamAsPositiveInt64OrDefault(r, QueryParamReviewerID, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("encountered error parsing reviewer ID filter: %w", err)
|
||||
}
|
||||
|
||||
reviewDecisions := parseReviewDecisions(r)
|
||||
if len(reviewDecisions) > 0 && reviewerID <= 0 {
|
||||
return nil, errors.InvalidArgument("Can't use review decisions without providing a reviewer ID")
|
||||
}
|
||||
|
||||
return &types.PullReqFilter{
|
||||
Page: ParsePage(r),
|
||||
Size: ParseLimit(r),
|
||||
|
@ -114,6 +157,10 @@ func ParsePullReqFilter(r *http.Request) (*types.PullReqFilter, error) {
|
|||
Order: ParseOrder(r),
|
||||
LabelID: labelID,
|
||||
ValueID: valueID,
|
||||
AuthorID: authorID,
|
||||
CommenterID: commenterID,
|
||||
ReviewerID: reviewerID,
|
||||
ReviewDecisions: reviewDecisions,
|
||||
IncludeDescription: includeDescription,
|
||||
CreatedFilter: createdAtFilter,
|
||||
EditedFilter: editedAtFilter,
|
||||
|
|
|
@ -547,7 +547,7 @@ func (s *PullReqStore) listQuery(opts *types.PullReqFilter) squirrel.SelectBuild
|
|||
columns = pullReqColumns
|
||||
}
|
||||
|
||||
if len(opts.LabelID) > 0 || len(opts.ValueID) > 0 {
|
||||
if len(opts.LabelID) > 0 || len(opts.ValueID) > 0 || opts.CommenterID > 0 {
|
||||
stmt = database.Builder.Select("DISTINCT " + columns)
|
||||
} else {
|
||||
stmt = database.Builder.Select(columns)
|
||||
|
@ -621,6 +621,26 @@ func (*PullReqStore) applyFilter(stmt *squirrel.SelectBuilder, opts *types.PullR
|
|||
*stmt = stmt.Where(squirrel.NotEq{"pullreq_target_repo_id": opts.RepoIDBlacklist})
|
||||
}
|
||||
|
||||
if opts.AuthorID > 0 {
|
||||
*stmt = stmt.Where("pullreq_created_by = ?", opts.AuthorID)
|
||||
}
|
||||
|
||||
if opts.CommenterID > 0 {
|
||||
*stmt = stmt.InnerJoin("pullreq_activities ON pullreq_activity_pullreq_id = pullreq_id")
|
||||
*stmt = stmt.Where("pullreq_activity_deleted IS NULL")
|
||||
*stmt = stmt.Where("(pullreq_activity_kind = 'comment' OR pullreq_activity_kind = 'change-comment')")
|
||||
*stmt = stmt.Where("pullreq_activity_created_by = ?", opts.CommenterID)
|
||||
}
|
||||
|
||||
if opts.ReviewerID > 0 {
|
||||
*stmt = stmt.InnerJoin(
|
||||
fmt.Sprintf("pullreq_reviewers ON "+
|
||||
"pullreq_reviewer_pullreq_id = pullreq_id AND pullreq_reviewer_principal_id = %d", opts.ReviewerID))
|
||||
if len(opts.ReviewDecisions) > 0 {
|
||||
*stmt = stmt.Where(squirrel.Eq{"pullreq_reviewer_review_decision": opts.ReviewDecisions})
|
||||
}
|
||||
}
|
||||
|
||||
// labels
|
||||
|
||||
if len(opts.LabelID) == 0 && len(opts.ValueID) == 0 {
|
||||
|
|
|
@ -94,21 +94,25 @@ type PullReqStats 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"`
|
||||
SourceRepoID int64 `json:"-"` // caller should use source_repo_ref
|
||||
SourceRepoRef string `json:"source_repo_ref"`
|
||||
SourceBranch string `json:"source_branch"`
|
||||
TargetRepoID int64 `json:"-"`
|
||||
TargetBranch string `json:"target_branch"`
|
||||
States []enum.PullReqState `json:"state"`
|
||||
Sort enum.PullReqSort `json:"sort"`
|
||||
Order enum.Order `json:"order"`
|
||||
LabelID []int64 `json:"label_id"`
|
||||
ValueID []int64 `json:"value_id"`
|
||||
IncludeDescription bool `json:"include_description"`
|
||||
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"`
|
||||
TargetRepoID int64 `json:"-"`
|
||||
TargetBranch string `json:"target_branch"`
|
||||
States []enum.PullReqState `json:"state"`
|
||||
Sort enum.PullReqSort `json:"sort"`
|
||||
Order enum.Order `json:"order"`
|
||||
LabelID []int64 `json:"label_id"`
|
||||
ValueID []int64 `json:"value_id"`
|
||||
AuthorID int64 `json:"author_id"`
|
||||
CommenterID int64 `json:"commenter_id"`
|
||||
ReviewerID int64 `json:"reviewer_id"`
|
||||
ReviewDecisions []enum.PullReqReviewDecision `json:"review_decisions"`
|
||||
IncludeDescription bool `json:"include_description"`
|
||||
CreatedFilter
|
||||
EditedFilter
|
||||
|
||||
|
|
Loading…
Reference in New Issue