1// Copyright 2016 The go-github AUTHORS. All rights reserved. 2// 3// Use of this source code is governed by a BSD-style 4// license that can be found in the LICENSE file. 5 6package github 7 8import ( 9 "context" 10 "fmt" 11 "time" 12) 13 14// AppsService provides access to the installation related functions 15// in the GitHub API. 16// 17// GitHub API docs: https://developer.github.com/v3/apps/ 18type AppsService service 19 20// App represents a GitHub App. 21type App struct { 22 ID *int64 `json:"id,omitempty"` 23 NodeID *string `json:"node_id,omitempty"` 24 Owner *User `json:"owner,omitempty"` 25 Name *string `json:"name,omitempty"` 26 Description *string `json:"description,omitempty"` 27 ExternalURL *string `json:"external_url,omitempty"` 28 HTMLURL *string `json:"html_url,omitempty"` 29 CreatedAt *Timestamp `json:"created_at,omitempty"` 30 UpdatedAt *Timestamp `json:"updated_at,omitempty"` 31} 32 33// InstallationToken represents an installation token. 34type InstallationToken struct { 35 Token *string `json:"token,omitempty"` 36 ExpiresAt *time.Time `json:"expires_at,omitempty"` 37 Permissions *InstallationPermissions `json:"permissions,omitempty"` 38 Repositories []*Repository `json:"repositories,omitempty"` 39} 40 41// InstallationTokenOptions allow restricting a token's access to specific repositories. 42type InstallationTokenOptions struct { 43 // The IDs of the repositories that the installation token can access. 44 // Providing repository IDs restricts the access of an installation token to specific repositories. 45 RepositoryIDs []int64 `json:"repository_ids,omitempty"` 46 47 // The permissions granted to the access token. 48 // The permissions object includes the permission names and their access type. 49 Permissions *InstallationPermissions `json:"permissions,omitempty"` 50} 51 52// InstallationPermissions lists the repository and organization permissions for an installation. 53// 54// Permission names taken from: 55// https://developer.github.com/v3/apps/permissions/ 56// https://developer.github.com/enterprise/v3/apps/permissions/ 57type InstallationPermissions struct { 58 Administration *string `json:"administration,omitempty"` 59 Checks *string `json:"checks,omitempty"` 60 Contents *string `json:"contents,omitempty"` 61 ContentReferences *string `json:"content_references,omitempty"` 62 Deployments *string `json:"deployments,omitempty"` 63 Issues *string `json:"issues,omitempty"` 64 Metadata *string `json:"metadata,omitempty"` 65 Members *string `json:"members,omitempty"` 66 OrganizationAdministration *string `json:"organization_administration,omitempty"` 67 OrganizationHooks *string `json:"organization_hooks,omitempty"` 68 OrganizationPlan *string `json:"organization_plan,omitempty"` 69 OrganizationPreReceiveHooks *string `json:"organization_pre_receive_hooks,omitempty"` 70 OrganizationProjects *string `json:"organization_projects,omitempty"` 71 OrganizationUserBlocking *string `json:"organization_user_blocking,omitempty"` 72 Packages *string `json:"packages,omitempty"` 73 Pages *string `json:"pages,omitempty"` 74 PullRequests *string `json:"pull_requests,omitempty"` 75 RepositoryHooks *string `json:"repository_hooks,omitempty"` 76 RepositoryProjects *string `json:"repository_projects,omitempty"` 77 RepositoryPreReceiveHooks *string `json:"repository_pre_receive_hooks,omitempty"` 78 SingleFile *string `json:"single_file,omitempty"` 79 Statuses *string `json:"statuses,omitempty"` 80 TeamDiscussions *string `json:"team_discussions,omitempty"` 81 VulnerabilityAlerts *string `json:"vulnerability_alerts,omitempty"` 82} 83 84// Installation represents a GitHub Apps installation. 85type Installation struct { 86 ID *int64 `json:"id,omitempty"` 87 AppID *int64 `json:"app_id,omitempty"` 88 TargetID *int64 `json:"target_id,omitempty"` 89 Account *User `json:"account,omitempty"` 90 AccessTokensURL *string `json:"access_tokens_url,omitempty"` 91 RepositoriesURL *string `json:"repositories_url,omitempty"` 92 HTMLURL *string `json:"html_url,omitempty"` 93 TargetType *string `json:"target_type,omitempty"` 94 SingleFileName *string `json:"single_file_name,omitempty"` 95 RepositorySelection *string `json:"repository_selection,omitempty"` 96 Events []string `json:"events,omitempty"` 97 Permissions *InstallationPermissions `json:"permissions,omitempty"` 98 CreatedAt *Timestamp `json:"created_at,omitempty"` 99 UpdatedAt *Timestamp `json:"updated_at,omitempty"` 100} 101 102// Attachment represents a GitHub Apps attachment. 103type Attachment struct { 104 ID *int64 `json:"id,omitempty"` 105 Title *string `json:"title,omitempty"` 106 Body *string `json:"body,omitempty"` 107} 108 109func (i Installation) String() string { 110 return Stringify(i) 111} 112 113// Get a single GitHub App. Passing the empty string will get 114// the authenticated GitHub App. 115// 116// Note: appSlug is just the URL-friendly name of your GitHub App. 117// You can find this on the settings page for your GitHub App 118// (e.g., https://github.com/settings/apps/:app_slug). 119// 120// GitHub API docs: https://developer.github.com/v3/apps/#get-a-single-github-app 121func (s *AppsService) Get(ctx context.Context, appSlug string) (*App, *Response, error) { 122 var u string 123 if appSlug != "" { 124 u = fmt.Sprintf("apps/%v", appSlug) 125 } else { 126 u = "app" 127 } 128 129 req, err := s.client.NewRequest("GET", u, nil) 130 if err != nil { 131 return nil, nil, err 132 } 133 134 // TODO: remove custom Accept header when this API fully launches. 135 req.Header.Set("Accept", mediaTypeIntegrationPreview) 136 137 app := new(App) 138 resp, err := s.client.Do(ctx, req, app) 139 if err != nil { 140 return nil, resp, err 141 } 142 143 return app, resp, nil 144} 145 146// ListInstallations lists the installations that the current GitHub App has. 147// 148// GitHub API docs: https://developer.github.com/v3/apps/#find-installations 149func (s *AppsService) ListInstallations(ctx context.Context, opt *ListOptions) ([]*Installation, *Response, error) { 150 u, err := addOptions("app/installations", opt) 151 if err != nil { 152 return nil, nil, err 153 } 154 155 req, err := s.client.NewRequest("GET", u, nil) 156 if err != nil { 157 return nil, nil, err 158 } 159 160 // TODO: remove custom Accept header when this API fully launches. 161 req.Header.Set("Accept", mediaTypeIntegrationPreview) 162 163 var i []*Installation 164 resp, err := s.client.Do(ctx, req, &i) 165 if err != nil { 166 return nil, resp, err 167 } 168 169 return i, resp, nil 170} 171 172// GetInstallation returns the specified installation. 173// 174// GitHub API docs: https://developer.github.com/v3/apps/#get-a-single-installation 175func (s *AppsService) GetInstallation(ctx context.Context, id int64) (*Installation, *Response, error) { 176 return s.getInstallation(ctx, fmt.Sprintf("app/installations/%v", id)) 177} 178 179// ListUserInstallations lists installations that are accessible to the authenticated user. 180// 181// GitHub API docs: https://developer.github.com/v3/apps/#list-installations-for-user 182func (s *AppsService) ListUserInstallations(ctx context.Context, opt *ListOptions) ([]*Installation, *Response, error) { 183 u, err := addOptions("user/installations", opt) 184 if err != nil { 185 return nil, nil, err 186 } 187 188 req, err := s.client.NewRequest("GET", u, nil) 189 if err != nil { 190 return nil, nil, err 191 } 192 193 // TODO: remove custom Accept header when this API fully launches. 194 req.Header.Set("Accept", mediaTypeIntegrationPreview) 195 196 var i struct { 197 Installations []*Installation `json:"installations"` 198 } 199 resp, err := s.client.Do(ctx, req, &i) 200 if err != nil { 201 return nil, resp, err 202 } 203 204 return i.Installations, resp, nil 205} 206 207// CreateInstallationToken creates a new installation token. 208// 209// GitHub API docs: https://developer.github.com/v3/apps/#create-a-new-installation-token 210func (s *AppsService) CreateInstallationToken(ctx context.Context, id int64, opt *InstallationTokenOptions) (*InstallationToken, *Response, error) { 211 u := fmt.Sprintf("app/installations/%v/access_tokens", id) 212 213 req, err := s.client.NewRequest("POST", u, opt) 214 if err != nil { 215 return nil, nil, err 216 } 217 218 // TODO: remove custom Accept header when this API fully launches. 219 req.Header.Set("Accept", mediaTypeIntegrationPreview) 220 221 t := new(InstallationToken) 222 resp, err := s.client.Do(ctx, req, t) 223 if err != nil { 224 return nil, resp, err 225 } 226 227 return t, resp, nil 228} 229 230// Create a new attachment on user comment containing a url. 231// 232// GitHub API docs: https://developer.github.com/v3/apps/#create-a-content-attachment 233func (s *AppsService) CreateAttachment(ctx context.Context, contentReferenceID int64, title, body string) (*Attachment, *Response, error) { 234 u := fmt.Sprintf("content_references/%v/attachments", contentReferenceID) 235 payload := &Attachment{Title: String(title), Body: String(body)} 236 req, err := s.client.NewRequest("POST", u, payload) 237 if err != nil { 238 return nil, nil, err 239 } 240 241 // TODO: remove custom Accept headers when APIs fully launch. 242 req.Header.Set("Accept", mediaTypeReactionsPreview) 243 244 m := &Attachment{} 245 resp, err := s.client.Do(ctx, req, m) 246 if err != nil { 247 return nil, resp, err 248 } 249 250 return m, resp, nil 251} 252 253// FindOrganizationInstallation finds the organization's installation information. 254// 255// GitHub API docs: https://developer.github.com/v3/apps/#find-organization-installation 256func (s *AppsService) FindOrganizationInstallation(ctx context.Context, org string) (*Installation, *Response, error) { 257 return s.getInstallation(ctx, fmt.Sprintf("orgs/%v/installation", org)) 258} 259 260// FindRepositoryInstallation finds the repository's installation information. 261// 262// GitHub API docs: https://developer.github.com/v3/apps/#find-repository-installation 263func (s *AppsService) FindRepositoryInstallation(ctx context.Context, owner, repo string) (*Installation, *Response, error) { 264 return s.getInstallation(ctx, fmt.Sprintf("repos/%v/%v/installation", owner, repo)) 265} 266 267// FindRepositoryInstallationByID finds the repository's installation information. 268// 269// Note: FindRepositoryInstallationByID uses the undocumented GitHub API endpoint /repositories/:id/installation. 270func (s *AppsService) FindRepositoryInstallationByID(ctx context.Context, id int64) (*Installation, *Response, error) { 271 return s.getInstallation(ctx, fmt.Sprintf("repositories/%d/installation", id)) 272} 273 274// FindUserInstallation finds the user's installation information. 275// 276// GitHub API docs: https://developer.github.com/v3/apps/#find-repository-installation 277func (s *AppsService) FindUserInstallation(ctx context.Context, user string) (*Installation, *Response, error) { 278 return s.getInstallation(ctx, fmt.Sprintf("users/%v/installation", user)) 279} 280 281func (s *AppsService) getInstallation(ctx context.Context, url string) (*Installation, *Response, error) { 282 req, err := s.client.NewRequest("GET", url, nil) 283 if err != nil { 284 return nil, nil, err 285 } 286 287 // TODO: remove custom Accept header when this API fully launches. 288 req.Header.Set("Accept", mediaTypeIntegrationPreview) 289 290 i := new(Installation) 291 resp, err := s.client.Do(ctx, req, i) 292 if err != nil { 293 return nil, resp, err 294 } 295 296 return i, resp, nil 297} 298