github.com/google/go-github/v66@v66.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]interface{} `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  }