github.com/google/go-github/v50@v50.2.0/github/repos_hooks.go (about) 1 // Copyright 2013 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 6 package github 7 8 import ( 9 "context" 10 "fmt" 11 "net/http" 12 "net/url" 13 "strings" 14 ) 15 16 // WebHookPayload represents the data that is received from GitHub when a push 17 // event hook is triggered. The format of these payloads pre-date most of the 18 // GitHub v3 API, so there are lots of minor incompatibilities with the types 19 // defined in the rest of the API. Therefore, several types are duplicated 20 // here to account for these differences. 21 // 22 // GitHub API docs: https://help.github.com/articles/post-receive-hooks 23 // 24 // Deprecated: Please use PushEvent instead. 25 type WebHookPayload = PushEvent 26 27 // WebHookCommit represents the commit variant we receive from GitHub in a 28 // WebHookPayload. 29 // 30 // Deprecated: Please use HeadCommit instead. 31 type WebHookCommit = HeadCommit 32 33 // WebHookAuthor represents the author or committer of a commit, as specified 34 // in a WebHookCommit. The commit author may not correspond to a GitHub User. 35 // 36 // Deprecated: Please use CommitAuthor instead. 37 // NOTE Breaking API change: the `Username` field is now called `Login`. 38 type WebHookAuthor = CommitAuthor 39 40 // Hook represents a GitHub (web and service) hook for a repository. 41 type Hook struct { 42 CreatedAt *Timestamp `json:"created_at,omitempty"` 43 UpdatedAt *Timestamp `json:"updated_at,omitempty"` 44 URL *string `json:"url,omitempty"` 45 ID *int64 `json:"id,omitempty"` 46 Type *string `json:"type,omitempty"` 47 Name *string `json:"name,omitempty"` 48 TestURL *string `json:"test_url,omitempty"` 49 PingURL *string `json:"ping_url,omitempty"` 50 LastResponse map[string]interface{} `json:"last_response,omitempty"` 51 52 // Only the following fields are used when creating a hook. 53 // Config is required. 54 Config map[string]interface{} `json:"config,omitempty"` 55 Events []string `json:"events,omitempty"` 56 Active *bool `json:"active,omitempty"` 57 } 58 59 func (h Hook) String() string { 60 return Stringify(h) 61 } 62 63 // createHookRequest is a subset of Hook and is used internally 64 // by CreateHook to pass only the known fields for the endpoint. 65 // 66 // See https://github.com/google/go-github/issues/1015 for more 67 // information. 68 type createHookRequest struct { 69 // Config is required. 70 Name string `json:"name"` 71 Config map[string]interface{} `json:"config,omitempty"` 72 Events []string `json:"events,omitempty"` 73 Active *bool `json:"active,omitempty"` 74 } 75 76 // CreateHook creates a Hook for the specified repository. 77 // Config is a required field. 78 // 79 // Note that only a subset of the hook fields are used and hook must 80 // not be nil. 81 // 82 // GitHub API docs: https://docs.github.com/en/rest/webhooks/repos#create-a-repository-webhook 83 func (s *RepositoriesService) CreateHook(ctx context.Context, owner, repo string, hook *Hook) (*Hook, *Response, error) { 84 u := fmt.Sprintf("repos/%v/%v/hooks", owner, repo) 85 86 hookReq := &createHookRequest{ 87 Name: "web", 88 Events: hook.Events, 89 Active: hook.Active, 90 Config: hook.Config, 91 } 92 93 req, err := s.client.NewRequest("POST", u, hookReq) 94 if err != nil { 95 return nil, nil, err 96 } 97 98 h := new(Hook) 99 resp, err := s.client.Do(ctx, req, h) 100 if err != nil { 101 return nil, resp, err 102 } 103 104 return h, resp, nil 105 } 106 107 // ListHooks lists all Hooks for the specified repository. 108 // 109 // GitHub API docs: https://docs.github.com/en/rest/webhooks/repos#list-repository-webhooks 110 func (s *RepositoriesService) ListHooks(ctx context.Context, owner, repo string, opts *ListOptions) ([]*Hook, *Response, error) { 111 u := fmt.Sprintf("repos/%v/%v/hooks", owner, repo) 112 u, err := addOptions(u, opts) 113 if err != nil { 114 return nil, nil, err 115 } 116 117 req, err := s.client.NewRequest("GET", u, nil) 118 if err != nil { 119 return nil, nil, err 120 } 121 122 var hooks []*Hook 123 resp, err := s.client.Do(ctx, req, &hooks) 124 if err != nil { 125 return nil, resp, err 126 } 127 128 return hooks, resp, nil 129 } 130 131 // GetHook returns a single specified Hook. 132 // 133 // GitHub API docs: https://docs.github.com/en/rest/webhooks/repos#get-a-repository-webhook 134 func (s *RepositoriesService) GetHook(ctx context.Context, owner, repo string, id int64) (*Hook, *Response, error) { 135 u := fmt.Sprintf("repos/%v/%v/hooks/%d", owner, repo, id) 136 req, err := s.client.NewRequest("GET", u, nil) 137 if err != nil { 138 return nil, nil, err 139 } 140 h := new(Hook) 141 resp, err := s.client.Do(ctx, req, h) 142 if err != nil { 143 return nil, resp, err 144 } 145 146 return h, resp, nil 147 } 148 149 // EditHook updates a specified Hook. 150 // 151 // GitHub API docs: https://docs.github.com/en/rest/webhooks/repos#update-a-repository-webhook 152 func (s *RepositoriesService) EditHook(ctx context.Context, owner, repo string, id int64, hook *Hook) (*Hook, *Response, error) { 153 u := fmt.Sprintf("repos/%v/%v/hooks/%d", owner, repo, id) 154 req, err := s.client.NewRequest("PATCH", u, hook) 155 if err != nil { 156 return nil, nil, err 157 } 158 h := new(Hook) 159 resp, err := s.client.Do(ctx, req, h) 160 if err != nil { 161 return nil, resp, err 162 } 163 164 return h, resp, nil 165 } 166 167 // DeleteHook deletes a specified Hook. 168 // 169 // GitHub API docs: https://docs.github.com/en/rest/webhooks/repos#delete-a-repository-webhook 170 func (s *RepositoriesService) DeleteHook(ctx context.Context, owner, repo string, id int64) (*Response, error) { 171 u := fmt.Sprintf("repos/%v/%v/hooks/%d", owner, repo, id) 172 req, err := s.client.NewRequest("DELETE", u, nil) 173 if err != nil { 174 return nil, err 175 } 176 return s.client.Do(ctx, req, nil) 177 } 178 179 // PingHook triggers a 'ping' event to be sent to the Hook. 180 // 181 // GitHub API docs: https://docs.github.com/en/rest/webhooks/repos#ping-a-repository-webhook 182 func (s *RepositoriesService) PingHook(ctx context.Context, owner, repo string, id int64) (*Response, error) { 183 u := fmt.Sprintf("repos/%v/%v/hooks/%d/pings", owner, repo, id) 184 req, err := s.client.NewRequest("POST", u, nil) 185 if err != nil { 186 return nil, err 187 } 188 return s.client.Do(ctx, req, nil) 189 } 190 191 // TestHook triggers a test Hook by github. 192 // 193 // GitHub API docs: https://docs.github.com/en/rest/webhooks/repos#test-the-push-repository-webhook 194 func (s *RepositoriesService) TestHook(ctx context.Context, owner, repo string, id int64) (*Response, error) { 195 u := fmt.Sprintf("repos/%v/%v/hooks/%d/tests", owner, repo, id) 196 req, err := s.client.NewRequest("POST", u, nil) 197 if err != nil { 198 return nil, err 199 } 200 return s.client.Do(ctx, req, nil) 201 } 202 203 // Subscribe lets servers register to receive updates when a topic is updated. 204 // 205 // GitHub API docs: https://docs.github.com/en/rest/webhooks#pubsubhubbub 206 func (s *RepositoriesService) Subscribe(ctx context.Context, owner, repo, event, callback string, secret []byte) (*Response, error) { 207 req, err := s.createWebSubRequest("subscribe", owner, repo, event, callback, secret) 208 if err != nil { 209 return nil, err 210 } 211 212 return s.client.Do(ctx, req, nil) 213 } 214 215 // Unsubscribe lets servers unregister to no longer receive updates when a topic is updated. 216 // 217 // GitHub API docs: https://docs.github.com/en/rest/webhooks#pubsubhubbub 218 func (s *RepositoriesService) Unsubscribe(ctx context.Context, owner, repo, event, callback string, secret []byte) (*Response, error) { 219 req, err := s.createWebSubRequest("unsubscribe", owner, repo, event, callback, secret) 220 if err != nil { 221 return nil, err 222 } 223 224 return s.client.Do(ctx, req, nil) 225 } 226 227 // createWebSubRequest returns a subscribe/unsubscribe request that implements 228 // the WebSub (formerly PubSubHubbub) protocol. 229 // 230 // See: https://www.w3.org/TR/websub/#subscriber-sends-subscription-request 231 func (s *RepositoriesService) createWebSubRequest(hubMode, owner, repo, event, callback string, secret []byte) (*http.Request, error) { 232 topic := fmt.Sprintf( 233 "https://github.com/%s/%s/events/%s", 234 owner, 235 repo, 236 event, 237 ) 238 form := url.Values{} 239 form.Add("hub.mode", hubMode) 240 form.Add("hub.topic", topic) 241 form.Add("hub.callback", callback) 242 if secret != nil { 243 form.Add("hub.secret", string(secret)) 244 } 245 body := strings.NewReader(form.Encode()) 246 247 req, err := s.client.NewFormRequest("hub", body) 248 if err != nil { 249 return nil, err 250 } 251 252 return req, nil 253 }