sigs.k8s.io/prow@v0.0.0-20240503223140-c5e374dc7eb1/pkg/github/types.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package github
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"strings"
    23  	"time"
    24  
    25  	utilerrors "k8s.io/apimachinery/pkg/util/errors"
    26  )
    27  
    28  const (
    29  	// EventGUID is sent by GitHub in a header of every webhook request.
    30  	// Used as a log field across prow.
    31  	EventGUID = "event-GUID"
    32  	// PrLogField is the number of a PR.
    33  	// Used as a log field across prow.
    34  	PrLogField = "pr"
    35  	// OrgLogField is the organization of a PR.
    36  	// Used as a log field across prow.
    37  	OrgLogField = "org"
    38  	// RepoLogField is the repository of a PR.
    39  	// Used as a log field across prow.
    40  	RepoLogField = "repo"
    41  
    42  	// SearchTimeFormat is a time.Time format string for ISO8601 which is the
    43  	// format that GitHub requires for times specified as part of a search query.
    44  	SearchTimeFormat = "2006-01-02T15:04:05Z"
    45  
    46  	// DefaultAPIEndpoint is the default GitHub API endpoint.
    47  	DefaultAPIEndpoint = "https://api.github.com"
    48  
    49  	// DefaultHost is the default GitHub base endpoint.
    50  	DefaultHost = "github.com"
    51  
    52  	// DefaultGraphQLEndpoint is the default GitHub GraphQL API endpoint.
    53  	DefaultGraphQLEndpoint = "https://api.github.com/graphql"
    54  )
    55  
    56  var (
    57  	// FoundingYear is the year GitHub was founded. This is just used so that
    58  	// we can lower bound dates related to PRs and issues.
    59  	FoundingYear, _ = time.Parse(SearchTimeFormat, "2007-01-01T00:00:00Z")
    60  )
    61  
    62  // These are possible State entries for a Status.
    63  const (
    64  	StatusPending = "pending"
    65  	StatusSuccess = "success"
    66  	StatusError   = "error"
    67  	StatusFailure = "failure"
    68  )
    69  
    70  // Possible contents for reactions.
    71  const (
    72  	ReactionThumbsUp                  = "+1"
    73  	ReactionThumbsDown                = "-1"
    74  	ReactionLaugh                     = "laugh"
    75  	ReactionConfused                  = "confused"
    76  	ReactionHeart                     = "heart"
    77  	ReactionHooray                    = "hooray"
    78  	stateCannotBeChangedMessagePrefix = "state cannot be changed."
    79  )
    80  
    81  func unmarshalClientError(b []byte) error {
    82  	var errors []error
    83  	clientError := ClientError{}
    84  	err := json.Unmarshal(b, &clientError)
    85  	if err == nil {
    86  		return clientError
    87  	}
    88  	errors = append(errors, err)
    89  	alternativeClientError := AlternativeClientError{}
    90  	err = json.Unmarshal(b, &alternativeClientError)
    91  	if err == nil {
    92  		return alternativeClientError
    93  	}
    94  	errors = append(errors, err)
    95  	return utilerrors.NewAggregate(errors)
    96  }
    97  
    98  // ClientError represents https://developer.github.com/v3/#client-errors
    99  type ClientError struct {
   100  	Message string                `json:"message"`
   101  	Errors  []clientErrorSubError `json:"errors,omitempty"`
   102  }
   103  
   104  type clientErrorSubError struct {
   105  	Resource string `json:"resource"`
   106  	Field    string `json:"field"`
   107  	Code     string `json:"code"`
   108  	Message  string `json:"message,omitempty"`
   109  }
   110  
   111  func (r ClientError) Error() string {
   112  	return r.Message
   113  }
   114  
   115  // AlternativeClientError represents an alternative format for https://developer.github.com/v3/#client-errors
   116  // This is probably a GitHub bug, as documentation_url should appear only in custom errors
   117  type AlternativeClientError struct {
   118  	Message          string   `json:"message"`
   119  	Errors           []string `json:"errors,omitempty"`
   120  	DocumentationURL string   `json:"documentation_url,omitempty"`
   121  }
   122  
   123  func (r AlternativeClientError) Error() string {
   124  	return r.Message
   125  }
   126  
   127  // Reaction holds the type of emotional reaction.
   128  type Reaction struct {
   129  	Content string `json:"content"`
   130  }
   131  
   132  // Status is used to set a commit status line.
   133  type Status struct {
   134  	State       string `json:"state"`
   135  	TargetURL   string `json:"target_url,omitempty"`
   136  	Description string `json:"description,omitempty"`
   137  	Context     string `json:"context,omitempty"`
   138  }
   139  
   140  // CombinedStatus is the latest statuses for a ref.
   141  type CombinedStatus struct {
   142  	SHA      string   `json:"sha"`
   143  	Statuses []Status `json:"statuses"`
   144  	State    string   `json:"state"`
   145  }
   146  
   147  // User is a GitHub user account.
   148  type User struct {
   149  	Login       string          `json:"login"`
   150  	Name        string          `json:"name"`
   151  	Email       string          `json:"email"`
   152  	ID          int             `json:"id"`
   153  	HTMLURL     string          `json:"html_url"`
   154  	Permissions RepoPermissions `json:"permissions"`
   155  	Type        string          `json:"type"`
   156  }
   157  
   158  const (
   159  	// UserTypeUser identifies an actual user account in the User.Type field
   160  	UserTypeUser = "User"
   161  	// UserTypeBot identifies a github app bot user in the User.Type field
   162  	UserTypeBot = "Bot"
   163  )
   164  
   165  // NormLogin normalizes GitHub login strings
   166  func NormLogin(login string) string {
   167  	return strings.TrimPrefix(strings.ToLower(login), "@")
   168  }
   169  
   170  // PullRequestEventAction enumerates the triggers for this
   171  // webhook payload type. See also:
   172  // https://developer.github.com/v3/activity/events/types/#pullrequestevent
   173  type PullRequestEventAction string
   174  
   175  const (
   176  	// PullRequestActionAssigned means assignees were added.
   177  	PullRequestActionAssigned PullRequestEventAction = "assigned"
   178  	// PullRequestActionUnassigned means assignees were removed.
   179  	PullRequestActionUnassigned PullRequestEventAction = "unassigned"
   180  	// PullRequestActionReviewRequested means review requests were added.
   181  	PullRequestActionReviewRequested PullRequestEventAction = "review_requested"
   182  	// PullRequestActionReviewRequestRemoved means review requests were removed.
   183  	PullRequestActionReviewRequestRemoved PullRequestEventAction = "review_request_removed"
   184  	// PullRequestActionLabeled means labels were added.
   185  	PullRequestActionLabeled PullRequestEventAction = "labeled"
   186  	// PullRequestActionUnlabeled means labels were removed
   187  	PullRequestActionUnlabeled PullRequestEventAction = "unlabeled"
   188  	// PullRequestActionOpened means the PR was created
   189  	PullRequestActionOpened PullRequestEventAction = "opened"
   190  	// PullRequestActionEdited means the PR body changed.
   191  	PullRequestActionEdited PullRequestEventAction = "edited"
   192  	// PullRequestActionClosed means the PR was closed (or was merged).
   193  	PullRequestActionClosed PullRequestEventAction = "closed"
   194  	// PullRequestActionReopened means the PR was reopened.
   195  	PullRequestActionReopened PullRequestEventAction = "reopened"
   196  	// PullRequestActionSynchronize means the git state changed.
   197  	PullRequestActionSynchronize PullRequestEventAction = "synchronize"
   198  	// PullRequestActionReadyForReview means the PR is no longer a draft PR.
   199  	PullRequestActionReadyForReview PullRequestEventAction = "ready_for_review"
   200  	// PullRequestActionConvertedToDraft means the PR is now a draft PR.
   201  	PullRequestActionConvertedToDraft PullRequestEventAction = "converted_to_draft"
   202  	// PullRequestActionLocked means labels were added.
   203  	PullRequestActionLocked PullRequestEventAction = "locked"
   204  	// PullRequestActionUnlocked means labels were removed
   205  	PullRequestActionUnlocked PullRequestEventAction = "unlocked"
   206  	// PullRequestActionAutoMergeEnabled means auto merge was enabled
   207  	PullRequestActionAutoMergeEnabled PullRequestEventAction = "auto_merge_enabled"
   208  	// PullRequestActionAutoMergeDisabled means auto merge was disabled
   209  	PullRequestActionAutoMergeDisabled PullRequestEventAction = "auto_merge_disabled"
   210  )
   211  
   212  // GenericEvent is a lightweight struct containing just Sender, Organization and Repo as
   213  // they are allWebhook payload object common properties:
   214  // https://developer.github.com/webhooks/event-payloads/#webhook-payload-object-common-properties
   215  type GenericEvent struct {
   216  	Sender User         `json:"sender"`
   217  	Org    Organization `json:"organization"`
   218  	Repo   Repo         `json:"repository"`
   219  }
   220  
   221  // PullRequestEvent is what GitHub sends us when a PR is changed.
   222  type PullRequestEvent struct {
   223  	Action      PullRequestEventAction `json:"action"`
   224  	Number      int                    `json:"number"`
   225  	PullRequest PullRequest            `json:"pull_request"`
   226  	Repo        Repo                   `json:"repository"`
   227  	Label       Label                  `json:"label"`
   228  	Sender      User                   `json:"sender"`
   229  
   230  	// Changes holds raw change data, which we must inspect
   231  	// and deserialize later as this is a polymorphic field
   232  	Changes json.RawMessage `json:"changes"`
   233  
   234  	// GUID is included in the header of the request received by GitHub.
   235  	GUID string
   236  }
   237  
   238  const (
   239  	PullRequestStateOpen   = "open"
   240  	PullRequestStateClosed = "closed"
   241  )
   242  
   243  // PullRequest contains information about a PullRequest.
   244  type PullRequest struct {
   245  	ID                 int               `json:"id"`
   246  	NodeID             string            `json:"node_id"`
   247  	Number             int               `json:"number"`
   248  	HTMLURL            string            `json:"html_url"`
   249  	User               User              `json:"user"`
   250  	Labels             []Label           `json:"labels"`
   251  	Base               PullRequestBranch `json:"base"`
   252  	Head               PullRequestBranch `json:"head"`
   253  	Title              string            `json:"title"`
   254  	Body               string            `json:"body"`
   255  	RequestedReviewers []User            `json:"requested_reviewers"`
   256  	RequestedTeams     []Team            `json:"requested_teams"`
   257  	Assignees          []User            `json:"assignees"`
   258  	State              string            `json:"state"`
   259  	Draft              bool              `json:"draft"`
   260  	Merged             bool              `json:"merged"`
   261  	CreatedAt          time.Time         `json:"created_at,omitempty"`
   262  	UpdatedAt          time.Time         `json:"updated_at,omitempty"`
   263  	// ref https://developer.github.com/v3/pulls/#get-a-single-pull-request
   264  	// If Merged is true, MergeSHA is the SHA of the merge commit, or squashed commit
   265  	// If Merged is false, MergeSHA is a commit SHA that github created to test if
   266  	// the PR can be merged automatically.
   267  	MergeSHA *string `json:"merge_commit_sha"`
   268  	// ref https://developer.github.com/v3/pulls/#response-1
   269  	// The value of the mergeable attribute can be true, false, or null. If the value
   270  	// is null, this means that the mergeability hasn't been computed yet, and a
   271  	// background job was started to compute it. When the job is complete, the response
   272  	// will include a non-null value for the mergeable attribute.
   273  	Mergable *bool `json:"mergeable,omitempty"`
   274  	// If the PR doesn't have any milestone, `milestone` is null and is unmarshaled to nil.
   275  	Milestone         *Milestone `json:"milestone,omitempty"`
   276  	Commits           int        `json:"commits"`
   277  	AuthorAssociation string     `json:"author_association,omitempty"`
   278  }
   279  
   280  // PullRequestBranch contains information about a particular branch in a PR.
   281  type PullRequestBranch struct {
   282  	Ref  string `json:"ref"`
   283  	SHA  string `json:"sha"`
   284  	Repo Repo   `json:"repo"`
   285  }
   286  
   287  // Label describes a GitHub label.
   288  type Label struct {
   289  	URL         string `json:"url"`
   290  	Name        string `json:"name"`
   291  	Description string `json:"description"`
   292  	Color       string `json:"color"`
   293  }
   294  
   295  // PullRequestFileStatus enumerates the statuses for this webhook payload type.
   296  type PullRequestFileStatus string
   297  
   298  const (
   299  	// PullRequestFileModified means a file changed.
   300  	PullRequestFileModified PullRequestFileStatus = "modified"
   301  	// PullRequestFileAdded means a file was added.
   302  	PullRequestFileAdded = "added"
   303  	// PullRequestFileRemoved means a file was deleted.
   304  	PullRequestFileRemoved = "removed"
   305  	// PullRequestFileRenamed means a file moved.
   306  	PullRequestFileRenamed = "renamed"
   307  )
   308  
   309  // PullRequestChange contains information about what a PR changed.
   310  type PullRequestChange struct {
   311  	SHA              string `json:"sha"`
   312  	Filename         string `json:"filename"`
   313  	Status           string `json:"status"`
   314  	Additions        int    `json:"additions"`
   315  	Deletions        int    `json:"deletions"`
   316  	Changes          int    `json:"changes"`
   317  	Patch            string `json:"patch"`
   318  	BlobURL          string `json:"blob_url"`
   319  	PreviousFilename string `json:"previous_filename"`
   320  }
   321  
   322  // Repo contains general repository information: it includes fields available
   323  // in repo records returned by GH "List" methods but not those returned by GH
   324  // "Get" method. Use FullRepo struct for "Get" method.
   325  // See also https://developer.github.com/v3/repos/#list-organization-repositories
   326  type Repo struct {
   327  	Owner         User   `json:"owner"`
   328  	Name          string `json:"name"`
   329  	FullName      string `json:"full_name"`
   330  	HTMLURL       string `json:"html_url"`
   331  	Fork          bool   `json:"fork"`
   332  	DefaultBranch string `json:"default_branch"`
   333  	Archived      bool   `json:"archived"`
   334  	Private       bool   `json:"private"`
   335  	Description   string `json:"description"`
   336  	Homepage      string `json:"homepage"`
   337  	HasIssues     bool   `json:"has_issues"`
   338  	HasProjects   bool   `json:"has_projects"`
   339  	HasWiki       bool   `json:"has_wiki"`
   340  	NodeID        string `json:"node_id"`
   341  	// Permissions reflect the permission level for the requester, so
   342  	// on a repository GET call this will be for the user whose token
   343  	// is being used, if listing a team's repos this will be for the
   344  	// team's privilege level in the repo
   345  	Permissions RepoPermissions `json:"permissions"`
   346  	Parent      ParentRepo      `json:"parent"`
   347  }
   348  
   349  // ParentRepo contains a small subsection of general repository information: it
   350  // just includes the information needed to confirm that a parent repo exists
   351  // and what the name of that repo is.
   352  type ParentRepo struct {
   353  	Owner    User   `json:"owner"`
   354  	Name     string `json:"name"`
   355  	FullName string `json:"full_name"`
   356  	HTMLURL  string `json:"html_url"`
   357  }
   358  
   359  // Repo contains detailed repository information, including items
   360  // that are not available in repo records returned by GH "List" methods
   361  // but are in those returned by GH "Get" method.
   362  // See https://developer.github.com/v3/repos/#list-organization-repositories
   363  // See https://developer.github.com/v3/repos/#get
   364  type FullRepo struct {
   365  	Repo
   366  
   367  	AllowSquashMerge         bool   `json:"allow_squash_merge,omitempty"`
   368  	AllowMergeCommit         bool   `json:"allow_merge_commit,omitempty"`
   369  	AllowRebaseMerge         bool   `json:"allow_rebase_merge,omitempty"`
   370  	SquashMergeCommitTitle   string `json:"squash_merge_commit_title,omitempty"`
   371  	SquashMergeCommitMessage string `json:"squash_merge_commit_message,omitempty"`
   372  }
   373  
   374  // RepoRequest contains metadata used in requests to create or update a Repo.
   375  // Compared to `Repo`, its members are pointers to allow the "not set/use default
   376  // semantics.
   377  // See also:
   378  // - https://developer.github.com/v3/repos/#create
   379  // - https://developer.github.com/v3/repos/#edit
   380  type RepoRequest struct {
   381  	Name                     *string `json:"name,omitempty"`
   382  	Description              *string `json:"description,omitempty"`
   383  	Homepage                 *string `json:"homepage,omitempty"`
   384  	Private                  *bool   `json:"private,omitempty"`
   385  	HasIssues                *bool   `json:"has_issues,omitempty"`
   386  	HasProjects              *bool   `json:"has_projects,omitempty"`
   387  	HasWiki                  *bool   `json:"has_wiki,omitempty"`
   388  	AllowSquashMerge         *bool   `json:"allow_squash_merge,omitempty"`
   389  	AllowMergeCommit         *bool   `json:"allow_merge_commit,omitempty"`
   390  	AllowRebaseMerge         *bool   `json:"allow_rebase_merge,omitempty"`
   391  	SquashMergeCommitTitle   *string `json:"squash_merge_commit_title,omitempty"`
   392  	SquashMergeCommitMessage *string `json:"squash_merge_commit_message,omitempty"`
   393  }
   394  
   395  type WorkflowRuns struct {
   396  	Count       int           `json:"total_count,omitempty"`
   397  	WorflowRuns []WorkflowRun `json:"workflow_runs"`
   398  }
   399  
   400  // RepoCreateRequest contains metadata used in requests to create a repo.
   401  // See also: https://developer.github.com/v3/repos/#create
   402  type RepoCreateRequest struct {
   403  	RepoRequest `json:",omitempty"`
   404  
   405  	AutoInit          *bool   `json:"auto_init,omitempty"`
   406  	GitignoreTemplate *string `json:"gitignore_template,omitempty"`
   407  	LicenseTemplate   *string `json:"license_template,omitempty"`
   408  }
   409  
   410  func (r RepoRequest) ToRepo() *FullRepo {
   411  	setString := func(dest, src *string) {
   412  		if src != nil {
   413  			*dest = *src
   414  		}
   415  	}
   416  	setBool := func(dest, src *bool) {
   417  		if src != nil {
   418  			*dest = *src
   419  		}
   420  	}
   421  
   422  	var repo FullRepo
   423  	setString(&repo.Name, r.Name)
   424  	setString(&repo.Description, r.Description)
   425  	setString(&repo.Homepage, r.Homepage)
   426  	setBool(&repo.Private, r.Private)
   427  	setBool(&repo.HasIssues, r.HasIssues)
   428  	setBool(&repo.HasProjects, r.HasProjects)
   429  	setBool(&repo.HasWiki, r.HasWiki)
   430  	setBool(&repo.AllowSquashMerge, r.AllowSquashMerge)
   431  	setBool(&repo.AllowMergeCommit, r.AllowMergeCommit)
   432  	setBool(&repo.AllowRebaseMerge, r.AllowRebaseMerge)
   433  	setString(&repo.SquashMergeCommitTitle, r.SquashMergeCommitTitle)
   434  	setString(&repo.SquashMergeCommitMessage, r.SquashMergeCommitMessage)
   435  
   436  	return &repo
   437  }
   438  
   439  // Defined returns true if at least one of the pointer fields are not nil
   440  func (r RepoRequest) Defined() bool {
   441  	return r.Name != nil || r.Description != nil || r.Homepage != nil || r.Private != nil ||
   442  		r.HasIssues != nil || r.HasProjects != nil || r.HasWiki != nil || r.AllowSquashMerge != nil ||
   443  		r.AllowMergeCommit != nil || r.AllowRebaseMerge != nil
   444  }
   445  
   446  // RepoUpdateRequest contains metadata used for updating a repository
   447  // See also: https://developer.github.com/v3/repos/#edit
   448  type RepoUpdateRequest struct {
   449  	RepoRequest `json:",omitempty"`
   450  
   451  	DefaultBranch *string `json:"default_branch,omitempty"`
   452  	Archived      *bool   `json:"archived,omitempty"`
   453  }
   454  
   455  func (r RepoUpdateRequest) ToRepo() *FullRepo {
   456  	repo := r.RepoRequest.ToRepo()
   457  	if r.DefaultBranch != nil {
   458  		repo.DefaultBranch = *r.DefaultBranch
   459  	}
   460  	if r.Archived != nil {
   461  		repo.Archived = *r.Archived
   462  	}
   463  
   464  	return repo
   465  }
   466  
   467  func (r RepoUpdateRequest) Defined() bool {
   468  	return r.RepoRequest.Defined() || r.DefaultBranch != nil || r.Archived != nil
   469  }
   470  
   471  // RepoPermissions describes which permission level an entity has in a
   472  // repo. At most one of the booleans here should be true.
   473  type RepoPermissions struct {
   474  	// Pull is equivalent to "Read" permissions in the web UI
   475  	Pull   bool `json:"pull"`
   476  	Triage bool `json:"triage"`
   477  	// Push is equivalent to "Edit" permissions in the web UI
   478  	Push     bool `json:"push"`
   479  	Maintain bool `json:"maintain"`
   480  	Admin    bool `json:"admin"`
   481  }
   482  
   483  // RepoPermissionLevel is admin, write, read or none.
   484  //
   485  // See https://developer.github.com/v3/repos/collaborators/#review-a-users-permission-level
   486  type RepoPermissionLevel string
   487  
   488  // For more information on access levels, see:
   489  // https://docs.github.com/en/github/setting-up-and-managing-organizations-and-teams/repository-permission-levels-for-an-organization
   490  const (
   491  	// Read allows pull but not push
   492  	Read RepoPermissionLevel = "read"
   493  	// Triage allows Read and managing issues
   494  	// pull requests but not push
   495  	Triage RepoPermissionLevel = "triage"
   496  	// Write allows Read plus push
   497  	Write RepoPermissionLevel = "write"
   498  	// Maintain allows Write along with managing
   499  	// repository without access to sensitive or
   500  	// destructive instructions.
   501  	Maintain RepoPermissionLevel = "maintain"
   502  	// Admin allows Write plus change others' rights.
   503  	Admin RepoPermissionLevel = "admin"
   504  	// None disallows everything
   505  	None RepoPermissionLevel = "none"
   506  )
   507  
   508  var repoPermissionLevels = map[RepoPermissionLevel]bool{
   509  	Read:     true,
   510  	Triage:   true,
   511  	Write:    true,
   512  	Maintain: true,
   513  	Admin:    true,
   514  	None:     true,
   515  }
   516  
   517  // MarshalText returns the byte representation of the permission
   518  func (l RepoPermissionLevel) MarshalText() ([]byte, error) {
   519  	return []byte(l), nil
   520  }
   521  
   522  // UnmarshalText validates the text is a valid string
   523  func (l *RepoPermissionLevel) UnmarshalText(text []byte) error {
   524  	v := RepoPermissionLevel(text)
   525  	if _, ok := repoPermissionLevels[v]; !ok {
   526  		return fmt.Errorf("bad repo permission: %s not in %v", v, repoPermissionLevels)
   527  	}
   528  	*l = v
   529  	return nil
   530  }
   531  
   532  type TeamPermission string
   533  
   534  const (
   535  	RepoPull     TeamPermission = "pull"
   536  	RepoTriage   TeamPermission = "triage"
   537  	RepoMaintain TeamPermission = "maintain"
   538  	RepoPush     TeamPermission = "push"
   539  	RepoAdmin    TeamPermission = "admin"
   540  )
   541  
   542  // Branch contains general branch information.
   543  type Branch struct {
   544  	Name      string `json:"name"`
   545  	Protected bool   `json:"protected"` // only included for ?protection=true requests
   546  	// TODO(fejta): consider including undocumented protection key
   547  }
   548  
   549  // BranchProtection represents protections
   550  // currently in place for a branch
   551  // See also: https://developer.github.com/v3/repos/branches/#get-branch-protection
   552  type BranchProtection struct {
   553  	RequiredStatusChecks       *RequiredStatusChecks       `json:"required_status_checks"`
   554  	EnforceAdmins              EnforceAdmins               `json:"enforce_admins"`
   555  	RequiredPullRequestReviews *RequiredPullRequestReviews `json:"required_pull_request_reviews"`
   556  	Restrictions               *Restrictions               `json:"restrictions"`
   557  	AllowForcePushes           AllowForcePushes            `json:"allow_force_pushes"`
   558  	RequiredLinearHistory      RequiredLinearHistory       `json:"required_linear_history"`
   559  	AllowDeletions             AllowDeletions              `json:"allow_deletions"`
   560  }
   561  
   562  // AllowDeletions specifies whether to permit users with push access to delete matching branches.
   563  type AllowDeletions struct {
   564  	Enabled bool `json:"enabled"`
   565  }
   566  
   567  // RequiredLinearHistory specifies whether to prevent merge commits from being pushed to matching branches.
   568  type RequiredLinearHistory struct {
   569  	Enabled bool `json:"enabled"`
   570  }
   571  
   572  // AllowForcePushes specifies whether to permit force pushes for all users with push access.
   573  type AllowForcePushes struct {
   574  	Enabled bool `json:"enabled"`
   575  }
   576  
   577  // EnforceAdmins specifies whether to enforce the
   578  // configured branch restrictions for administrators.
   579  type EnforceAdmins struct {
   580  	Enabled bool `json:"enabled"`
   581  }
   582  
   583  // RequiredPullRequestReviews exposes the state of review rights.
   584  type RequiredPullRequestReviews struct {
   585  	DismissalRestrictions        *DismissalRestrictions `json:"dismissal_restrictions"`
   586  	DismissStaleReviews          bool                   `json:"dismiss_stale_reviews"`
   587  	RequireCodeOwnerReviews      bool                   `json:"require_code_owner_reviews"`
   588  	RequiredApprovingReviewCount int                    `json:"required_approving_review_count"`
   589  	BypassRestrictions           *BypassRestrictions    `json:"bypass_pull_request_allowances"`
   590  }
   591  
   592  // DismissalRestrictions exposes restrictions in github for an activity to people/teams.
   593  type DismissalRestrictions struct {
   594  	Users []User `json:"users,omitempty"`
   595  	Teams []Team `json:"teams,omitempty"`
   596  }
   597  
   598  // BypassRestrictions exposes bypass option in github for a pull request to people/teams.
   599  type BypassRestrictions struct {
   600  	Users []User `json:"users,omitempty"`
   601  	Teams []Team `json:"teams,omitempty"`
   602  }
   603  
   604  // Restrictions exposes restrictions in github for an activity to apps/people/teams.
   605  type Restrictions struct {
   606  	Apps  []App  `json:"apps,omitempty"`
   607  	Users []User `json:"users,omitempty"`
   608  	Teams []Team `json:"teams,omitempty"`
   609  }
   610  
   611  // BranchProtectionRequest represents
   612  // protections to put in place for a branch.
   613  // See also: https://developer.github.com/v3/repos/branches/#update-branch-protection
   614  type BranchProtectionRequest struct {
   615  	RequiredStatusChecks       *RequiredStatusChecks              `json:"required_status_checks"`
   616  	EnforceAdmins              *bool                              `json:"enforce_admins"`
   617  	RequiredPullRequestReviews *RequiredPullRequestReviewsRequest `json:"required_pull_request_reviews"`
   618  	Restrictions               *RestrictionsRequest               `json:"restrictions"`
   619  	RequiredLinearHistory      bool                               `json:"required_linear_history"`
   620  	AllowForcePushes           bool                               `json:"allow_force_pushes"`
   621  	AllowDeletions             bool                               `json:"allow_deletions"`
   622  }
   623  
   624  func (r BranchProtectionRequest) String() string {
   625  	bytes, err := json.Marshal(&r)
   626  	if err != nil {
   627  		return fmt.Sprintf("%#v", r)
   628  	}
   629  	return string(bytes)
   630  }
   631  
   632  // RequiredStatusChecks specifies which contexts must pass to merge.
   633  type RequiredStatusChecks struct {
   634  	Strict   bool     `json:"strict"` // PR must be up to date (include latest base branch commit).
   635  	Contexts []string `json:"contexts"`
   636  }
   637  
   638  // RequiredPullRequestReviewsRequest controls a request for review rights.
   639  type RequiredPullRequestReviewsRequest struct {
   640  	DismissalRestrictions        DismissalRestrictionsRequest `json:"dismissal_restrictions"`
   641  	DismissStaleReviews          bool                         `json:"dismiss_stale_reviews"`
   642  	RequireCodeOwnerReviews      bool                         `json:"require_code_owner_reviews"`
   643  	RequiredApprovingReviewCount int                          `json:"required_approving_review_count"`
   644  	BypassRestrictions           BypassRestrictionsRequest    `json:"bypass_pull_request_allowances"`
   645  }
   646  
   647  // DismissalRestrictionsRequest tells github to restrict an activity to people/teams.
   648  //
   649  // Use *[]string in order to distinguish unset and empty list.
   650  // This is needed by dismissal_restrictions to distinguish
   651  // do not restrict (empty object) and restrict everyone (nil user/teams list)
   652  type DismissalRestrictionsRequest struct {
   653  	// Users is a list of user logins
   654  	Users *[]string `json:"users,omitempty"`
   655  	// Teams is a list of team slugs
   656  	Teams *[]string `json:"teams,omitempty"`
   657  }
   658  
   659  // BypassRestrictionsRequest tells github to restrict PR bypass activity to people/teams.
   660  //
   661  // Use *[]string in order to distinguish unset and empty list.
   662  // This is needed by bypass_pull_request_allowances to distinguish
   663  // do not restrict (empty object) and restrict everyone (nil user/teams list)
   664  type BypassRestrictionsRequest struct {
   665  	// Users is a list of user logins
   666  	Users *[]string `json:"users,omitempty"`
   667  	// Teams is a list of team slugs
   668  	Teams *[]string `json:"teams,omitempty"`
   669  }
   670  
   671  // RestrictionsRequest tells github to restrict an activity to apps/people/teams.
   672  //
   673  // Use *[]string in order to distinguish unset and empty list.
   674  // do not restrict (empty object) and restrict everyone (nil apps/user/teams list)
   675  type RestrictionsRequest struct {
   676  	// Apps is a list of app names
   677  	Apps *[]string `json:"apps,omitempty"`
   678  	// Users is a list of user logins
   679  	Users *[]string `json:"users,omitempty"`
   680  	// Teams is a list of team slugs
   681  	Teams *[]string `json:"teams,omitempty"`
   682  }
   683  
   684  // HookConfig holds the endpoint and its secret.
   685  type HookConfig struct {
   686  	URL         string  `json:"url"`
   687  	ContentType *string `json:"content_type,omitempty"`
   688  	Secret      *string `json:"secret,omitempty"`
   689  }
   690  
   691  // Hook holds info about the webhook configuration.
   692  type Hook struct {
   693  	ID     int        `json:"id"`
   694  	Name   string     `json:"name"`
   695  	Events []string   `json:"events"`
   696  	Active bool       `json:"active"`
   697  	Config HookConfig `json:"config"`
   698  }
   699  
   700  // HookRequest can create and/or edit a webhook.
   701  //
   702  // AddEvents and RemoveEvents are only valid during an edit, and only for a repo
   703  type HookRequest struct {
   704  	Name         string      `json:"name,omitempty"` // must be web or "", only create
   705  	Active       *bool       `json:"active,omitempty"`
   706  	AddEvents    []string    `json:"add_events,omitempty"` // only repo edit
   707  	Config       *HookConfig `json:"config,omitempty"`
   708  	Events       []string    `json:"events,omitempty"`
   709  	RemoveEvents []string    `json:"remove_events,omitempty"` // only repo edit
   710  }
   711  
   712  // AllHookEvents causes github to send all events.
   713  // https://developer.github.com/v3/activity/events/types/
   714  var AllHookEvents = []string{"*"}
   715  
   716  // IssueEventAction enumerates the triggers for this
   717  // webhook payload type. See also:
   718  // https://developer.github.com/v3/activity/events/types/#issuesevent
   719  type IssueEventAction string
   720  
   721  const (
   722  	// IssueActionAssigned means assignees were added.
   723  	IssueActionAssigned IssueEventAction = "assigned"
   724  	// IssueActionUnassigned means assignees were added.
   725  	IssueActionUnassigned IssueEventAction = "unassigned"
   726  	// IssueActionLabeled means labels were added.
   727  	IssueActionLabeled IssueEventAction = "labeled"
   728  	// IssueActionUnlabeled means labels were removed.
   729  	IssueActionUnlabeled IssueEventAction = "unlabeled"
   730  	// IssueActionOpened means issue was opened/created.
   731  	IssueActionOpened IssueEventAction = "opened"
   732  	// IssueActionEdited means issue body was edited.
   733  	IssueActionEdited IssueEventAction = "edited"
   734  	// IssueActionDeleted means the issue was deleted.
   735  	IssueActionDeleted IssueEventAction = "deleted"
   736  	// IssueActionMilestoned means the milestone was added/changed.
   737  	IssueActionMilestoned IssueEventAction = "milestoned"
   738  	// IssueActionDemilestoned means a milestone was removed.
   739  	IssueActionDemilestoned IssueEventAction = "demilestoned"
   740  	// IssueActionClosed means issue was closed.
   741  	IssueActionClosed IssueEventAction = "closed"
   742  	// IssueActionReopened means issue was reopened.
   743  	IssueActionReopened IssueEventAction = "reopened"
   744  	// IssueActionPinned means the issue was pinned.
   745  	IssueActionPinned IssueEventAction = "pinned"
   746  	// IssueActionUnpinned means the issue was unpinned.
   747  	IssueActionUnpinned IssueEventAction = "unpinned"
   748  	// IssueActionTransferred means the issue was transferred to another repo.
   749  	IssueActionTransferred IssueEventAction = "transferred"
   750  	// IssueActionLocked means the issue was locked.
   751  	IssueActionLocked IssueEventAction = "locked"
   752  	// IssueActionUnlocked means the issue was unlocked.
   753  	IssueActionUnlocked IssueEventAction = "unlocked"
   754  )
   755  
   756  // IssueEvent represents an issue event from a webhook payload (not from the events API).
   757  type IssueEvent struct {
   758  	Action IssueEventAction `json:"action"`
   759  	Issue  Issue            `json:"issue"`
   760  	Repo   Repo             `json:"repository"`
   761  	// Label is specified for IssueActionLabeled and IssueActionUnlabeled events.
   762  	Label  Label `json:"label"`
   763  	Sender User  `json:"sender"`
   764  
   765  	// GUID is included in the header of the request received by GitHub.
   766  	GUID string
   767  }
   768  
   769  // ListedIssueEvent represents an issue event from the events API (not from a webhook payload).
   770  // https://developer.github.com/v3/issues/events/
   771  type ListedIssueEvent struct {
   772  	ID  int64  `json:"id,omitempty"`
   773  	URL string `json:"url,omitempty"`
   774  
   775  	// The User that generated this event.
   776  	Actor User `json:"actor"`
   777  
   778  	// This is the same as IssueEvent.Action
   779  	Event IssueEventAction `json:"event"`
   780  
   781  	CreatedAt time.Time `json:"created_at"`
   782  	Issue     Issue     `json:"issue,omitempty"`
   783  
   784  	// Only present on certain events.
   785  	Assignee          User            `json:"assignee,omitempty"`
   786  	Assigner          User            `json:"assigner,omitempty"`
   787  	CommitID          string          `json:"commit_id,omitempty"`
   788  	Milestone         Milestone       `json:"milestone,omitempty"`
   789  	Label             Label           `json:"label"`
   790  	Rename            Rename          `json:"rename,omitempty"`
   791  	LockReason        string          `json:"lock_reason,omitempty"`
   792  	ProjectCard       ProjectCard     `json:"project_card,omitempty"`
   793  	DismissedReview   DismissedReview `json:"dismissed_review,omitempty"`
   794  	RequestedReviewer User            `json:"requested_reviewer,omitempty"`
   795  	ReviewRequester   User            `json:"review_requester,omitempty"`
   796  }
   797  
   798  // Rename contains details for 'renamed' events.
   799  type Rename struct {
   800  	From string `json:"from,omitempty"`
   801  	To   string `json:"to,omitempty"`
   802  }
   803  
   804  // DismissedReview represents details for 'dismissed_review' events.
   805  type DismissedReview struct {
   806  	// State represents the state of the dismissed review.DismissedReview
   807  	// Possible values are: "commented", "approved", and "changes_requested".
   808  	State             string `json:"state,omitempty"`
   809  	ReviewID          int64  `json:"review_id,omitempty"`
   810  	DismissalMessage  string `json:"dismissal_message,omitempty"`
   811  	DismissalCommitID string `json:"dismissal_commit_id,omitempty"`
   812  }
   813  
   814  // IssueCommentEventAction enumerates the triggers for this
   815  // webhook payload type. See also:
   816  // https://developer.github.com/v3/activity/events/types/#issuecommentevent
   817  type IssueCommentEventAction string
   818  
   819  const (
   820  	// IssueCommentActionCreated means the comment was created.
   821  	IssueCommentActionCreated IssueCommentEventAction = "created"
   822  	// IssueCommentActionEdited means the comment was edited.
   823  	IssueCommentActionEdited IssueCommentEventAction = "edited"
   824  	// IssueCommentActionDeleted means the comment was deleted.
   825  	IssueCommentActionDeleted IssueCommentEventAction = "deleted"
   826  )
   827  
   828  // IssueCommentEvent is what GitHub sends us when an issue comment is changed.
   829  type IssueCommentEvent struct {
   830  	Action  IssueCommentEventAction `json:"action"`
   831  	Issue   Issue                   `json:"issue"`
   832  	Comment IssueComment            `json:"comment"`
   833  	Repo    Repo                    `json:"repository"`
   834  
   835  	// GUID is included in the header of the request received by GitHub.
   836  	GUID string
   837  }
   838  
   839  // Issue represents general info about an issue.
   840  type Issue struct {
   841  	ID          int       `json:"id"`
   842  	NodeID      string    `json:"node_id"`
   843  	User        User      `json:"user"`
   844  	Number      int       `json:"number"`
   845  	Title       string    `json:"title"`
   846  	State       string    `json:"state"`
   847  	HTMLURL     string    `json:"html_url"`
   848  	Labels      []Label   `json:"labels"`
   849  	Assignees   []User    `json:"assignees"`
   850  	Body        string    `json:"body"`
   851  	CreatedAt   time.Time `json:"created_at"`
   852  	UpdatedAt   time.Time `json:"updated_at"`
   853  	Milestone   Milestone `json:"milestone"`
   854  	StateReason string    `json:"state_reason"`
   855  
   856  	// This will be non-nil if it is a pull request.
   857  	PullRequest *struct{} `json:"pull_request,omitempty"`
   858  }
   859  
   860  // IsAssignee checks if a user is assigned to the issue.
   861  func (i Issue) IsAssignee(login string) bool {
   862  	for _, assignee := range i.Assignees {
   863  		if NormLogin(login) == NormLogin(assignee.Login) {
   864  			return true
   865  		}
   866  	}
   867  	return false
   868  }
   869  
   870  // IsAuthor checks if a user is the author of the issue.
   871  func (i Issue) IsAuthor(login string) bool {
   872  	return NormLogin(i.User.Login) == NormLogin(login)
   873  }
   874  
   875  // IsPullRequest checks if an issue is a pull request.
   876  func (i Issue) IsPullRequest() bool {
   877  	return i.PullRequest != nil
   878  }
   879  
   880  // HasLabel checks if an issue has a given label.
   881  func (i Issue) HasLabel(labelToFind string) bool {
   882  	for _, label := range i.Labels {
   883  		if strings.EqualFold(label.Name, labelToFind) {
   884  			return true
   885  		}
   886  	}
   887  	return false
   888  }
   889  
   890  // IssueComment represents general info about an issue comment.
   891  type IssueComment struct {
   892  	ID        int       `json:"id,omitempty"`
   893  	Body      string    `json:"body"`
   894  	User      User      `json:"user,omitempty"`
   895  	HTMLURL   string    `json:"html_url,omitempty"`
   896  	CreatedAt time.Time `json:"created_at,omitempty"`
   897  	UpdatedAt time.Time `json:"updated_at,omitempty"`
   898  }
   899  
   900  // StatusEvent fires whenever a git commit changes.
   901  //
   902  // See https://developer.github.com/v3/activity/events/types/#statusevent
   903  type StatusEvent struct {
   904  	SHA         string `json:"sha,omitempty"`
   905  	State       string `json:"state,omitempty"`
   906  	Description string `json:"description,omitempty"`
   907  	TargetURL   string `json:"target_url,omitempty"`
   908  	ID          int    `json:"id,omitempty"`
   909  	Name        string `json:"name,omitempty"`
   910  	Context     string `json:"context,omitempty"`
   911  	Sender      User   `json:"sender,omitempty"`
   912  	Repo        Repo   `json:"repository,omitempty"`
   913  
   914  	// GUID is included in the header of the request received by GitHub.
   915  	GUID string
   916  }
   917  
   918  // IssuesSearchResult represents the result of an issues search.
   919  type IssuesSearchResult struct {
   920  	Total  int     `json:"total_count,omitempty"`
   921  	Issues []Issue `json:"items,omitempty"`
   922  }
   923  
   924  // PushEvent is what GitHub sends us when a user pushes to a repo.
   925  type PushEvent struct {
   926  	Ref     string   `json:"ref"`
   927  	Before  string   `json:"before"`
   928  	After   string   `json:"after"`
   929  	Created bool     `json:"created"`
   930  	Deleted bool     `json:"deleted"`
   931  	Forced  bool     `json:"forced"`
   932  	Compare string   `json:"compare"`
   933  	Commits []Commit `json:"commits"`
   934  	// Pusher is the user that pushed the commit, valid in a webhook event.
   935  	Pusher User `json:"pusher"`
   936  	// Sender contains more information that Pusher about the user.
   937  	Sender User `json:"sender"`
   938  	Repo   Repo `json:"repository"`
   939  
   940  	// GUID is included in the header of the request received by GitHub.
   941  	GUID string
   942  }
   943  
   944  // Branch returns the name of the branch to which the user pushed.
   945  func (pe PushEvent) Branch() string {
   946  	ref := strings.TrimPrefix(pe.Ref, "refs/heads/") // if Ref is a branch
   947  	ref = strings.TrimPrefix(ref, "refs/tags/")      // if Ref is a tag
   948  	return ref
   949  }
   950  
   951  // Commit represents general info about a commit.
   952  type Commit struct {
   953  	ID       string   `json:"id"`
   954  	Message  string   `json:"message"`
   955  	Added    []string `json:"added"`
   956  	Removed  []string `json:"removed"`
   957  	Modified []string `json:"modified"`
   958  }
   959  
   960  // Tree represents a GitHub tree.
   961  type Tree struct {
   962  	SHA string `json:"sha,omitempty"`
   963  }
   964  
   965  // ReviewEventAction enumerates the triggers for this
   966  // webhook payload type. See also:
   967  // https://developer.github.com/v3/activity/events/types/#pullrequestreviewevent
   968  type ReviewEventAction string
   969  
   970  const (
   971  	// ReviewActionSubmitted means the review was submitted.
   972  	ReviewActionSubmitted ReviewEventAction = "submitted"
   973  	// ReviewActionEdited means the review was edited.
   974  	ReviewActionEdited ReviewEventAction = "edited"
   975  	// ReviewActionDismissed means the review was dismissed.
   976  	ReviewActionDismissed ReviewEventAction = "dismissed"
   977  )
   978  
   979  // ReviewEvent is what GitHub sends us when a PR review is changed.
   980  type ReviewEvent struct {
   981  	Action      ReviewEventAction `json:"action"`
   982  	PullRequest PullRequest       `json:"pull_request"`
   983  	Repo        Repo              `json:"repository"`
   984  	Review      Review            `json:"review"`
   985  
   986  	// GUID is included in the header of the request received by GitHub.
   987  	GUID string
   988  }
   989  
   990  // ReviewState is the state a review can be in.
   991  type ReviewState string
   992  
   993  // Possible review states.
   994  const (
   995  	ReviewStateApproved         ReviewState = "APPROVED"
   996  	ReviewStateChangesRequested ReviewState = "CHANGES_REQUESTED"
   997  	ReviewStateCommented        ReviewState = "COMMENTED"
   998  	ReviewStateDismissed        ReviewState = "DISMISSED"
   999  	ReviewStatePending          ReviewState = "PENDING"
  1000  )
  1001  
  1002  // Review describes a Pull Request review.
  1003  type Review struct {
  1004  	ID          int         `json:"id"`
  1005  	NodeID      string      `json:"node_id"`
  1006  	User        User        `json:"user"`
  1007  	Body        string      `json:"body"`
  1008  	State       ReviewState `json:"state"`
  1009  	HTMLURL     string      `json:"html_url"`
  1010  	SubmittedAt time.Time   `json:"submitted_at"`
  1011  }
  1012  
  1013  // ReviewCommentEventAction enumerates the triggers for this
  1014  // webhook payload type. See also:
  1015  // https://developer.github.com/v3/activity/events/types/#pullrequestreviewcommentevent
  1016  type ReviewCommentEventAction string
  1017  
  1018  const (
  1019  	// ReviewCommentActionCreated means the comment was created.
  1020  	ReviewCommentActionCreated ReviewCommentEventAction = "created"
  1021  	// ReviewCommentActionEdited means the comment was edited.
  1022  	ReviewCommentActionEdited ReviewCommentEventAction = "edited"
  1023  	// ReviewCommentActionDeleted means the comment was deleted.
  1024  	ReviewCommentActionDeleted ReviewCommentEventAction = "deleted"
  1025  )
  1026  
  1027  // ReviewCommentEvent is what GitHub sends us when a PR review comment is changed.
  1028  type ReviewCommentEvent struct {
  1029  	Action      ReviewCommentEventAction `json:"action"`
  1030  	PullRequest PullRequest              `json:"pull_request"`
  1031  	Repo        Repo                     `json:"repository"`
  1032  	Comment     ReviewComment            `json:"comment"`
  1033  
  1034  	// GUID is included in the header of the request received by GitHub.
  1035  	GUID string
  1036  }
  1037  
  1038  // DiffSide enumerates the sides of the diff that the PR's changes appear on.
  1039  // See also: https://docs.github.com/en/rest/reference/pulls#create-a-review-comment-for-a-pull-request
  1040  type DiffSide string
  1041  
  1042  const (
  1043  	// DiffSideLeft means left side of the diff.
  1044  	DiffSideLeft = "LEFT"
  1045  	// DiffSideRight means right side of the diff.
  1046  	DiffSideRight = "RIGHT"
  1047  )
  1048  
  1049  // ReviewComment describes a Pull Request review.
  1050  type ReviewComment struct {
  1051  	ID        int       `json:"id"`
  1052  	NodeID    string    `json:"node_id"`
  1053  	ReviewID  int       `json:"pull_request_review_id"`
  1054  	User      User      `json:"user"`
  1055  	Body      string    `json:"body"`
  1056  	Path      string    `json:"path"`
  1057  	HTMLURL   string    `json:"html_url"`
  1058  	CreatedAt time.Time `json:"created_at"`
  1059  	UpdatedAt time.Time `json:"updated_at"`
  1060  	// Position will be nil if the code has changed such that the comment is no
  1061  	// longer relevant.
  1062  	Position  *int     `json:"position,omitempty"`
  1063  	Side      DiffSide `json:"side,omitempty"`
  1064  	StartSide DiffSide `json:"start_side,omitempty"`
  1065  	Line      int      `json:"line,omitempty"`
  1066  	StartLine int      `json:"start_line,omitempty"`
  1067  }
  1068  
  1069  // ReviewAction is the action that a review can be made with.
  1070  type ReviewAction string
  1071  
  1072  // Possible review actions. Leave Action blank for a pending review.
  1073  const (
  1074  	Approve        ReviewAction = "APPROVE"
  1075  	RequestChanges ReviewAction = "REQUEST_CHANGES"
  1076  	Comment        ReviewAction = "COMMENT"
  1077  )
  1078  
  1079  // DraftReview is what we give GitHub when we want to make a PR Review. This is
  1080  // different than what we receive when we ask for a Review.
  1081  type DraftReview struct {
  1082  	// If unspecified, defaults to the most recent commit in the PR.
  1083  	CommitSHA string `json:"commit_id,omitempty"`
  1084  	Body      string `json:"body"`
  1085  	// If unspecified, defaults to PENDING.
  1086  	Action   ReviewAction         `json:"event,omitempty"`
  1087  	Comments []DraftReviewComment `json:"comments,omitempty"`
  1088  }
  1089  
  1090  // DraftReviewComment is a comment in a draft review.
  1091  type DraftReviewComment struct {
  1092  	Path string `json:"path"`
  1093  	// Position in the patch, not the line number in the file.
  1094  	Position int    `json:"position"`
  1095  	Body     string `json:"body"`
  1096  }
  1097  
  1098  // Content is some base64 encoded github file content
  1099  // It include selected fields available in content record returned by
  1100  // GH "GET" method. See also:
  1101  // https://docs.github.com/en/free-pro-team@latest/rest/reference/repos#get-repository-content
  1102  type Content struct {
  1103  	Content string `json:"content"`
  1104  	SHA     string `json:"sha"`
  1105  }
  1106  
  1107  const (
  1108  	// PrivacySecret memberships are only visible to other team members.
  1109  	PrivacySecret = "secret"
  1110  	// PrivacyClosed memberships are visible to org members.
  1111  	PrivacyClosed = "closed"
  1112  )
  1113  
  1114  // Team is a github organizational team
  1115  type Team struct {
  1116  	ID           int            `json:"id,omitempty"`
  1117  	Name         string         `json:"name"`
  1118  	Slug         string         `json:"slug"`
  1119  	Description  string         `json:"description,omitempty"`
  1120  	Privacy      string         `json:"privacy,omitempty"`
  1121  	Parent       *Team          `json:"parent,omitempty"`         // Only present in responses
  1122  	ParentTeamID *int           `json:"parent_team_id,omitempty"` // Only valid in creates/edits
  1123  	Permission   TeamPermission `json:"permission,omitempty"`
  1124  }
  1125  
  1126  // TeamMember is a member of an organizational team
  1127  type TeamMember struct {
  1128  	Login string `json:"login"`
  1129  }
  1130  
  1131  const (
  1132  	// RoleAll lists both members and admins
  1133  	RoleAll = "all"
  1134  	// RoleAdmin specifies the user is an org admin, or lists only admins
  1135  	RoleAdmin = "admin"
  1136  	// RoleMaintainer specifies the user is a team maintainer, or lists only maintainers
  1137  	RoleMaintainer = "maintainer"
  1138  	// RoleMember specifies the user is a regular user, or only lists regular users
  1139  	RoleMember = "member"
  1140  	// StatePending specifies the user has an invitation to the org/team.
  1141  	StatePending = "pending"
  1142  	// StateActive specifies the user's membership is active.
  1143  	StateActive = "active"
  1144  )
  1145  
  1146  // Membership specifies the role and state details for an org and/or team.
  1147  type Membership struct {
  1148  	// admin or member
  1149  	Role string `json:"role"`
  1150  	// pending or active
  1151  	State string `json:"state,omitempty"`
  1152  }
  1153  
  1154  // Organization stores metadata information about an organization
  1155  type Organization struct {
  1156  	// Login has the same meaning as Name, but it's more reliable to use as Name can sometimes be empty,
  1157  	// see https://developer.github.com/v3/orgs/#list-organizations
  1158  	Login  string `json:"login"`
  1159  	Id     int    `json:"id"`
  1160  	NodeId string `json:"node_id"`
  1161  	// BillingEmail holds private billing address
  1162  	BillingEmail string `json:"billing_email"`
  1163  	Company      string `json:"company"`
  1164  	// Email is publicly visible
  1165  	Email                        string `json:"email"`
  1166  	Location                     string `json:"location"`
  1167  	Name                         string `json:"name"`
  1168  	Description                  string `json:"description"`
  1169  	HasOrganizationProjects      bool   `json:"has_organization_projects"`
  1170  	HasRepositoryProjects        bool   `json:"has_repository_projects"`
  1171  	DefaultRepositoryPermission  string `json:"default_repository_permission"`
  1172  	MembersCanCreateRepositories bool   `json:"members_can_create_repositories"`
  1173  }
  1174  
  1175  // OrgMembership contains Membership fields for user membership in an org.
  1176  type OrgMembership struct {
  1177  	Membership
  1178  }
  1179  
  1180  // TeamMembership contains Membership fields for user membership on a team.
  1181  type TeamMembership struct {
  1182  	Membership
  1183  }
  1184  
  1185  // OrgInvitation contains Login and other details about the invitation.
  1186  type OrgInvitation struct {
  1187  	TeamMember
  1188  	Email   string     `json:"email"`
  1189  	Inviter TeamMember `json:"inviter"`
  1190  }
  1191  
  1192  // UserRepoInvitation is returned by repo invitation obtained by user.
  1193  type UserRepoInvitation struct {
  1194  	InvitationID int                 `json:"id"`
  1195  	Repository   *Repo               `json:"repository,omitempty"`
  1196  	Permission   RepoPermissionLevel `json:"permissions"`
  1197  }
  1198  
  1199  // OrgPermissionLevel is admin, and member
  1200  //
  1201  // See https://docs.github.com/en/rest/reference/orgs#set-organization-membership-for-a-user
  1202  type OrgPermissionLevel string
  1203  
  1204  const (
  1205  	// OrgMember is the member
  1206  	OrgMember OrgPermissionLevel = "member"
  1207  	// OrgAdmin manages the org
  1208  	OrgAdmin OrgPermissionLevel = "admin"
  1209  	// OrgUnaffiliated probably means user not a member yet, this was returned
  1210  	// from an org invitation, had to add it so unmarshal doesn't crash
  1211  	OrgUnaffiliated OrgPermissionLevel = "unaffiliated"
  1212  	// OrgReinstate means the user was removed and the invited again before n months have passed.
  1213  	// More info here: https://docs.github.com/en/github-ae@latest/organizations/managing-membership-in-your-organization/reinstating-a-former-member-of-your-organization
  1214  	OrgReinstate OrgPermissionLevel = "reinstate"
  1215  )
  1216  
  1217  var orgPermissionLevels = map[OrgPermissionLevel]bool{
  1218  	OrgMember:       true,
  1219  	OrgAdmin:        true,
  1220  	OrgUnaffiliated: true,
  1221  	OrgReinstate:    true,
  1222  }
  1223  
  1224  // MarshalText returns the byte representation of the permission
  1225  func (l OrgPermissionLevel) MarshalText() ([]byte, error) {
  1226  	return []byte(l), nil
  1227  }
  1228  
  1229  // UnmarshalText validates the text is a valid string
  1230  func (l *OrgPermissionLevel) UnmarshalText(text []byte) error {
  1231  	v := OrgPermissionLevel(text)
  1232  	if _, ok := orgPermissionLevels[v]; !ok {
  1233  		return fmt.Errorf("bad org permission: %s not in %v", v, orgPermissionLevels)
  1234  	}
  1235  	*l = v
  1236  	return nil
  1237  }
  1238  
  1239  // UserOrganization contains info consumed by UserOrgInvitation.
  1240  type UserOrganization struct {
  1241  	// Login is the name of org
  1242  	Login string `json:"login"`
  1243  }
  1244  
  1245  // UserOrgInvitation is returned by org invitation obtained by user.
  1246  type UserOrgInvitation struct {
  1247  	State string             `json:"state"`
  1248  	Role  OrgPermissionLevel `json:"role"`
  1249  	Org   UserOrganization   `json:"organization"`
  1250  }
  1251  
  1252  // GenericCommentEventAction coerces multiple actions into its generic equivalent.
  1253  type GenericCommentEventAction string
  1254  
  1255  // Comments indicate values that are coerced to the specified value.
  1256  const (
  1257  	// GenericCommentActionCreated means something was created/opened/submitted
  1258  	GenericCommentActionCreated GenericCommentEventAction = "created" // "opened", "submitted"
  1259  	// GenericCommentActionEdited means something was edited.
  1260  	GenericCommentActionEdited GenericCommentEventAction = "edited"
  1261  	// GenericCommentActionDeleted means something was deleted/dismissed.
  1262  	GenericCommentActionDeleted GenericCommentEventAction = "deleted" // "dismissed"
  1263  )
  1264  
  1265  // GeneralizeCommentAction normalizes the action string to a GenericCommentEventAction or returns ""
  1266  // if the action is unrelated to the comment text. (For example a PR 'label' action.)
  1267  func GeneralizeCommentAction(action string) GenericCommentEventAction {
  1268  	switch action {
  1269  	case "created", "opened", "submitted":
  1270  		return GenericCommentActionCreated
  1271  	case "edited":
  1272  		return GenericCommentActionEdited
  1273  	case "deleted", "dismissed":
  1274  		return GenericCommentActionDeleted
  1275  	}
  1276  	// The action is not related to the text body.
  1277  	return ""
  1278  }
  1279  
  1280  // GenericCommentEvent is a fake event type that is instantiated for any github event that contains
  1281  // comment like content.
  1282  // The specific events that are also handled as GenericCommentEvents are:
  1283  // - issue_comment events
  1284  // - pull_request_review events
  1285  // - pull_request_review_comment events
  1286  // - pull_request events with action in ["opened", "edited"]
  1287  // - issue events with action in ["opened", "edited"]
  1288  //
  1289  // Issue and PR "closed" events are not coerced to the "deleted" Action and do not trigger
  1290  // a GenericCommentEvent because these events don't actually remove the comment content from GH.
  1291  type GenericCommentEvent struct {
  1292  	ID           int    `json:"id"`
  1293  	NodeID       string `json:"node_id"`
  1294  	CommentID    *int
  1295  	IsPR         bool
  1296  	Action       GenericCommentEventAction
  1297  	Body         string
  1298  	HTMLURL      string
  1299  	Number       int
  1300  	Repo         Repo
  1301  	User         User
  1302  	IssueAuthor  User
  1303  	Assignees    []User
  1304  	IssueState   string
  1305  	IssueTitle   string
  1306  	IssueBody    string
  1307  	IssueHTMLURL string
  1308  	GUID         string
  1309  }
  1310  
  1311  // Milestone is a milestone defined on a github repository
  1312  type Milestone struct {
  1313  	Title  string `json:"title"`
  1314  	Number int    `json:"number"`
  1315  	State  string `json:"state"`
  1316  }
  1317  
  1318  // RepositoryCommit represents a commit in a repo.
  1319  // Note that it's wrapping a GitCommit, so author/committer information is in two places,
  1320  // but contain different details about them: in RepositoryCommit "github details", in GitCommit - "git details".
  1321  // Get single commit also use it, see: https://developer.github.com/v3/repos/commits/#get-a-single-commit.
  1322  type RepositoryCommit struct {
  1323  	NodeID      string      `json:"node_id,omitempty"`
  1324  	SHA         string      `json:"sha,omitempty"`
  1325  	Commit      GitCommit   `json:"commit,omitempty"`
  1326  	Author      User        `json:"author,omitempty"`
  1327  	Committer   User        `json:"committer,omitempty"`
  1328  	Parents     []GitCommit `json:"parents,omitempty"`
  1329  	HTMLURL     string      `json:"html_url,omitempty"`
  1330  	URL         string      `json:"url,omitempty"`
  1331  	CommentsURL string      `json:"comments_url,omitempty"`
  1332  
  1333  	// Details about how many changes were made in this commit. Only filled in during GetCommit!
  1334  	Stats *CommitStats `json:"stats,omitempty"`
  1335  	// Details about which files, and how this commit touched. Only filled in during GetCommit!
  1336  	Files []CommitFile `json:"files,omitempty"`
  1337  }
  1338  
  1339  // CommitStats represents the number of additions / deletions from a file in a given RepositoryCommit or GistCommit.
  1340  type CommitStats struct {
  1341  	Additions int `json:"additions,omitempty"`
  1342  	Deletions int `json:"deletions,omitempty"`
  1343  	Total     int `json:"total,omitempty"`
  1344  }
  1345  
  1346  // CommitFile represents a file modified in a commit.
  1347  type CommitFile struct {
  1348  	SHA              string `json:"sha,omitempty"`
  1349  	Filename         string `json:"filename,omitempty"`
  1350  	Additions        int    `json:"additions,omitempty"`
  1351  	Deletions        int    `json:"deletions,omitempty"`
  1352  	Changes          int    `json:"changes,omitempty"`
  1353  	Status           string `json:"status,omitempty"`
  1354  	Patch            string `json:"patch,omitempty"`
  1355  	BlobURL          string `json:"blob_url,omitempty"`
  1356  	RawURL           string `json:"raw_url,omitempty"`
  1357  	ContentsURL      string `json:"contents_url,omitempty"`
  1358  	PreviousFilename string `json:"previous_filename,omitempty"`
  1359  }
  1360  
  1361  // GitCommit represents a GitHub commit.
  1362  type GitCommit struct {
  1363  	SHA          string                 `json:"sha,omitempty"`
  1364  	Author       CommitAuthor           `json:"author,omitempty"`
  1365  	Committer    CommitAuthor           `json:"committer,omitempty"`
  1366  	Message      string                 `json:"message,omitempty"`
  1367  	Tree         Tree                   `json:"tree,omitempty"`
  1368  	Parents      []GitCommit            `json:"parents,omitempty"`
  1369  	Stats        *CommitStats           `json:"stats,omitempty"`
  1370  	HTMLURL      string                 `json:"html_url,omitempty"`
  1371  	URL          string                 `json:"url,omitempty"`
  1372  	Verification *SignatureVerification `json:"verification,omitempty"`
  1373  	NodeID       string                 `json:"node_id,omitempty"`
  1374  
  1375  	// CommentCount is the number of GitHub comments on the commit. This
  1376  	// is only populated for requests that fetch GitHub data like
  1377  	// Pulls.ListCommits, Repositories.ListCommits, etc.
  1378  	CommentCount *int `json:"comment_count,omitempty"`
  1379  }
  1380  
  1381  // CommitAuthor represents the author or committer of a commit. The commit
  1382  // author may not correspond to a GitHub User.
  1383  type CommitAuthor struct {
  1384  	Date  time.Time `json:"date,omitempty"`
  1385  	Name  string    `json:"name,omitempty"`
  1386  	Email string    `json:"email,omitempty"`
  1387  
  1388  	// The following fields are only populated by Webhook events.
  1389  	Login *string `json:"username,omitempty"`
  1390  }
  1391  
  1392  // SignatureVerification represents GPG signature verification.
  1393  type SignatureVerification struct {
  1394  	Verified  bool   `json:"verified,omitempty"`
  1395  	Reason    string `json:"reason,omitempty"`
  1396  	Signature string `json:"signature,omitempty"`
  1397  	Payload   string `json:"payload,omitempty"`
  1398  }
  1399  
  1400  // Project is a github project
  1401  type Project struct {
  1402  	Name string `json:"name"`
  1403  	ID   int    `json:"id"`
  1404  }
  1405  
  1406  // ProjectColumn is a colunm in a github project
  1407  type ProjectColumn struct {
  1408  	Name string `json:"name"`
  1409  	ID   int    `json:"id"`
  1410  }
  1411  
  1412  // ProjectCard is a github project card
  1413  type ProjectCard struct {
  1414  	ID          int    `json:"id"`
  1415  	ContentID   int    `json:"content_id"`
  1416  	ContentType string `json:"content_type"`
  1417  	ContentURL  string `json:"content_url"`
  1418  }
  1419  
  1420  type CheckRunList struct {
  1421  	Total     int        `json:"total_count,omitempty"`
  1422  	CheckRuns []CheckRun `json:"check_runs,omitempty"`
  1423  }
  1424  
  1425  type CheckRun struct {
  1426  	ID           int64          `json:"id,omitempty"`
  1427  	NodeID       string         `json:"node_id,omitempty"`
  1428  	HeadSHA      string         `json:"head_sha,omitempty"`
  1429  	ExternalID   string         `json:"external_id,omitempty"`
  1430  	URL          string         `json:"url,omitempty"`
  1431  	HTMLURL      string         `json:"html_url,omitempty"`
  1432  	DetailsURL   string         `json:"details_url,omitempty"`
  1433  	Status       string         `json:"status,omitempty"`
  1434  	Conclusion   string         `json:"conclusion,omitempty"`
  1435  	StartedAt    string         `json:"started_at,omitempty"`
  1436  	CompletedAt  string         `json:"completed_at,omitempty"`
  1437  	Output       CheckRunOutput `json:"output,omitempty"`
  1438  	Name         string         `json:"name,omitempty"`
  1439  	CheckSuite   CheckSuite     `json:"check_suite,omitempty"`
  1440  	App          App            `json:"app,omitempty"`
  1441  	PullRequests []PullRequest  `json:"pull_requests,omitempty"`
  1442  }
  1443  
  1444  type CheckRunOutput struct {
  1445  	Title            string               `json:"title,omitempty"`
  1446  	Summary          string               `json:"summary,omitempty"`
  1447  	Text             string               `json:"text,omitempty"`
  1448  	AnnotationsCount int                  `json:"annotations_count,omitempty"`
  1449  	AnnotationsURL   string               `json:"annotations_url,omitempty"`
  1450  	Annotations      []CheckRunAnnotation `json:"annotations,omitempty"`
  1451  	Images           []CheckRunImage      `json:"images,omitempty"`
  1452  }
  1453  
  1454  type CheckRunAnnotation struct {
  1455  	Path            string `json:"path,omitempty"`
  1456  	StartLine       int    `json:"start_line,omitempty"`
  1457  	EndLine         int    `json:"end_line,omitempty"`
  1458  	StartColumn     int    `json:"start_column,omitempty"`
  1459  	EndColumn       int    `json:"end_column,omitempty"`
  1460  	AnnotationLevel string `json:"annotation_level,omitempty"`
  1461  	Message         string `json:"message,omitempty"`
  1462  	Title           string `json:"title,omitempty"`
  1463  	RawDetails      string `json:"raw_details,omitempty"`
  1464  }
  1465  
  1466  type CheckRunImage struct {
  1467  	Alt      string `json:"alt,omitempty"`
  1468  	ImageURL string `json:"image_url,omitempty"`
  1469  	Caption  string `json:"caption,omitempty"`
  1470  }
  1471  
  1472  type CheckSuite struct {
  1473  	ID           int64         `json:"id,omitempty"`
  1474  	NodeID       string        `json:"node_id,omitempty"`
  1475  	HeadBranch   string        `json:"head_branch,omitempty"`
  1476  	HeadSHA      string        `json:"head_sha,omitempty"`
  1477  	URL          string        `json:"url,omitempty"`
  1478  	BeforeSHA    string        `json:"before,omitempty"`
  1479  	AfterSHA     string        `json:"after,omitempty"`
  1480  	Status       string        `json:"status,omitempty"`
  1481  	Conclusion   string        `json:"conclusion,omitempty"`
  1482  	App          *App          `json:"app,omitempty"`
  1483  	Repository   *Repo         `json:"repository,omitempty"`
  1484  	PullRequests []PullRequest `json:"pull_requests,omitempty"`
  1485  
  1486  	// The following fields are only populated by Webhook events.
  1487  	HeadCommit *Commit `json:"head_commit,omitempty"`
  1488  }
  1489  
  1490  type App struct {
  1491  	ID          int64                    `json:"id,omitempty"`
  1492  	Slug        string                   `json:"slug,omitempty"`
  1493  	NodeID      string                   `json:"node_id,omitempty"`
  1494  	Owner       User                     `json:"owner,omitempty"`
  1495  	Name        string                   `json:"name,omitempty"`
  1496  	Description string                   `json:"description,omitempty"`
  1497  	ExternalURL string                   `json:"external_url,omitempty"`
  1498  	HTMLURL     string                   `json:"html_url,omitempty"`
  1499  	CreatedAt   string                   `json:"created_at,omitempty"`
  1500  	UpdatedAt   string                   `json:"updated_at,omitempty"`
  1501  	Permissions *InstallationPermissions `json:"permissions,omitempty"`
  1502  	Events      []string                 `json:"events,omitempty"`
  1503  }
  1504  
  1505  type InstallationPermissions struct {
  1506  	Administration              string `json:"administration,omitempty"`
  1507  	Blocking                    string `json:"blocking,omitempty"`
  1508  	Checks                      string `json:"checks,omitempty"`
  1509  	Contents                    string `json:"contents,omitempty"`
  1510  	ContentReferences           string `json:"content_references,omitempty"`
  1511  	Deployments                 string `json:"deployments,omitempty"`
  1512  	Emails                      string `json:"emails,omitempty"`
  1513  	Followers                   string `json:"followers,omitempty"`
  1514  	Issues                      string `json:"issues,omitempty"`
  1515  	Metadata                    string `json:"metadata,omitempty"`
  1516  	Members                     string `json:"members,omitempty"`
  1517  	OrganizationAdministration  string `json:"organization_administration,omitempty"`
  1518  	OrganizationHooks           string `json:"organization_hooks,omitempty"`
  1519  	OrganizationPlan            string `json:"organization_plan,omitempty"`
  1520  	OrganizationPreReceiveHooks string `json:"organization_pre_receive_hooks,omitempty"`
  1521  	OrganizationProjects        string `json:"organization_projects,omitempty"`
  1522  	OrganizationUserBlocking    string `json:"organization_user_blocking,omitempty"`
  1523  	Packages                    string `json:"packages,omitempty"`
  1524  	Pages                       string `json:"pages,omitempty"`
  1525  	PullRequests                string `json:"pull_requests,omitempty"`
  1526  	RepositoryHooks             string `json:"repository_hooks,omitempty"`
  1527  	RepositoryProjects          string `json:"repository_projects,omitempty"`
  1528  	RepositoryPreReceiveHooks   string `json:"repository_pre_receive_hooks,omitempty"`
  1529  	SingleFile                  string `json:"single_file,omitempty"`
  1530  	Statuses                    string `json:"statuses,omitempty"`
  1531  	TeamDiscussions             string `json:"team_discussions,omitempty"`
  1532  	VulnerabilityAlerts         string `json:"vulnerability_alerts,omitempty"`
  1533  }
  1534  
  1535  // AppInstallation represents a GitHub Apps installation.
  1536  type AppInstallation struct {
  1537  	ID                  int64                   `json:"id,omitempty"`
  1538  	AppSlug             string                  `json:"app_slug,omitempty"`
  1539  	NodeID              string                  `json:"node_id,omitempty"`
  1540  	AppID               int64                   `json:"app_id,omitempty"`
  1541  	TargetID            int64                   `json:"target_id,omitempty"`
  1542  	Account             User                    `json:"account,omitempty"`
  1543  	AccessTokensURL     string                  `json:"access_tokens_url,omitempty"`
  1544  	RepositoriesURL     string                  `json:"repositories_url,omitempty"`
  1545  	HTMLURL             string                  `json:"html_url,omitempty"`
  1546  	TargetType          string                  `json:"target_type,omitempty"`
  1547  	SingleFileName      string                  `json:"single_file_name,omitempty"`
  1548  	RepositorySelection string                  `json:"repository_selection,omitempty"`
  1549  	Events              []string                `json:"events,omitempty"`
  1550  	Permissions         InstallationPermissions `json:"permissions,omitempty"`
  1551  	CreatedAt           string                  `json:"created_at,omitempty"`
  1552  	UpdatedAt           string                  `json:"updated_at,omitempty"`
  1553  }
  1554  
  1555  // AppInstallationList represents the result of an AppInstallationList search.
  1556  type AppInstallationList struct {
  1557  	Total         int               `json:"total_count,omitempty"`
  1558  	Installations []AppInstallation `json:"installations,omitempty"`
  1559  }
  1560  
  1561  // AppInstallationToken is the response when retrieving an app installation
  1562  // token.
  1563  type AppInstallationToken struct {
  1564  	Token        string                  `json:"token,omitempty"`
  1565  	ExpiresAt    time.Time               `json:"expires_at,omitempty"`
  1566  	Permissions  InstallationPermissions `json:"permissions,omitempty"`
  1567  	Repositories []Repo                  `json:"repositories,omitempty"`
  1568  }
  1569  
  1570  // DirectoryContent contains information about a github directory.
  1571  // It include selected fields available in content records returned by
  1572  // GH "GET" method. See also:
  1573  // https://docs.github.com/en/free-pro-team@latest/rest/reference/repos#get-repository-content
  1574  type DirectoryContent struct {
  1575  	SHA  string `json:"sha"`
  1576  	Type string `json:"type"`
  1577  	Name string `json:"name"`
  1578  	Path string `json:"path"`
  1579  }
  1580  
  1581  // WorkflowRunEvent holds information about an `workflow_run` GitHub webhook event.
  1582  // see // https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#workflow_run
  1583  type WorkflowRunEvent struct {
  1584  	Action       string       `json:"action"`
  1585  	WorkflowRun  WorkflowRun  `json:"workflow_run"`
  1586  	Workflow     Workflow     `json:"workflow"`
  1587  	Repo         *Repo        `json:"repository"`
  1588  	Organization Organization `json:"organization"`
  1589  	Sender       User         `json:"sender"`
  1590  
  1591  	// GUID is included in the header of the request received by GitHub.
  1592  	GUID string
  1593  }
  1594  
  1595  type WorkflowRun struct {
  1596  	ID               int           `json:"id"`
  1597  	Name             string        `json:"name"`
  1598  	NodeID           string        `json:"node_id"`
  1599  	HeadBranch       string        `json:"head_branch"`
  1600  	HeadSha          string        `json:"head_sha"`
  1601  	RunNumber        int           `json:"run_number"`
  1602  	Event            string        `json:"event"`
  1603  	Status           string        `json:"status"`
  1604  	Conclusion       string        `json:"conclusion"`
  1605  	WorkflowID       int           `json:"workflow_id"`
  1606  	CheckSuiteID     int64         `json:"check_suite_id"`
  1607  	CheckSuiteNodeID string        `json:"check_suite_node_id"`
  1608  	URL              string        `json:"url"`
  1609  	PullRequests     []PullRequest `json:"pull_requests"`
  1610  	CreatedAt        time.Time     `json:"created_at"`
  1611  	UpdatedAt        time.Time     `json:"updated_at"`
  1612  	RunAttempt       int           `json:"run_attempt"`
  1613  	RunStartedAt     time.Time     `json:"run_started_at"`
  1614  	HeadCommit       *Commit       `json:"head_commit"`
  1615  	Repository       *Repo         `json:"repository"`
  1616  }
  1617  
  1618  type Workflow struct {
  1619  	ID        int       `json:"id"`
  1620  	NodeID    string    `json:"node_id"`
  1621  	Name      string    `json:"name"`
  1622  	Path      string    `json:"path"`
  1623  	State     string    `json:"state"`
  1624  	CreatedAt time.Time `json:"created_at"`
  1625  	UpdatedAt time.Time `json:"updated_at"`
  1626  }
  1627  
  1628  // RegistryPackageEvent holds information about an `registry_package` GitHub webhook event.
  1629  // see https://docs.github.com/en/webhooks/webhook-events-and-payloads#registry_package
  1630  type RegistryPackageEvent struct {
  1631  	Action          string          `json:"action"`
  1632  	RegistryPackage RegistryPackage `json:"registry_package"`
  1633  	Repo            *Repo           `json:"repository"`
  1634  	Organization    Organization    `json:"organization"`
  1635  	Sender          User            `json:"sender"`
  1636  
  1637  	// GUID is included in the header of the request received by GitHub.
  1638  	GUID string
  1639  }
  1640  
  1641  type RegistryPackage struct {
  1642  	ID             int            `json:"id"`
  1643  	Name           string         `json:"name"`
  1644  	Namespace      string         `json:"namespace"`
  1645  	Description    string         `json:"description"`
  1646  	Ecosystem      string         `json:"ecosystem"`
  1647  	PackageType    string         `json:"package_type"`
  1648  	HTMLURL        string         `json:"html_url"`
  1649  	CreatedAt      time.Time      `json:"created_at"`
  1650  	UpdatedAt      time.Time      `json:"updated_at"`
  1651  	Owner          User           `json:"owner"`
  1652  	Registry       Registry       `json:"registry"`
  1653  	PackageVersion PackageVersion `json:"package_version"`
  1654  }
  1655  
  1656  type Registry struct {
  1657  	AboutURL string `json:"about_url"`
  1658  	Name     string `json:"name"`
  1659  	Type     string `json:"type"`
  1660  	URL      string `json:"url"`
  1661  	Vendor   string `json:"vendor"`
  1662  }
  1663  
  1664  type PackageVersion struct {
  1665  	ID                  int               `json:"id"`
  1666  	Version             string            `json:"version"`
  1667  	Name                string            `json:"name"`
  1668  	Description         string            `json:"description"`
  1669  	Summary             string            `json:"summary"`
  1670  	Manifest            string            `json:"manifest"`
  1671  	HTMLURL             string            `json:"html_url"`
  1672  	TargetCommitish     string            `json:"target_commitish"`
  1673  	TargetOid           string            `json:"target_oid"`
  1674  	CreatedAt           time.Time         `json:"created_at"`
  1675  	UpdatedAt           time.Time         `json:"updated_at"`
  1676  	Metadata            []interface{}     `json:"metadata"`
  1677  	ContainerMetadata   ContainerMetadata `json:"container_metadata"`
  1678  	PackageFiles        []interface{}     `json:"package_files"`
  1679  	Author              User              `json:"author"`
  1680  	InstallationCommand string            `json:"installation_command"`
  1681  	PackageURL          string            `json:"package_url"`
  1682  }
  1683  
  1684  type ContainerMetadata struct {
  1685  	Tag      Tag      `json:"tag"`
  1686  	Labels   Labels   `json:"labels"`
  1687  	Manifest Manifest `json:"manifest"`
  1688  }
  1689  type Tag struct {
  1690  	Name   string `json:"name"`
  1691  	Digest string `json:"digest"`
  1692  }
  1693  
  1694  type Labels struct {
  1695  	Description string `json:"description"`
  1696  	Source      string `json:"source"`
  1697  	Revision    string `json:"revision"`
  1698  	ImageURL    string `json:"image_url"`
  1699  	Licenses    string `json:"licenses"`
  1700  }
  1701  
  1702  type Manifest struct {
  1703  	Digest    string   `json:"digest"`
  1704  	MediaType string   `json:"media_type"`
  1705  	URI       string   `json:"uri"`
  1706  	Size      int      `json:"size"`
  1707  	Config    Config   `json:"config"`
  1708  	Layers    []Layers `json:"layers"`
  1709  }
  1710  
  1711  type Config struct {
  1712  	Digest    string `json:"digest"`
  1713  	MediaType string `json:"media_type"`
  1714  	Size      int    `json:"size"`
  1715  }
  1716  
  1717  type Layers struct {
  1718  	Digest    string `json:"digest"`
  1719  	MediaType string `json:"media_type"`
  1720  	Size      int    `json:"size"`
  1721  }