package app import ( "encoding/json" "errors" "fmt" "net/http" "sync" gitlab "gitlab.com/gitlab-org/api/client-go" ) type MergeRequestListerByBranch interface { ListProjectMergeRequests(pid interface{}, opt *gitlab.ListProjectMergeRequestsOptions, options ...gitlab.RequestOptionFunc) ([]*gitlab.BasicMergeRequest, *gitlab.Response, error) } type mergeRequestListerByBranchService struct { data client MergeRequestListerByBranch } type MergeRequestByBranchRequest struct { Branch string `json:"branch" validate:"required"` State string `json:"state,omitempty"` } // Returns a list of merge requests where the given branch is the source branch func (a mergeRequestListerByBranchService) ServeHTTP(w http.ResponseWriter, r *http.Request) { request := r.Context().Value(payload("payload")).(*MergeRequestByBranchRequest) if request.State == "" { request.State = "opened" } payloads := []gitlab.ListProjectMergeRequestsOptions{ { SourceBranch: gitlab.Ptr(request.Branch), State: gitlab.Ptr(request.State), Scope: gitlab.Ptr("all"), }, } type apiResponse struct { mrs []*gitlab.BasicMergeRequest err error } mrChan := make(chan apiResponse, len(payloads)) wg := sync.WaitGroup{} go func() { wg.Wait() close(mrChan) }() for _, payload := range payloads { wg.Add(1) go func(p gitlab.ListProjectMergeRequestsOptions) { defer wg.Done() mrs, err := a.getMrs(&p) mrChan <- apiResponse{mrs, err} }(payload) } var mergeRequests []*gitlab.BasicMergeRequest existingIds := make(map[int64]bool) var errs []error for res := range mrChan { if res.err != nil { errs = append(errs, res.err) } else { for _, mr := range res.mrs { if !existingIds[mr.ID] { mergeRequests = append(mergeRequests, mr) existingIds[mr.ID] = true } } } } if len(errs) > 0 { combinedErr := "" for _, err := range errs { combinedErr += err.Error() + "; " } handleError(w, errors.New(combinedErr), "An error occurred", http.StatusInternalServerError) return } if len(mergeRequests) == 0 { handleError(w, fmt.Errorf("%s did not have any MRs", request.Branch), "No MRs found", http.StatusNotFound) return } w.WriteHeader(http.StatusOK) response := ListMergeRequestResponse{ SuccessResponse: SuccessResponse{Message: fmt.Sprintf("Merge requests fetched for %s", request.Branch)}, MergeRequests: mergeRequests, } err := json.NewEncoder(w).Encode(response) if err != nil { handleError(w, err, "Could not encode response", http.StatusInternalServerError) } } func (a mergeRequestListerByBranchService) getMrs(payload *gitlab.ListProjectMergeRequestsOptions) ([]*gitlab.BasicMergeRequest, error) { mrs, res, err := a.client.ListProjectMergeRequests(a.projectInfo.ProjectId, payload) if err != nil { return []*gitlab.BasicMergeRequest{}, err } if res.StatusCode >= 300 { return []*gitlab.BasicMergeRequest{}, GenericError{endpoint: "/merge_requests_by_branch"} } defer res.Body.Close() return mrs, err }