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 }