github.com/pengwynn/gh@v1.0.1-0.20140118055701-14327ca3942e/github/client.go (about) 1 package github 2 3 import ( 4 "fmt" 5 "github.com/jingweno/go-octokit/octokit" 6 "net/url" 7 "os" 8 ) 9 10 const ( 11 GitHubHost string = "github.com" 12 GitHubApiHost string = "api.github.com" 13 OAuthAppURL string = "http://owenou.com/gh" 14 ) 15 16 type ClientError struct { 17 error 18 } 19 20 func (e *ClientError) Error() string { 21 return e.error.Error() 22 } 23 24 func (e *ClientError) Is2FAError() bool { 25 re, ok := e.error.(*octokit.ResponseError) 26 return ok && re.Type == octokit.ErrorOneTimePasswordRequired 27 } 28 29 type Client struct { 30 Credentials *Credentials 31 } 32 33 func (client *Client) PullRequest(project *Project, id string) (pr *octokit.PullRequest, err error) { 34 url, err := octokit.PullRequestsURL.Expand(octokit.M{"owner": project.Owner, "repo": project.Name, "number": id}) 35 if err != nil { 36 return 37 } 38 39 pr, result := client.octokit().PullRequests(client.requestURL(url)).One() 40 if result.HasError() { 41 err = fmt.Errorf("Error getting pull request: %s", result.Err) 42 } 43 44 return 45 } 46 47 func (client *Client) CreatePullRequest(project *Project, base, head, title, body string) (pr *octokit.PullRequest, err error) { 48 url, err := octokit.PullRequestsURL.Expand(octokit.M{"owner": project.Owner, "repo": project.Name}) 49 if err != nil { 50 return 51 } 52 53 params := octokit.PullRequestParams{Base: base, Head: head, Title: title, Body: body} 54 pr, result := client.octokit().PullRequests(client.requestURL(url)).Create(params) 55 if result.HasError() { 56 err = fmt.Errorf("Error creating pull request: %s", result.Err) 57 } 58 59 return 60 } 61 62 func (client *Client) CreatePullRequestForIssue(project *Project, base, head, issue string) (pr *octokit.PullRequest, err error) { 63 url, err := octokit.PullRequestsURL.Expand(octokit.M{"owner": project.Owner, "repo": project.Name}) 64 if err != nil { 65 return 66 } 67 68 params := octokit.PullRequestForIssueParams{Base: base, Head: head, Issue: issue} 69 pr, result := client.octokit().PullRequests(client.requestURL(url)).Create(params) 70 if result.HasError() { 71 err = fmt.Errorf("Error creating pull request: %s", result.Err) 72 } 73 74 return 75 } 76 77 func (client *Client) Repository(project *Project) (repo *octokit.Repository, err error) { 78 url, err := octokit.RepositoryURL.Expand(octokit.M{"owner": project.Owner, "repo": project.Name}) 79 if err != nil { 80 return 81 } 82 83 repo, result := client.octokit().Repositories(client.requestURL(url)).One() 84 if result.HasError() { 85 err = fmt.Errorf("Error getting repository: %s", result.Err) 86 } 87 88 return 89 } 90 91 func (client *Client) IsRepositoryExist(project *Project) bool { 92 repo, err := client.Repository(project) 93 94 return err == nil && repo != nil 95 } 96 97 func (client *Client) CreateRepository(project *Project, description, homepage string, isPrivate bool) (repo *octokit.Repository, err error) { 98 var repoURL octokit.Hyperlink 99 if project.Owner != client.Credentials.User { 100 repoURL = octokit.OrgRepositoriesURL 101 } else { 102 repoURL = octokit.UserRepositoriesURL 103 } 104 105 url, err := repoURL.Expand(octokit.M{"org": project.Owner}) 106 if err != nil { 107 return 108 } 109 110 params := octokit.Repository{ 111 Name: project.Name, 112 Description: description, 113 Homepage: homepage, 114 Private: isPrivate, 115 } 116 repo, result := client.octokit().Repositories(client.requestURL(url)).Create(params) 117 if result.HasError() { 118 if result.Response == nil || result.Response.StatusCode == 500 { 119 err = fmt.Errorf("Error creating repository: Internal Server Error (HTTP 500)") 120 } else { 121 err = fmt.Errorf("Error creating repository: %v", result.Err) 122 } 123 } 124 125 return 126 } 127 128 func (client *Client) Releases(project *Project) (releases []octokit.Release, err error) { 129 url, err := octokit.ReleasesURL.Expand(octokit.M{"owner": project.Owner, "repo": project.Name}) 130 if err != nil { 131 return 132 } 133 134 releases, result := client.octokit().Releases(client.requestURL(url)).All() 135 if result.HasError() { 136 err = fmt.Errorf("Error getting release: %s", result.Err) 137 } 138 139 return 140 } 141 142 func (client *Client) CreateRelease(project *Project, params octokit.ReleaseParams) (release *octokit.Release, err error) { 143 url, err := octokit.ReleasesURL.Expand(octokit.M{"owner": project.Owner, "repo": project.Name}) 144 if err != nil { 145 return 146 } 147 148 release, result := client.octokit().Releases(client.requestURL(url)).Create(params) 149 if result.HasError() { 150 err = fmt.Errorf("Error creating release: %s", result.Err) 151 } 152 153 return 154 } 155 156 func (client *Client) UploadReleaseAsset(uploadUrl *url.URL, asset *os.File, contentType string) (err error) { 157 c := client.octokit() 158 result := c.Uploads(uploadUrl).UploadAsset(asset, contentType) 159 if result.HasError() { 160 err = fmt.Errorf("Error uploading asset: %s", result.Err) 161 } 162 return 163 } 164 165 func (client *Client) CIStatus(project *Project, sha string) (status *octokit.Status, err error) { 166 url, err := octokit.StatusesURL.Expand(octokit.M{"owner": project.Owner, "repo": project.Name, "ref": sha}) 167 if err != nil { 168 return 169 } 170 171 statuses, result := client.octokit().Statuses(client.requestURL(url)).All() 172 if result.HasError() { 173 err = fmt.Errorf("Error getting CI status: %s", result.Err) 174 return 175 } 176 177 if len(statuses) > 0 { 178 status = &statuses[0] 179 } 180 181 return 182 } 183 184 func (client *Client) ForkRepository(project *Project) (repo *octokit.Repository, err error) { 185 url, err := octokit.ForksURL.Expand(octokit.M{"owner": project.Owner, "repo": project.Name}) 186 if err != nil { 187 return 188 } 189 190 repo, result := client.octokit().Repositories(client.requestURL(url)).Create(nil) 191 if result.HasError() { 192 err = fmt.Errorf("Error forking repository: %s", result.Err) 193 } 194 195 return 196 } 197 198 func (client *Client) Issues(project *Project) (issues []octokit.Issue, err error) { 199 var result *octokit.Result 200 201 err = client.issuesService(project, func(service *octokit.IssuesService) error { 202 issues, result = service.All() 203 return resultError(result) 204 }) 205 206 return 207 } 208 209 func (client *Client) CreateIssue(project *Project, title, body string, labels []string) (issue *octokit.Issue, err error) { 210 params := octokit.IssueParams{ 211 Title: title, 212 Body: body, 213 Labels: labels, 214 } 215 216 var result *octokit.Result 217 218 err = client.issuesService(project, func(service *octokit.IssuesService) error { 219 issue, result = service.Create(params) 220 return resultError(result) 221 }) 222 223 return 224 } 225 226 func (client *Client) GhLatestTagName() (tagName string, err error) { 227 url, err := octokit.ReleasesURL.Expand(octokit.M{"owner": "jingweno", "repo": "gh"}) 228 if err != nil { 229 return 230 } 231 232 c := octokit.NewClientWith(client.apiEndpoint(), nil, nil) 233 releases, result := c.Releases(client.requestURL(url)).All() 234 if result.HasError() { 235 err = fmt.Errorf("Error getting gh release: %s", result.Err) 236 return 237 } 238 239 if len(releases) == 0 { 240 err = fmt.Errorf("No gh release is available") 241 return 242 } 243 244 tagName = releases[0].TagName 245 246 return 247 } 248 249 func (client *Client) FindOrCreateToken(user, password, twoFactorCode string) (token string, err error) { 250 url, e := octokit.AuthorizationsURL.Expand(nil) 251 if e != nil { 252 err = &ClientError{e} 253 return 254 } 255 256 basicAuth := octokit.BasicAuth{Login: user, Password: password, OneTimePassword: twoFactorCode} 257 c := octokit.NewClientWith(client.apiEndpoint(), nil, basicAuth) 258 authsService := c.Authorizations(client.requestURL(url)) 259 260 auths, result := authsService.All() 261 if result.HasError() { 262 err = &ClientError{result.Err} 263 return 264 } 265 266 for _, auth := range auths { 267 if auth.App.URL == OAuthAppURL { 268 token = auth.Token 269 break 270 } 271 } 272 273 if token == "" { 274 authParam := octokit.AuthorizationParams{} 275 authParam.Scopes = append(authParam.Scopes, "repo") 276 authParam.Note = "gh" 277 authParam.NoteURL = OAuthAppURL 278 279 auth, result := authsService.Create(authParam) 280 if result.HasError() { 281 err = &ClientError{result.Err} 282 return 283 } 284 285 token = auth.Token 286 } 287 288 return 289 } 290 291 func (client *Client) octokit() (c *octokit.Client) { 292 tokenAuth := octokit.TokenAuth{AccessToken: client.Credentials.AccessToken} 293 c = octokit.NewClientWith(client.apiEndpoint(), nil, tokenAuth) 294 295 return 296 } 297 298 func (client *Client) requestURL(u *url.URL) (uu *url.URL) { 299 uu = u 300 if client.Credentials != nil && client.Credentials.Host != GitHubHost { 301 uu, _ = url.Parse(fmt.Sprintf("/api/v3/%s", u.Path)) 302 } 303 304 return 305 } 306 307 func (client *Client) apiEndpoint() string { 308 host := os.Getenv("GH_API_HOST") 309 if host == "" && client.Credentials != nil { 310 host = client.Credentials.Host 311 } 312 313 if host == GitHubHost { 314 host = GitHubApiHost 315 } 316 317 return absolute(host) 318 } 319 320 func absolute(endpoint string) string { 321 u, _ := url.Parse(endpoint) 322 if u.Scheme == "" { 323 u.Scheme = "https" 324 } 325 326 return u.String() 327 } 328 329 func NewClient(host string) *Client { 330 c := CurrentConfigs().PromptFor(host) 331 return &Client{Credentials: c} 332 } 333 334 func (client *Client) issuesService(project *Project, fn func(service *octokit.IssuesService) error) (err error) { 335 url, err := octokit.RepoIssuesURL.Expand(octokit.M{"owner": project.Owner, "repo": project.Name}) 336 if err != nil { 337 return 338 } 339 340 service := client.octokit().Issues(client.requestURL(url)) 341 return fn(service) 342 } 343 344 func resultError(result *octokit.Result) (err error) { 345 if result != nil && result.HasError() { 346 err = result.Err 347 } 348 return 349 }