diff --git a/appview/state/pull.go b/appview/state/pull.go index eae4b477..6610f944 100644 --- a/appview/state/pull.go +++ b/appview/state/pull.go @@ -563,6 +563,20 @@ func (s *State) NewPull(w http.ResponseWriter, r *http.Request) { return } + us, err := NewUnsignedClient(f.Knot, s.config.Dev) + if err != nil { + log.Println("failed to create unsigned client to %s: %v", f.Knot, err) + s.pages.Notice(w, "pull", "Failed to create a pull request. Try again later.") + return + } + + caps, err := us.Capabilities() + if err != nil { + log.Println("error fetching knot caps", f.Knot, err) + s.pages.Notice(w, "pull", "Failed to create a pull request. Try again later.") + return + } + // Determine PR type based on input parameters isPushAllowed := f.RepoInfo(s, user).Roles.IsPushAllowed() isBranchBased := isPushAllowed && sourceBranch != "" && fromFork == "" @@ -583,10 +597,22 @@ func (s *State) NewPull(w http.ResponseWriter, r *http.Request) { // Handle the PR creation based on the type if isBranchBased { + if !caps.PullRequests.BranchSubmissions { + s.pages.Notice(w, "pull", "This knot doesn't support branch-based pull requests. Try another way?") + return + } s.handleBranchBasedPull(w, r, f, user, title, body, targetBranch, sourceBranch) } else if isForkBased { + if !caps.PullRequests.ForkSubmissions { + s.pages.Notice(w, "pull", "This knot doesn't support fork-based pull requests. Try another way?") + return + } s.handleForkBasedPull(w, r, f, user, fromFork, title, body, targetBranch, sourceBranch) } else if isPatchBased { + if !caps.PullRequests.PatchSubmissions { + s.pages.Notice(w, "pull", "This knot doesn't support patch-based pull requests. Send your patch over email.") + return + } s.handlePatchBasedPull(w, r, f, user, title, body, targetBranch, patch) } return diff --git a/appview/state/signer.go b/appview/state/signer.go index 497df8ae..806015fb 100644 --- a/appview/state/signer.go +++ b/appview/state/signer.go @@ -351,7 +351,7 @@ func (us *UnsignedClient) DefaultBranch(ownerDid, repoName string) (*http.Respon return us.client.Do(req) } -func (us *UnsignedClient) Capabilities(ownerDid, repoName string) (*http.Response, error) { +func (us *UnsignedClient) Capabilities() (*types.Capabilities, error) { const ( Method = "GET" Endpoint = "/capabilities" @@ -362,7 +362,18 @@ func (us *UnsignedClient) Capabilities(ownerDid, repoName string) (*http.Respons return nil, err } - return us.client.Do(req) + resp, err := us.client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var capabilities types.Capabilities + if err := json.NewDecoder(resp.Body).Decode(&capabilities); err != nil { + return nil, err + } + + return &capabilities, nil } func (us *UnsignedClient) Compare(ownerDid, repoName, rev1, rev2 string) (*http.Response, error) { diff --git a/types/capabilities.go b/types/capabilities.go new file mode 100644 index 00000000..2e81670d --- /dev/null +++ b/types/capabilities.go @@ -0,0 +1,9 @@ +package types + +type Capabilities struct { + PullRequests struct { + PatchSubmissions bool `json:"patch_submissions"` + BranchSubmissions bool `json:"branch_submissions"` + ForkSubmissions bool `json:"fork_submissions"` + } `json:"pull_requests"` +}