Skip to content

Commit

Permalink
Add PullRequestResource functionality for updating labels and comments.
Browse files Browse the repository at this point in the history
Missing from this change:
* Statuses, since this might involve more discussion on the set of statuses
  that we want to support.
* Updating from changes to the raw payloads. Unclear how we want to
  handle these at the moment. Punting on this for now.

First step for supporting tektoncd#778.

Co-authored-by: Dan Lorenc <[email protected]>
Co-authored-by: Billy Lynch <[email protected]>
  • Loading branch information
wlynch and dlorenc committed Jun 19, 2019
1 parent fc6ef39 commit b32bb87
Show file tree
Hide file tree
Showing 116 changed files with 39,615 additions and 1 deletion.
27 changes: 27 additions & 0 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 58 additions & 0 deletions cmd/pullrequest-init/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# pullrequest-init

pullrequest-init fetches pull request data from the given URL and places it in
the provided path.

This binary outputs a generic pull request object into `pr.json`, as well as
provider specific payloads.

Currently supported providers:

* GitHub

## Generic pull request payload

The payload generated by default aims to abstract the base features of any
pull request provider. Since there is no one true spec for pull requests, not
every feature may be available. The payload is output to `$PATH/pr.json` and
looks like:

```json
{
"Type": "github",
"ID": 188184279,
"Head": {
"Repo": "https://github.com/wlynch/test.git",
"Branch": "dev",
"SHA": "9bcde245572c74329827acdcab88792ebb84d578"
},
"Base": {
"Repo": "https://github.com/wlynch/test.git",
"Branch": "master",
"SHA": "1e80c83ed01e187669b836096335d1c8a2c57182"
},
"Comments": [
{
"Text": "test comment",
"Author": "wlynch",
"ID": 494418247,
"Raw": "/tmp/prtest/github/comments/494418247.json"
}
],
"Labels": [
{
"Text": "my-label"
}
],
"Raw": "/tmp/prtest/github/pr.json"
}
```

## GitHub

GitHub pull requests will output these additional files:

* `$PATH/github/pr.json`: The raw GitHub payload as specified by
https://developer.github.com/v3/pulls/#get-a-single-pull-request
* `$PATH/github/comments/#.json`: Comments associated to the PR as specified by
https://developer.github.com/v3/issues/comments/#get-a-single-comment
171 changes: 171 additions & 0 deletions cmd/pullrequest-init/fake_github.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package main

import (
"encoding/json"
"fmt"
"net/http"
"strconv"

"github.com/google/go-github/github"
"github.com/gorilla/mux"
)

// key defines keys for associating data to PRs/issues in the fake server.
type key struct {
owner string
repo string
id int64
}

// FakeGitHub is a fake GitHub server for use in tests.
type FakeGitHub struct {
*mux.Router

pr map[key]*github.PullRequest
comments map[key][]*github.IssueComment
}

// NewFakeGitHub returns a new FakeGitHub.
func NewFakeGitHub() *FakeGitHub {
s := &FakeGitHub{
Router: mux.NewRouter(),
pr: make(map[key]*github.PullRequest),
comments: make(map[key][]*github.IssueComment),
}
s.HandleFunc("/repos/{owner}/{repo}/pulls/{number}", s.getPullRequest).Methods(http.MethodGet)
s.HandleFunc("/repos/{owner}/{repo}/issues/{number}/comments", s.getComments).Methods(http.MethodGet)
s.HandleFunc("/repos/{owner}/{repo}/issues/{number}/comments", s.createComment).Methods(http.MethodPost)
s.HandleFunc("/repos/{owner}/{repo}/issues/{number}/labels", s.updateLabels).Methods(http.MethodPut)

return s
}

// AddPullRequest adds the given pull request to the fake GitHub server.
func (g *FakeGitHub) AddPullRequest(pr *github.PullRequest) {
key := key{
owner: pr.GetBase().GetUser().GetLogin(),
repo: pr.GetBase().GetRepo().GetName(),
id: pr.GetID(),
}
g.pr[key] = pr
}

// AddComment adds a comment to the fake GitHub server.
func (g *FakeGitHub) AddComment(owner string, repo string, pr int64, comment *github.IssueComment) {
key := key{
owner: owner,
repo: repo,
id: pr,
}
c := g.comments[key]
if c == nil {
c = []*github.IssueComment{comment}
} else {
c = append(c, comment)
}
g.comments[key] = c
}

func (g *FakeGitHub) getPullRequest(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseInt(mux.Vars(r)["number"], 10, 64)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
key := key{
owner: mux.Vars(r)["owner"],
repo: mux.Vars(r)["repo"],
id: id,
}

pr, ok := g.pr[key]
if !ok {
http.Error(w, fmt.Sprintf("%v not found", key), http.StatusNotFound)
return
}

if err := json.NewEncoder(w).Encode(pr); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}

func (g *FakeGitHub) getComments(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseInt(mux.Vars(r)["number"], 10, 64)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
key := key{
owner: mux.Vars(r)["owner"],
repo: mux.Vars(r)["repo"],
id: id,
}
comments, ok := g.comments[key]
if !ok {
comments = []*github.IssueComment{}
}
if err := json.NewEncoder(w).Encode(comments); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}

func (g *FakeGitHub) createComment(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseInt(mux.Vars(r)["number"], 10, 64)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
key := key{
owner: mux.Vars(r)["owner"],
repo: mux.Vars(r)["repo"],
id: id,
}

c := new(github.IssueComment)
if err := json.NewDecoder(r.Body).Decode(c); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
comments, ok := g.comments[key]
if !ok {
comments = []*github.IssueComment{}
}
c.ID = github.Int64(int64(len(comments) + 1))
g.comments[key] = append(comments, c)

w.WriteHeader(http.StatusOK)
}

func (g *FakeGitHub) updateLabels(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseInt(mux.Vars(r)["number"], 10, 64)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
key := key{
owner: mux.Vars(r)["owner"],
repo: mux.Vars(r)["repo"],
id: id,
}
pr, ok := g.pr[key]
if !ok {
http.Error(w, "pull request not found", http.StatusNotFound)
return
}

payload := []string{}
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
pr.Labels = make([]*github.Label, 0, len(payload))
for _, l := range payload {
pr.Labels = append(pr.Labels, &github.Label{
Name: github.String(l),
})
}

w.WriteHeader(http.StatusOK)
}
Loading

0 comments on commit b32bb87

Please sign in to comment.