github.com/google/go-github/v74@v74.0.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]any `json:"last_response,omitempty"` 51 52 // Only the following fields are used when creating a hook. 53 // Config is required. 54 Config *HookConfig `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 *HookConfig `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/rest/repos/webhooks#create-a-repository-webhook 83 // 84 //meta:operation POST /repos/{owner}/{repo}/hooks 85 func (s *RepositoriesService) CreateHook(ctx context.Context, owner, repo string, hook *Hook) (*Hook, *Response, error) { 86 u := fmt.Sprintf("repos/%v/%v/hooks", owner, repo) 87 88 hookReq := &createHookRequest{ 89 Name: "web", 90 Events: hook.Events, 91 Active: hook.Active, 92 Config: hook.Config, 93 } 94 95 req, err := s.client.NewRequest("POST", u, hookReq) 96 if err != nil { 97 return nil, nil, err 98 } 99 100 h := new(Hook) 101 resp, err := s.client.Do(ctx, req, h) 102 if err != nil { 103 return nil, resp, err 104 } 105 106 return h, resp, nil 107 } 108 109 // ListHooks lists all Hooks for the specified repository. 110 // 111 // GitHub API docs: https://docs.github.com/rest/repos/webhooks#list-repository-webhooks 112 // 113 //meta:operation GET /repos/{owner}/{repo}/hooks 114 func (s *RepositoriesService) ListHooks(ctx context.Context, owner, repo string, opts *ListOptions) ([]*Hook, *Response, error) { 115 u := fmt.Sprintf("repos/%v/%v/hooks", owner, repo) 116 u, err := addOptions(u, opts) 117 if err != nil { 118 return nil, nil, err 119 } 120 121 req, err := s.client.NewRequest("GET", u, nil) 122 if err != nil { 123 return nil, nil, err 124 } 125 126 var hooks []*Hook 127 resp, err := s.client.Do(ctx, req, &hooks) 128 if err != nil { 129 return nil, resp, err 130 } 131 132 return hooks, resp, nil 133 } 134 135 // GetHook returns a single specified Hook. 136 // 137 // GitHub API docs: https://docs.github.com/rest/repos/webhooks#get-a-repository-webhook 138 // 139 //meta:operation GET /repos/{owner}/{repo}/hooks/{hook_id} 140 func (s *RepositoriesService) GetHook(ctx context.Context, owner, repo string, id int64) (*Hook, *Response, error) { 141 u := fmt.Sprintf("repos/%v/%v/hooks/%d", owner, repo, id) 142 req, err := s.client.NewRequest("GET", u, nil) 143 if err != nil { 144 return nil, nil, err 145 } 146 h := new(Hook) 147 resp, err := s.client.Do(ctx, req, h) 148 if err != nil { 149 return nil, resp, err 150 } 151 152 return h, resp, nil 153 } 154 155 // EditHook updates a specified Hook. 156 // 157 // GitHub API docs: https://docs.github.com/rest/repos/webhooks#update-a-repository-webhook 158 // 159 //meta:operation PATCH /repos/{owner}/{repo}/hooks/{hook_id} 160 func (s *RepositoriesService) EditHook(ctx context.Context, owner, repo string, id int64, hook *Hook) (*Hook, *Response, error) { 161 u := fmt.Sprintf("repos/%v/%v/hooks/%d", owner, repo, id) 162 req, err := s.client.NewRequest("PATCH", u, hook) 163 if err != nil { 164 return nil, nil, err 165 } 166 h := new(Hook) 167 resp, err := s.client.Do(ctx, req, h) 168 if err != nil { 169 return nil, resp, err 170 } 171 172 return h, resp, nil 173 } 174 175 // DeleteHook deletes a specified Hook. 176 // 177 // GitHub API docs: https://docs.github.com/rest/repos/webhooks#delete-a-repository-webhook 178 // 179 //meta:operation DELETE /repos/{owner}/{repo}/hooks/{hook_id} 180 func (s *RepositoriesService) DeleteHook(ctx context.Context, owner, repo string, id int64) (*Response, error) { 181 u := fmt.Sprintf("repos/%v/%v/hooks/%d", owner, repo, id) 182 req, err := s.client.NewRequest("DELETE", u, nil) 183 if err != nil { 184 return nil, err 185 } 186 return s.client.Do(ctx, req, nil) 187 } 188 189 // PingHook triggers a 'ping' event to be sent to the Hook. 190 // 191 // GitHub API docs: https://docs.github.com/rest/repos/webhooks#ping-a-repository-webhook 192 // 193 //meta:operation POST /repos/{owner}/{repo}/hooks/{hook_id}/pings 194 func (s *RepositoriesService) PingHook(ctx context.Context, owner, repo string, id int64) (*Response, error) { 195 u := fmt.Sprintf("repos/%v/%v/hooks/%d/pings", 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 // TestHook triggers a test Hook by github. 204 // 205 // GitHub API docs: https://docs.github.com/rest/repos/webhooks#test-the-push-repository-webhook 206 // 207 //meta:operation POST /repos/{owner}/{repo}/hooks/{hook_id}/tests 208 func (s *RepositoriesService) TestHook(ctx context.Context, owner, repo string, id int64) (*Response, error) { 209 u := fmt.Sprintf("repos/%v/%v/hooks/%d/tests", owner, repo, id) 210 req, err := s.client.NewRequest("POST", u, nil) 211 if err != nil { 212 return nil, err 213 } 214 return s.client.Do(ctx, req, nil) 215 } 216 217 // Subscribe lets servers register to receive updates when a topic is updated. 218 // 219 // GitHub API docs: https://docs.github.com/webhooks/about-webhooks-for-repositories#pubsubhubbub 220 // 221 //meta:operation POST /hub 222 func (s *RepositoriesService) Subscribe(ctx context.Context, owner, repo, event, callback string, secret []byte) (*Response, error) { 223 req, err := s.createWebSubRequest("subscribe", owner, repo, event, callback, secret) 224 if err != nil { 225 return nil, err 226 } 227 228 return s.client.Do(ctx, req, nil) 229 } 230 231 // Unsubscribe lets servers unregister to no longer receive updates when a topic is updated. 232 // 233 // GitHub API docs: https://docs.github.com/webhooks/about-webhooks-for-repositories#pubsubhubbub 234 // 235 //meta:operation POST /hub 236 func (s *RepositoriesService) Unsubscribe(ctx context.Context, owner, repo, event, callback string, secret []byte) (*Response, error) { 237 req, err := s.createWebSubRequest("unsubscribe", owner, repo, event, callback, secret) 238 if err != nil { 239 return nil, err 240 } 241 242 return s.client.Do(ctx, req, nil) 243 } 244 245 // createWebSubRequest returns a subscribe/unsubscribe request that implements 246 // the WebSub (formerly PubSubHubbub) protocol. 247 // 248 // See: https://www.w3.org/TR/websub/#subscriber-sends-subscription-request 249 func (s *RepositoriesService) createWebSubRequest(hubMode, owner, repo, event, callback string, secret []byte) (*http.Request, error) { 250 topic := fmt.Sprintf( 251 "https://github.com/%s/%s/events/%s", 252 owner, 253 repo, 254 event, 255 ) 256 form := url.Values{} 257 form.Add("hub.mode", hubMode) 258 form.Add("hub.topic", topic) 259 form.Add("hub.callback", callback) 260 if secret != nil { 261 form.Add("hub.secret", string(secret)) 262 } 263 body := strings.NewReader(form.Encode()) 264 265 req, err := s.client.NewFormRequest("hub", body) 266 if err != nil { 267 return nil, err 268 } 269 270 return req, nil 271 }