| OLD | NEW |
| 1 // Copyright 2016 The LUCI Authors. | 1 // Copyright 2016 The LUCI Authors. |
| 2 // | 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
| 6 // | 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // | 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. | 13 // limitations under the License. |
| 14 | 14 |
| 15 package gitiles | 15 package gitiles |
| 16 | 16 |
| 17 // TODO(tandrii): add tests. |
| 18 |
| 17 import ( | 19 import ( |
| 18 "encoding/json" | 20 "encoding/json" |
| 19 "fmt" | 21 "fmt" |
| 20 "net/http" | 22 "net/http" |
| 21 "net/url" | 23 "net/url" |
| 22 "strings" | 24 "strings" |
| 23 | 25 |
| 24 "github.com/luci/luci-go/milo/api/resp" | |
| 25 "github.com/luci/luci-go/server/auth" | 26 "github.com/luci/luci-go/server/auth" |
| 26 "golang.org/x/net/context" | 27 "golang.org/x/net/context" |
| 27 ) | 28 ) |
| 28 | 29 |
| 29 // Repo defines a git repository. | 30 // User is the author or the committer returned from gitiles. |
| 30 type Repo struct { | |
| 31 » // Server is the full path to a git repository. Server must start with
https:// | |
| 32 » // and should not end with .git. | |
| 33 » Server string | |
| 34 » // Branch specifies a treeish of a git repository. This is generally a
branch. | |
| 35 » Branch string | |
| 36 } | |
| 37 | |
| 38 // User is the author or the committer returned from a gitiles log request. | |
| 39 type User struct { | 31 type User struct { |
| 40 Name string `json:"name"` | 32 Name string `json:"name"` |
| 41 Email string `json:"email"` | 33 Email string `json:"email"` |
| 42 Time string `json:"time"` | 34 Time string `json:"time"` |
| 43 } | 35 } |
| 44 | 36 |
| 45 // Log is the Log information of a commit returned from a gitiles log request. | 37 // Commit is the information of a commit returned from gitiles. |
| 46 type Log struct { | 38 type Commit struct { |
| 47 Commit string `json:"commit"` | 39 Commit string `json:"commit"` |
| 48 Tree string `json:"tree"` | 40 Tree string `json:"tree"` |
| 49 Parents []string `json:"parents"` | 41 Parents []string `json:"parents"` |
| 50 Author User `json:"author"` | 42 Author User `json:"author"` |
| 51 Committer User `json:"committer"` | 43 Committer User `json:"committer"` |
| 52 Message string `json:"message"` | 44 Message string `json:"message"` |
| 53 } | 45 } |
| 54 | 46 |
| 55 // Commit is the JSON response from querying gitiles for a log request. | 47 // LogResponse is the JSON response from querying gitiles for a log request. |
| 56 type Commit struct { | 48 type LogResponse struct { |
| 57 » Log []Log `json:"log"` | 49 » Log []Commit `json:"log"` |
| 58 » Next string `json:"next"` | 50 » Next string `json:"next"` |
| 59 } | 51 } |
| 60 | 52 |
| 61 // fixURL validates and normalizes a repoURL and treeish, and returns the | 53 // fixURL validates and normalizes a repoURL and treeish, and returns the |
| 62 // log JSON gitiles URL. | 54 // log JSON gitiles URL. |
| 63 func fixURL(repoURL, treeish string) (string, error) { | 55 func fixURL(repoURL, treeish string) (string, error) { |
| 64 u, err := url.Parse(repoURL) | 56 u, err := url.Parse(repoURL) |
| 65 if err != nil { | 57 if err != nil { |
| 66 return "", err | 58 return "", err |
| 67 } | 59 } |
| 68 if u.Scheme != "https" { | 60 if u.Scheme != "https" { |
| 69 return "", fmt.Errorf("%s should start with https://", repoURL) | 61 return "", fmt.Errorf("%s should start with https://", repoURL) |
| 70 } | 62 } |
| 71 if !strings.HasSuffix(u.Host, ".googlesource.com") { | 63 if !strings.HasSuffix(u.Host, ".googlesource.com") { |
| 72 return "", fmt.Errorf("Only .googlesource.com repos supported") | 64 return "", fmt.Errorf("Only .googlesource.com repos supported") |
| 73 } | 65 } |
| 74 // Use the authenticated URL | 66 // Use the authenticated URL |
| 75 u.Path = "a/" + u.Path | 67 u.Path = "a/" + u.Path |
| 76 URL := fmt.Sprintf("%s/+log/%s?format=JSON", u.String(), treeish) | 68 URL := fmt.Sprintf("%s/+log/%s?format=JSON", u.String(), treeish) |
| 77 return URL, nil | 69 return URL, nil |
| 78 } | 70 } |
| 79 | 71 |
| 80 // GetCommits returns a list of commits based on a repo and treeish (usually | 72 // Log returns a list of commits based on a repo and treeish (usually |
| 81 // a branch). This should be equivilent of a "git log <treeish>" call in | 73 // a branch). This should be equivilent of a "git log <treeish>" call in |
| 82 // that repository. | 74 // that repository. |
| 83 func GetCommits(c context.Context, repoURL, treeish string, limit int) ([]resp.C
ommit, error) { | 75 func Log(c context.Context, repoURL, treeish string, limit int) ([]Commit, error
) { |
| 84 // TODO(hinoka): Respect the limit. | 76 // TODO(hinoka): Respect the limit. |
| 85 URL, err := fixURL(repoURL, treeish) | 77 URL, err := fixURL(repoURL, treeish) |
| 86 if err != nil { | 78 if err != nil { |
| 87 return nil, err | 79 return nil, err |
| 88 } | 80 } |
| 89 t, err := auth.GetRPCTransport(c, auth.NoAuth) | 81 t, err := auth.GetRPCTransport(c, auth.NoAuth) |
| 90 if err != nil { | 82 if err != nil { |
| 91 return nil, err | 83 return nil, err |
| 92 } | 84 } |
| 93 client := http.Client{Transport: t} | 85 client := http.Client{Transport: t} |
| 94 r, err := client.Get(URL) | 86 r, err := client.Get(URL) |
| 95 if err != nil { | 87 if err != nil { |
| 96 return nil, err | 88 return nil, err |
| 97 } | 89 } |
| 98 if r.StatusCode != 200 { | 90 if r.StatusCode != 200 { |
| 99 return nil, fmt.Errorf("Failed to fetch %s, status code %d", URL
, r.StatusCode) | 91 return nil, fmt.Errorf("Failed to fetch %s, status code %d", URL
, r.StatusCode) |
| 100 } | 92 } |
| 101 defer r.Body.Close() | 93 defer r.Body.Close() |
| 102 // Strip out the jsonp header, which is ")]}'" | 94 // Strip out the jsonp header, which is ")]}'" |
| 103 trash := make([]byte, 4) | 95 trash := make([]byte, 4) |
| 104 r.Body.Read(trash) // Read the jsonp header | 96 r.Body.Read(trash) // Read the jsonp header |
| 105 » commits := Commit{} | 97 » commits := LogResponse{} |
| 106 if err := json.NewDecoder(r.Body).Decode(&commits); err != nil { | 98 if err := json.NewDecoder(r.Body).Decode(&commits); err != nil { |
| 107 return nil, err | 99 return nil, err |
| 108 } | 100 } |
| 109 // TODO(hinoka): If there is a page and we have gotten less than the lim
it, | 101 // TODO(hinoka): If there is a page and we have gotten less than the lim
it, |
| 110 // keep making requests for the next page until we have enough commits. | 102 // keep making requests for the next page until we have enough commits. |
| 111 | 103 » return commits.Log, nil |
| 112 » // Move things into our own datastructure. | |
| 113 » result := make([]resp.Commit, len(commits.Log)) | |
| 114 » for i, log := range commits.Log { | |
| 115 » » result[i] = resp.Commit{ | |
| 116 » » » AuthorName: log.Author.Name, | |
| 117 » » » AuthorEmail: log.Author.Email, | |
| 118 » » » Repo: repoURL, | |
| 119 » » » Revision: resp.NewLink(log.Commit, repoURL+"/+/"+log.
Commit), | |
| 120 » » » Description: log.Message, | |
| 121 » » » Title: strings.SplitN(log.Message, "\n", 2)[0], | |
| 122 » » » // TODO(hinoka): Fill in the rest of resp.Commit and add
those details | |
| 123 » » » // in the html. | |
| 124 » » } | |
| 125 » } | |
| 126 » return result, nil | |
| 127 } | 104 } |
| OLD | NEW |