diff --git a/github/actions_workflow_runs.go b/github/actions_workflow_runs.go index d55c01dcd74..122ea1d0e2b 100644 --- a/github/actions_workflow_runs.go +++ b/github/actions_workflow_runs.go @@ -112,6 +112,31 @@ type ReferencedWorkflow struct { Ref *string `json:"ref,omitempty"` } +// PendingDeployment represents the pending_deployments response. +type PendingDeployment struct { + Environment *PendingDeploymentEnvironment `json:"environment,omitempty"` + WaitTimer *int64 `json:"wait_timer,omitempty"` + WaitTimerStartedAt *Timestamp `json:"wait_timer_started_at,omitempty"` + CurrentUserCanApprove *bool `json:"current_user_can_approve,omitempty"` + Reviewers []*RequiredReviewer `json:"reviewers,omitempty"` +} + +// PendingDeploymentEnvironment represents pending deployment environment properties. +type PendingDeploymentEnvironment struct { + ID *int64 `json:"id,omitempty"` + NodeID *string `json:"node_id,omitempty"` + Name *string `json:"name,omitempty"` + URL *string `json:"url,omitempty"` + HTMLURL *string `json:"html_url,omitempty"` +} + +// ReviewCustomDeploymentProtectionRuleRequest specifies the parameters to ReviewCustomDeploymentProtectionRule. +type ReviewCustomDeploymentProtectionRuleRequest struct { + EnvironmentName string `json:"environment_name"` + State string `json:"state"` + Comment string `json:"comment"` +} + func (s *ActionsService) listWorkflowRuns(ctx context.Context, endpoint string, opts *ListWorkflowRunsOptions) (*WorkflowRuns, *Response, error) { u, err := addOptions(endpoint, opts) if err != nil { @@ -388,6 +413,28 @@ func (s *ActionsService) GetWorkflowRunUsageByID(ctx context.Context, owner, rep return workflowRunUsage, resp, nil } +// GetPendingDeployments get all deployment environments for a workflow run that are waiting for protection rules to pass. +// +// GitHub API docs: https://docs.github.com/rest/actions/workflow-runs#get-pending-deployments-for-a-workflow-run +// +//meta:operation GET /repos/{owner}/{repo}/actions/runs/{run_id}/pending_deployments +func (s *ActionsService) GetPendingDeployments(ctx context.Context, owner, repo string, runID int64) ([]*PendingDeployment, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/actions/runs/%v/pending_deployments", owner, repo, runID) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var deployments []*PendingDeployment + resp, err := s.client.Do(ctx, req, &deployments) + if err != nil { + return nil, resp, err + } + + return deployments, resp, nil +} + // PendingDeployments approve or reject pending deployments that are waiting on approval by a required reviewer. // // GitHub API docs: https://docs.github.com/rest/actions/workflow-runs#review-pending-deployments-for-a-workflow-run @@ -409,3 +456,20 @@ func (s *ActionsService) PendingDeployments(ctx context.Context, owner, repo str return deployments, resp, nil } + +// ReviewCustomDeploymentProtectionRule approves or rejects custom deployment protection rules provided by a GitHub App for a workflow run. +// +// GitHub API docs: https://docs.github.com/rest/actions/workflow-runs#review-custom-deployment-protection-rules-for-a-workflow-run +// +//meta:operation POST /repos/{owner}/{repo}/actions/runs/{run_id}/deployment_protection_rule +func (s *ActionsService) ReviewCustomDeploymentProtectionRule(ctx context.Context, owner, repo string, runID int64, request *ReviewCustomDeploymentProtectionRuleRequest) (*Response, error) { + u := fmt.Sprintf("repos/%v/%v/actions/runs/%v/deployment_protection_rule", owner, repo, runID) + + req, err := s.client.NewRequest("POST", u, request) + if err != nil { + return nil, err + } + + resp, err := s.client.Do(ctx, req, nil) + return resp, err +} diff --git a/github/actions_workflow_runs_test.go b/github/actions_workflow_runs_test.go index 8e01aa82297..48552a73d25 100644 --- a/github/actions_workflow_runs_test.go +++ b/github/actions_workflow_runs_test.go @@ -571,6 +571,112 @@ func TestActionService_DeleteWorkflowRunLogs(t *testing.T) { }) } +func TestPendingDeployment_Marshal(t *testing.T) { + testJSONMarshal(t, &PendingDeployment{}, "{}") + + u := &PendingDeployment{ + Environment: &PendingDeploymentEnvironment{ + ID: Int64(1), + NodeID: String("nid"), + Name: String("n"), + URL: String("u"), + HTMLURL: String("hu"), + }, + WaitTimer: Int64(100), + WaitTimerStartedAt: &Timestamp{referenceTime}, + CurrentUserCanApprove: Bool(false), + Reviewers: []*RequiredReviewer{ + { + Type: String("User"), + Reviewer: &User{ + Login: String("l"), + }, + }, + { + Type: String("Team"), + Reviewer: &Team{ + Name: String("n"), + }, + }, + }, + } + want := `{ + "environment": { + "id": 1, + "node_id": "nid", + "name": "n", + "url": "u", + "html_url": "hu" + }, + "wait_timer": 100, + "wait_timer_started_at": ` + referenceTimeStr + `, + "current_user_can_approve": false, + "reviewers": [ + { + "type": "User", + "reviewer": { + "login": "l" + } + }, + { + "type": "Team", + "reviewer": { + "name": "n" + } + } + ] + }` + testJSONMarshal(t, u, want) +} + +func TestActionsService_ReviewCustomDeploymentProtectionRule(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/actions/runs/9444496/deployment_protection_rule", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + + w.WriteHeader(http.StatusNoContent) + }) + + request := ReviewCustomDeploymentProtectionRuleRequest{ + EnvironmentName: "production", + State: "approved", + Comment: "Approve deployment", + } + + ctx := context.Background() + if _, err := client.Actions.ReviewCustomDeploymentProtectionRule(ctx, "o", "r", 9444496, &request); err != nil { + t.Errorf("ReviewCustomDeploymentProtectionRule returned error: %v", err) + } + + const methodName = "ReviewCustomDeploymentProtectionRule" + testBadOptions(t, methodName, func() (err error) { + _, err = client.Actions.ReviewCustomDeploymentProtectionRule(ctx, "\n", "\n", 9444496, &request) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Actions.ReviewCustomDeploymentProtectionRule(ctx, "o", "r", 9444496, &request) + }) +} + +func TestReviewCustomDeploymentProtectionRuleRequest_Marshal(t *testing.T) { + testJSONMarshal(t, &ReviewCustomDeploymentProtectionRuleRequest{}, "{}") + + r := &ReviewCustomDeploymentProtectionRuleRequest{ + EnvironmentName: "e", + State: "rejected", + Comment: "c", + } + want := `{ + "environment_name": "e", + "state": "rejected", + "comment": "c" + }` + testJSONMarshal(t, r, want) +} + func TestActionsService_GetWorkflowRunUsageByID(t *testing.T) { client, mux, _, teardown := setup() defer teardown() @@ -1298,3 +1404,121 @@ func TestActionService_PendingDeployments(t *testing.T) { return resp, err }) } + +func TestActionService_GetPendingDeployments(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/actions/runs/399444496/pending_deployments", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `[ + { + "environment": { + "id": 1, + "node_id": "nid", + "name": "n", + "url": "u", + "html_url": "hu" + }, + "wait_timer": 0, + "wait_timer_started_at": `+referenceTimeStr+`, + "current_user_can_approve": false, + "reviewers": [] + }, + { + "environment": { + "id": 2, + "node_id": "nid", + "name": "n", + "url": "u", + "html_url": "hu" + }, + "wait_timer": 13, + "wait_timer_started_at": `+referenceTimeStr+`, + "current_user_can_approve": true, + "reviewers": [ + { + "type": "User", + "reviewer": { + "login": "l" + } + }, + { + "type": "Team", + "reviewer": { + "name": "t", + "slug": "s" + } + } + ] + } + ]`) + }) + + ctx := context.Background() + deployments, _, err := client.Actions.GetPendingDeployments(ctx, "o", "r", 399444496) + if err != nil { + t.Errorf("Actions.GetPendingDeployments returned error: %v", err) + } + + want := []*PendingDeployment{ + { + Environment: &PendingDeploymentEnvironment{ + ID: Int64(1), + NodeID: String("nid"), + Name: String("n"), + URL: String("u"), + HTMLURL: String("hu"), + }, + WaitTimer: Int64(0), + WaitTimerStartedAt: &Timestamp{referenceTime}, + CurrentUserCanApprove: Bool(false), + Reviewers: []*RequiredReviewer{}, + }, + { + Environment: &PendingDeploymentEnvironment{ + ID: Int64(2), + NodeID: String("nid"), + Name: String("n"), + URL: String("u"), + HTMLURL: String("hu"), + }, + WaitTimer: Int64(13), + WaitTimerStartedAt: &Timestamp{referenceTime}, + CurrentUserCanApprove: Bool(true), + Reviewers: []*RequiredReviewer{ + { + Type: String("User"), + Reviewer: &User{ + Login: String("l"), + }, + }, + { + Type: String("Team"), + Reviewer: &Team{ + Name: String("t"), + Slug: String("s"), + }, + }, + }, + }, + } + + if !cmp.Equal(deployments, want) { + t.Errorf("Actions.GetPendingDeployments returned %+v, want %+v", deployments, want) + } + + const methodName = "GetPendingDeployments" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Actions.GetPendingDeployments(ctx, "\n", "\n", 399444496) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Actions.GetPendingDeployments(ctx, "o", "r", 399444496) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} diff --git a/github/event_types.go b/github/event_types.go index df8d9e033e2..2193d5ac712 100644 --- a/github/event_types.go +++ b/github/event_types.go @@ -225,6 +225,46 @@ type DeploymentProtectionRuleEvent struct { Installation *Installation `json:"installation,omitempty"` } +// DeploymentReviewEvent represents a deployment review event. +// The Webhook event name is "deployment_review". +// +// GitHub API docs: https://docs.github.com/webhooks-and-events/webhooks/webhook-events-and-payloads?#deployment_review +type DeploymentReviewEvent struct { + // The action performed. Possible values are: "requested", "approved", or "rejected". + Action *string `json:"action,omitempty"` + + // The following will be populated only if requested. + Requester *User `json:"requester,omitempty"` + Environment *string `json:"environment,omitempty"` + + // The following will be populated only if approved or rejected. + Approver *User `json:"approver,omitempty"` + Comment *string `json:"comment,omitempty"` + WorkflowJobRuns []*WorkflowJobRun `json:"workflow_job_runs,omitempty"` + + Enterprise *Enterprise `json:"enterprise,omitempty"` + Installation *Installation `json:"installation,omitempty"` + Organization *Organization `json:"organization,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Reviewers []*RequiredReviewer `json:"reviewers,omitempty"` + Sender *User `json:"sender,omitempty"` + Since *string `json:"since,omitempty"` + WorkflowJobRun *WorkflowJobRun `json:"workflow_job_run,omitempty"` + WorkflowRun *WorkflowRun `json:"workflow_run,omitempty"` +} + +// WorkflowJobRun represents a workflow_job_run in a GitHub DeploymentReviewEvent. +type WorkflowJobRun struct { + Conclusion *string `json:"conclusion,omitempty"` + CreatedAt *Timestamp `json:"created_at,omitempty"` + Environment *string `json:"environment,omitempty"` + HTMLURL *string `json:"html_url,omitempty"` + ID *int64 `json:"id,omitempty"` + Name *string `json:"name,omitempty"` + Status *string `json:"status,omitempty"` + UpdatedAt *Timestamp `json:"updated_at,omitempty"` +} + // DeploymentStatusEvent represents a deployment status. // The Webhook event name is "deployment_status". // diff --git a/github/event_types_test.go b/github/event_types_test.go index 79532d4916a..a9d39a21e9d 100644 --- a/github/event_types_test.go +++ b/github/event_types_test.go @@ -6391,6 +6391,604 @@ func TestDeploymentProtectionRuleEvent_Marshal(t *testing.T) { testJSONMarshal(t, u, want) } +func TestDeploymentReviewEvent_Marshal(t *testing.T) { + testJSONMarshal(t, &DeploymentReviewEvent{}, "{}") + + u := &DeploymentReviewEvent{ + Action: String("a"), + Environment: String("e"), + Requester: &User{ + AvatarURL: String("a"), + Email: String("e"), + EventsURL: String("e"), + FollowersURL: String("f"), + FollowingURL: String("f"), + GistsURL: String("g"), + GravatarID: String("g"), + HTMLURL: String("h"), + ID: Int64(1), + Login: String("l"), + Name: String("n"), + NodeID: String("n"), + OrganizationsURL: String("o"), + ReceivedEventsURL: String("r"), + ReposURL: String("r"), + SiteAdmin: Bool(false), + StarredURL: String("s"), + SubscriptionsURL: String("s"), + Type: String("User"), + URL: String("u"), + }, + Reviewers: []*RequiredReviewer{ + { + Type: String("User"), + Reviewer: &User{ + AvatarURL: String("a"), + Email: String("e"), + EventsURL: String("e"), + FollowersURL: String("f"), + FollowingURL: String("f"), + GistsURL: String("g"), + GravatarID: String("g"), + HTMLURL: String("h"), + ID: Int64(1), + Login: String("l"), + Name: String("n"), + NodeID: String("n"), + OrganizationsURL: String("o"), + ReceivedEventsURL: String("r"), + ReposURL: String("r"), + SiteAdmin: Bool(false), + StarredURL: String("s"), + SubscriptionsURL: String("s"), + Type: String("User"), + URL: String("u"), + }, + }, + { + Type: String("Team"), + Reviewer: &Team{ + ID: Int64(1), + Name: String("n"), + Slug: String("s"), + }, + }, + }, + Enterprise: &Enterprise{ + ID: Int(1), + Slug: String("s"), + Name: String("n"), + NodeID: String("nid"), + AvatarURL: String("au"), + Description: String("d"), + WebsiteURL: String("wu"), + HTMLURL: String("hu"), + CreatedAt: &Timestamp{referenceTime}, + UpdatedAt: &Timestamp{referenceTime}, + }, + Installation: &Installation{ + ID: Int64(1), + NodeID: String("nid"), + AppID: Int64(1), + AppSlug: String("as"), + TargetID: Int64(1), + Account: &User{ + Login: String("l"), + ID: Int64(1), + URL: String("u"), + AvatarURL: String("a"), + GravatarID: String("g"), + Name: String("n"), + Company: String("c"), + Blog: String("b"), + Location: String("l"), + Email: String("e"), + Hireable: Bool(true), + Bio: String("b"), + TwitterUsername: String("t"), + PublicRepos: Int(1), + Followers: Int(1), + Following: Int(1), + CreatedAt: &Timestamp{referenceTime}, + SuspendedAt: &Timestamp{referenceTime}, + }, + AccessTokensURL: String("atu"), + RepositoriesURL: String("ru"), + HTMLURL: String("hu"), + TargetType: String("tt"), + SingleFileName: String("sfn"), + RepositorySelection: String("rs"), + Events: []string{"e"}, + SingleFilePaths: []string{"s"}, + Permissions: &InstallationPermissions{ + Actions: String("a"), + Administration: String("ad"), + Checks: String("c"), + Contents: String("co"), + ContentReferences: String("cr"), + Deployments: String("d"), + Environments: String("e"), + Issues: String("i"), + Metadata: String("md"), + Members: String("m"), + OrganizationAdministration: String("oa"), + OrganizationHooks: String("oh"), + OrganizationPlan: String("op"), + OrganizationPreReceiveHooks: String("opr"), + OrganizationProjects: String("op"), + OrganizationSecrets: String("os"), + OrganizationSelfHostedRunners: String("osh"), + OrganizationUserBlocking: String("oub"), + Packages: String("pkg"), + Pages: String("pg"), + PullRequests: String("pr"), + RepositoryHooks: String("rh"), + RepositoryProjects: String("rp"), + RepositoryPreReceiveHooks: String("rprh"), + Secrets: String("s"), + SecretScanningAlerts: String("ssa"), + SecurityEvents: String("se"), + SingleFile: String("sf"), + Statuses: String("s"), + TeamDiscussions: String("td"), + VulnerabilityAlerts: String("va"), + Workflows: String("w"), + }, + CreatedAt: &Timestamp{referenceTime}, + UpdatedAt: &Timestamp{referenceTime}, + HasMultipleSingleFiles: Bool(false), + SuspendedBy: &User{ + Login: String("l"), + ID: Int64(1), + URL: String("u"), + AvatarURL: String("a"), + GravatarID: String("g"), + Name: String("n"), + Company: String("c"), + Blog: String("b"), + Location: String("l"), + Email: String("e"), + Hireable: Bool(true), + Bio: String("b"), + TwitterUsername: String("t"), + PublicRepos: Int(1), + Followers: Int(1), + Following: Int(1), + CreatedAt: &Timestamp{referenceTime}, + SuspendedAt: &Timestamp{referenceTime}, + }, + SuspendedAt: &Timestamp{referenceTime}, + }, + Organization: &Organization{ + BillingEmail: String("be"), + Blog: String("b"), + Company: String("c"), + Email: String("e"), + TwitterUsername: String("tu"), + Location: String("loc"), + Name: String("n"), + Description: String("d"), + IsVerified: Bool(true), + HasOrganizationProjects: Bool(true), + HasRepositoryProjects: Bool(true), + DefaultRepoPermission: String("drp"), + MembersCanCreateRepos: Bool(true), + MembersCanCreateInternalRepos: Bool(true), + MembersCanCreatePrivateRepos: Bool(true), + MembersCanCreatePublicRepos: Bool(false), + MembersAllowedRepositoryCreationType: String("marct"), + MembersCanCreatePages: Bool(true), + MembersCanCreatePublicPages: Bool(false), + MembersCanCreatePrivatePages: Bool(true), + }, + Repo: &Repository{ + ID: Int64(1), + URL: String("s"), + Name: String("n"), + }, + Sender: &User{ + Login: String("l"), + ID: Int64(1), + NodeID: String("n"), + URL: String("u"), + ReposURL: String("r"), + EventsURL: String("e"), + AvatarURL: String("a"), + }, + Since: String("s"), + WorkflowJobRun: &WorkflowJobRun{ + ID: Int64(1), + Conclusion: String("c"), + Environment: String("e"), + HTMLURL: String("h"), + Name: String("n"), + Status: String("s"), + CreatedAt: &Timestamp{referenceTime}, + UpdatedAt: &Timestamp{referenceTime}, + }, + WorkflowRun: &WorkflowRun{ + ID: Int64(1), + Name: String("n"), + NodeID: String("nid"), + HeadBranch: String("hb"), + HeadSHA: String("hs"), + RunNumber: Int(1), + RunAttempt: Int(1), + Event: String("e"), + Status: String("s"), + Conclusion: String("c"), + WorkflowID: Int64(1), + URL: String("u"), + HTMLURL: String("h"), + PullRequests: []*PullRequest{ + { + URL: String("u"), + ID: Int64(1), + Number: Int(1), + Head: &PullRequestBranch{ + Ref: String("r"), + SHA: String("s"), + Repo: &Repository{ + ID: Int64(1), + URL: String("s"), + Name: String("n"), + }, + }, + Base: &PullRequestBranch{ + Ref: String("r"), + SHA: String("s"), + Repo: &Repository{ + ID: Int64(1), + URL: String("u"), + Name: String("n"), + }, + }, + }, + }, + CreatedAt: &Timestamp{referenceTime}, + UpdatedAt: &Timestamp{referenceTime}, + RunStartedAt: &Timestamp{referenceTime}, + JobsURL: String("j"), + LogsURL: String("l"), + CheckSuiteURL: String("c"), + ArtifactsURL: String("a"), + CancelURL: String("c"), + RerunURL: String("r"), + PreviousAttemptURL: String("p"), + HeadCommit: &HeadCommit{ + Message: String("m"), + Author: &CommitAuthor{ + Name: String("n"), + Email: String("e"), + Login: String("l"), + }, + URL: String("u"), + Distinct: Bool(false), + SHA: String("s"), + ID: String("i"), + TreeID: String("tid"), + Timestamp: &Timestamp{referenceTime}, + Committer: &CommitAuthor{ + Name: String("n"), + Email: String("e"), + Login: String("l"), + }, + }, + WorkflowURL: String("w"), + Repository: &Repository{ + ID: Int64(1), + URL: String("u"), + Name: String("n"), + }, + HeadRepository: &Repository{ + ID: Int64(1), + URL: String("u"), + Name: String("n"), + }, + }, + } + + want := `{ + "action": "a", + "requester": { + "login": "l", + "id": 1, + "node_id": "n", + "avatar_url": "a", + "url": "u", + "html_url": "h", + "followers_url": "f", + "following_url": "f", + "gists_url": "g", + "starred_url": "s", + "subscriptions_url": "s", + "organizations_url": "o", + "repos_url": "r", + "events_url": "e", + "received_events_url": "r", + "type": "User", + "site_admin": false, + "name": "n", + "email": "e", + "gravatar_id": "g" + }, + "reviewers": [ + { + "type": "User", + "reviewer": { + "login": "l", + "id": 1, + "node_id": "n", + "avatar_url": "a", + "url": "u", + "html_url": "h", + "followers_url": "f", + "following_url": "f", + "gists_url": "g", + "starred_url": "s", + "subscriptions_url": "s", + "organizations_url": "o", + "repos_url": "r", + "events_url": "e", + "received_events_url": "r", + "type": "User", + "site_admin": false, + "name": "n", + "email": "e", + "gravatar_id": "g" + } + }, + { + "type": "Team", + "reviewer": { + "id": 1, + "name": "n", + "slug": "s" + } + } + ], + "repository": { + "id": 1, + "name": "n", + "url": "s" + }, + "organization": { + "name": "n", + "company": "c", + "blog": "b", + "location": "loc", + "email": "e", + "twitter_username": "tu", + "description": "d", + "billing_email": "be", + "is_verified": true, + "has_organization_projects": true, + "has_repository_projects": true, + "default_repository_permission": "drp", + "members_can_create_repositories": true, + "members_can_create_public_repositories": false, + "members_can_create_private_repositories": true, + "members_can_create_internal_repositories": true, + "members_allowed_repository_creation_type": "marct", + "members_can_create_pages": true, + "members_can_create_public_pages": false, + "members_can_create_private_pages": true + }, + "environment": "e", + "enterprise": { + "id": 1, + "slug": "s", + "name": "n", + "node_id": "nid", + "avatar_url": "au", + "description": "d", + "website_url": "wu", + "html_url": "hu", + "created_at": ` + referenceTimeStr + `, + "updated_at": ` + referenceTimeStr + ` + }, + "sender": { + "login": "l", + "id": 1, + "node_id": "n", + "avatar_url": "a", + "url": "u", + "events_url": "e", + "repos_url": "r" + }, + "installation": { + "id": 1, + "node_id": "nid", + "app_id": 1, + "app_slug": "as", + "target_id": 1, + "account": { + "login": "l", + "id": 1, + "avatar_url": "a", + "gravatar_id": "g", + "name": "n", + "company": "c", + "blog": "b", + "location": "l", + "email": "e", + "hireable": true, + "bio": "b", + "twitter_username": "t", + "public_repos": 1, + "followers": 1, + "following": 1, + "created_at": ` + referenceTimeStr + `, + "suspended_at": ` + referenceTimeStr + `, + "url": "u" + }, + "access_tokens_url": "atu", + "repositories_url": "ru", + "html_url": "hu", + "target_type": "tt", + "single_file_name": "sfn", + "repository_selection": "rs", + "events": [ + "e" + ], + "single_file_paths": [ + "s" + ], + "permissions": { + "actions": "a", + "administration": "ad", + "checks": "c", + "contents": "co", + "content_references": "cr", + "deployments": "d", + "environments": "e", + "issues": "i", + "metadata": "md", + "members": "m", + "organization_administration": "oa", + "organization_hooks": "oh", + "organization_plan": "op", + "organization_pre_receive_hooks": "opr", + "organization_projects": "op", + "organization_secrets": "os", + "organization_self_hosted_runners": "osh", + "organization_user_blocking": "oub", + "packages": "pkg", + "pages": "pg", + "pull_requests": "pr", + "repository_hooks": "rh", + "repository_projects": "rp", + "repository_pre_receive_hooks": "rprh", + "secrets": "s", + "secret_scanning_alerts": "ssa", + "security_events": "se", + "single_file": "sf", + "statuses": "s", + "team_discussions": "td", + "vulnerability_alerts": "va", + "workflows": "w" + }, + "created_at": ` + referenceTimeStr + `, + "updated_at": ` + referenceTimeStr + `, + "has_multiple_single_files": false, + "suspended_by": { + "login": "l", + "id": 1, + "avatar_url": "a", + "gravatar_id": "g", + "name": "n", + "company": "c", + "blog": "b", + "location": "l", + "email": "e", + "hireable": true, + "bio": "b", + "twitter_username": "t", + "public_repos": 1, + "followers": 1, + "following": 1, + "created_at": ` + referenceTimeStr + `, + "suspended_at": ` + referenceTimeStr + `, + "url": "u" + }, + "suspended_at": ` + referenceTimeStr + ` + }, + "since": "s", + "workflow_job_run": { + "conclusion": "c", + "created_at": "2006-01-02T15:04:05Z", + "environment": "e", + "html_url": "h", + "id": 1, + "name": "n", + "status": "s", + "updated_at": "2006-01-02T15:04:05Z" + }, + "workflow_run": { + "id": 1, + "name": "n", + "node_id": "nid", + "head_branch": "hb", + "head_sha": "hs", + "run_number": 1, + "run_attempt": 1, + "event": "e", + "status": "s", + "conclusion": "c", + "workflow_id": 1, + "url": "u", + "html_url": "h", + "pull_requests": [ + { + "id": 1, + "number": 1, + "url": "u", + "head": { + "ref": "r", + "sha": "s", + "repo": { + "id": 1, + "name": "n", + "url": "s" + } + }, + "base": { + "ref": "r", + "sha": "s", + "repo": { + "id": 1, + "name": "n", + "url": "u" + } + } + } + ], + "created_at": ` + referenceTimeStr + `, + "updated_at": ` + referenceTimeStr + `, + "run_started_at": ` + referenceTimeStr + `, + "jobs_url": "j", + "logs_url": "l", + "check_suite_url": "c", + "artifacts_url": "a", + "cancel_url": "c", + "rerun_url": "r", + "previous_attempt_url": "p", + "head_commit": { + "message": "m", + "author": { + "name": "n", + "email": "e", + "username": "l" + }, + "url": "u", + "distinct": false, + "sha": "s", + "id": "i", + "tree_id": "tid", + "timestamp": ` + referenceTimeStr + `, + "committer": { + "name": "n", + "email": "e", + "username": "l" + } + }, + "workflow_url": "w", + "repository": { + "id": 1, + "name": "n", + "url": "u" + }, + "head_repository": { + "id": 1, + "name": "n", + "url": "u" + } + } + }` + + testJSONMarshal(t, u, want) +} + func TestDeploymentStatusEvent_Marshal(t *testing.T) { testJSONMarshal(t, &DeploymentStatusEvent{}, "{}") diff --git a/github/github-accessors.go b/github/github-accessors.go index 10096e44f21..08abe6e9500 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -5886,6 +5886,110 @@ func (d *DeploymentRequest) GetTransientEnvironment() bool { return *d.TransientEnvironment } +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (d *DeploymentReviewEvent) GetAction() string { + if d == nil || d.Action == nil { + return "" + } + return *d.Action +} + +// GetApprover returns the Approver field. +func (d *DeploymentReviewEvent) GetApprover() *User { + if d == nil { + return nil + } + return d.Approver +} + +// GetComment returns the Comment field if it's non-nil, zero value otherwise. +func (d *DeploymentReviewEvent) GetComment() string { + if d == nil || d.Comment == nil { + return "" + } + return *d.Comment +} + +// GetEnterprise returns the Enterprise field. +func (d *DeploymentReviewEvent) GetEnterprise() *Enterprise { + if d == nil { + return nil + } + return d.Enterprise +} + +// GetEnvironment returns the Environment field if it's non-nil, zero value otherwise. +func (d *DeploymentReviewEvent) GetEnvironment() string { + if d == nil || d.Environment == nil { + return "" + } + return *d.Environment +} + +// GetInstallation returns the Installation field. +func (d *DeploymentReviewEvent) GetInstallation() *Installation { + if d == nil { + return nil + } + return d.Installation +} + +// GetOrganization returns the Organization field. +func (d *DeploymentReviewEvent) GetOrganization() *Organization { + if d == nil { + return nil + } + return d.Organization +} + +// GetRepo returns the Repo field. +func (d *DeploymentReviewEvent) GetRepo() *Repository { + if d == nil { + return nil + } + return d.Repo +} + +// GetRequester returns the Requester field. +func (d *DeploymentReviewEvent) GetRequester() *User { + if d == nil { + return nil + } + return d.Requester +} + +// GetSender returns the Sender field. +func (d *DeploymentReviewEvent) GetSender() *User { + if d == nil { + return nil + } + return d.Sender +} + +// GetSince returns the Since field if it's non-nil, zero value otherwise. +func (d *DeploymentReviewEvent) GetSince() string { + if d == nil || d.Since == nil { + return "" + } + return *d.Since +} + +// GetWorkflowJobRun returns the WorkflowJobRun field. +func (d *DeploymentReviewEvent) GetWorkflowJobRun() *WorkflowJobRun { + if d == nil { + return nil + } + return d.WorkflowJobRun +} + +// GetWorkflowRun returns the WorkflowRun field. +func (d *DeploymentReviewEvent) GetWorkflowRun() *WorkflowRun { + if d == nil { + return nil + } + return d.WorkflowRun +} + // GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. func (d *DeploymentStatus) GetCreatedAt() Timestamp { if d == nil || d.CreatedAt == nil { @@ -14390,6 +14494,78 @@ func (p *PagesUpdate) GetSource() *PagesSource { return p.Source } +// GetCurrentUserCanApprove returns the CurrentUserCanApprove field if it's non-nil, zero value otherwise. +func (p *PendingDeployment) GetCurrentUserCanApprove() bool { + if p == nil || p.CurrentUserCanApprove == nil { + return false + } + return *p.CurrentUserCanApprove +} + +// GetEnvironment returns the Environment field. +func (p *PendingDeployment) GetEnvironment() *PendingDeploymentEnvironment { + if p == nil { + return nil + } + return p.Environment +} + +// GetWaitTimer returns the WaitTimer field if it's non-nil, zero value otherwise. +func (p *PendingDeployment) GetWaitTimer() int64 { + if p == nil || p.WaitTimer == nil { + return 0 + } + return *p.WaitTimer +} + +// GetWaitTimerStartedAt returns the WaitTimerStartedAt field if it's non-nil, zero value otherwise. +func (p *PendingDeployment) GetWaitTimerStartedAt() Timestamp { + if p == nil || p.WaitTimerStartedAt == nil { + return Timestamp{} + } + return *p.WaitTimerStartedAt +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (p *PendingDeploymentEnvironment) GetHTMLURL() string { + if p == nil || p.HTMLURL == nil { + return "" + } + return *p.HTMLURL +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (p *PendingDeploymentEnvironment) GetID() int64 { + if p == nil || p.ID == nil { + return 0 + } + return *p.ID +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (p *PendingDeploymentEnvironment) GetName() string { + if p == nil || p.Name == nil { + return "" + } + return *p.Name +} + +// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. +func (p *PendingDeploymentEnvironment) GetNodeID() string { + if p == nil || p.NodeID == nil { + return "" + } + return *p.NodeID +} + +// GetURL returns the URL field if it's non-nil, zero value otherwise. +func (p *PendingDeploymentEnvironment) GetURL() string { + if p == nil || p.URL == nil { + return "" + } + return *p.URL +} + // GetAccessGrantedAt returns the AccessGrantedAt field if it's non-nil, zero value otherwise. func (p *PersonalAccessToken) GetAccessGrantedAt() Timestamp { if p == nil || p.AccessGrantedAt == nil { @@ -25326,6 +25502,70 @@ func (w *WorkflowJobEvent) GetWorkflowJob() *WorkflowJob { return w.WorkflowJob } +// GetConclusion returns the Conclusion field if it's non-nil, zero value otherwise. +func (w *WorkflowJobRun) GetConclusion() string { + if w == nil || w.Conclusion == nil { + return "" + } + return *w.Conclusion +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (w *WorkflowJobRun) GetCreatedAt() Timestamp { + if w == nil || w.CreatedAt == nil { + return Timestamp{} + } + return *w.CreatedAt +} + +// GetEnvironment returns the Environment field if it's non-nil, zero value otherwise. +func (w *WorkflowJobRun) GetEnvironment() string { + if w == nil || w.Environment == nil { + return "" + } + return *w.Environment +} + +// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise. +func (w *WorkflowJobRun) GetHTMLURL() string { + if w == nil || w.HTMLURL == nil { + return "" + } + return *w.HTMLURL +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (w *WorkflowJobRun) GetID() int64 { + if w == nil || w.ID == nil { + return 0 + } + return *w.ID +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (w *WorkflowJobRun) GetName() string { + if w == nil || w.Name == nil { + return "" + } + return *w.Name +} + +// GetStatus returns the Status field if it's non-nil, zero value otherwise. +func (w *WorkflowJobRun) GetStatus() string { + if w == nil || w.Status == nil { + return "" + } + return *w.Status +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (w *WorkflowJobRun) GetUpdatedAt() Timestamp { + if w == nil || w.UpdatedAt == nil { + return Timestamp{} + } + return *w.UpdatedAt +} + // GetActor returns the Actor field. func (w *WorkflowRun) GetActor() *User { if w == nil { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index aa694fd58e1..79ba25f048a 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -6887,6 +6887,109 @@ func TestDeploymentRequest_GetTransientEnvironment(tt *testing.T) { d.GetTransientEnvironment() } +func TestDeploymentReviewEvent_GetAction(tt *testing.T) { + var zeroValue string + d := &DeploymentReviewEvent{Action: &zeroValue} + d.GetAction() + d = &DeploymentReviewEvent{} + d.GetAction() + d = nil + d.GetAction() +} + +func TestDeploymentReviewEvent_GetApprover(tt *testing.T) { + d := &DeploymentReviewEvent{} + d.GetApprover() + d = nil + d.GetApprover() +} + +func TestDeploymentReviewEvent_GetComment(tt *testing.T) { + var zeroValue string + d := &DeploymentReviewEvent{Comment: &zeroValue} + d.GetComment() + d = &DeploymentReviewEvent{} + d.GetComment() + d = nil + d.GetComment() +} + +func TestDeploymentReviewEvent_GetEnterprise(tt *testing.T) { + d := &DeploymentReviewEvent{} + d.GetEnterprise() + d = nil + d.GetEnterprise() +} + +func TestDeploymentReviewEvent_GetEnvironment(tt *testing.T) { + var zeroValue string + d := &DeploymentReviewEvent{Environment: &zeroValue} + d.GetEnvironment() + d = &DeploymentReviewEvent{} + d.GetEnvironment() + d = nil + d.GetEnvironment() +} + +func TestDeploymentReviewEvent_GetInstallation(tt *testing.T) { + d := &DeploymentReviewEvent{} + d.GetInstallation() + d = nil + d.GetInstallation() +} + +func TestDeploymentReviewEvent_GetOrganization(tt *testing.T) { + d := &DeploymentReviewEvent{} + d.GetOrganization() + d = nil + d.GetOrganization() +} + +func TestDeploymentReviewEvent_GetRepo(tt *testing.T) { + d := &DeploymentReviewEvent{} + d.GetRepo() + d = nil + d.GetRepo() +} + +func TestDeploymentReviewEvent_GetRequester(tt *testing.T) { + d := &DeploymentReviewEvent{} + d.GetRequester() + d = nil + d.GetRequester() +} + +func TestDeploymentReviewEvent_GetSender(tt *testing.T) { + d := &DeploymentReviewEvent{} + d.GetSender() + d = nil + d.GetSender() +} + +func TestDeploymentReviewEvent_GetSince(tt *testing.T) { + var zeroValue string + d := &DeploymentReviewEvent{Since: &zeroValue} + d.GetSince() + d = &DeploymentReviewEvent{} + d.GetSince() + d = nil + d.GetSince() +} + +func TestDeploymentReviewEvent_GetWorkflowJobRun(tt *testing.T) { + d := &DeploymentReviewEvent{} + d.GetWorkflowJobRun() + d = nil + d.GetWorkflowJobRun() +} + +func TestDeploymentReviewEvent_GetWorkflowRun(tt *testing.T) { + d := &DeploymentReviewEvent{} + d.GetWorkflowRun() + d = nil + d.GetWorkflowRun() +} + func TestDeploymentStatus_GetCreatedAt(tt *testing.T) { var zeroValue Timestamp d := &DeploymentStatus{CreatedAt: &zeroValue} @@ -16836,6 +16939,93 @@ func TestPagesUpdate_GetSource(tt *testing.T) { p.GetSource() } +func TestPendingDeployment_GetCurrentUserCanApprove(tt *testing.T) { + var zeroValue bool + p := &PendingDeployment{CurrentUserCanApprove: &zeroValue} + p.GetCurrentUserCanApprove() + p = &PendingDeployment{} + p.GetCurrentUserCanApprove() + p = nil + p.GetCurrentUserCanApprove() +} + +func TestPendingDeployment_GetEnvironment(tt *testing.T) { + p := &PendingDeployment{} + p.GetEnvironment() + p = nil + p.GetEnvironment() +} + +func TestPendingDeployment_GetWaitTimer(tt *testing.T) { + var zeroValue int64 + p := &PendingDeployment{WaitTimer: &zeroValue} + p.GetWaitTimer() + p = &PendingDeployment{} + p.GetWaitTimer() + p = nil + p.GetWaitTimer() +} + +func TestPendingDeployment_GetWaitTimerStartedAt(tt *testing.T) { + var zeroValue Timestamp + p := &PendingDeployment{WaitTimerStartedAt: &zeroValue} + p.GetWaitTimerStartedAt() + p = &PendingDeployment{} + p.GetWaitTimerStartedAt() + p = nil + p.GetWaitTimerStartedAt() +} + +func TestPendingDeploymentEnvironment_GetHTMLURL(tt *testing.T) { + var zeroValue string + p := &PendingDeploymentEnvironment{HTMLURL: &zeroValue} + p.GetHTMLURL() + p = &PendingDeploymentEnvironment{} + p.GetHTMLURL() + p = nil + p.GetHTMLURL() +} + +func TestPendingDeploymentEnvironment_GetID(tt *testing.T) { + var zeroValue int64 + p := &PendingDeploymentEnvironment{ID: &zeroValue} + p.GetID() + p = &PendingDeploymentEnvironment{} + p.GetID() + p = nil + p.GetID() +} + +func TestPendingDeploymentEnvironment_GetName(tt *testing.T) { + var zeroValue string + p := &PendingDeploymentEnvironment{Name: &zeroValue} + p.GetName() + p = &PendingDeploymentEnvironment{} + p.GetName() + p = nil + p.GetName() +} + +func TestPendingDeploymentEnvironment_GetNodeID(tt *testing.T) { + var zeroValue string + p := &PendingDeploymentEnvironment{NodeID: &zeroValue} + p.GetNodeID() + p = &PendingDeploymentEnvironment{} + p.GetNodeID() + p = nil + p.GetNodeID() +} + +func TestPendingDeploymentEnvironment_GetURL(tt *testing.T) { + var zeroValue string + p := &PendingDeploymentEnvironment{URL: &zeroValue} + p.GetURL() + p = &PendingDeploymentEnvironment{} + p.GetURL() + p = nil + p.GetURL() +} + func TestPersonalAccessToken_GetAccessGrantedAt(tt *testing.T) { var zeroValue Timestamp p := &PersonalAccessToken{AccessGrantedAt: &zeroValue} @@ -29465,6 +29655,86 @@ func TestWorkflowJobEvent_GetWorkflowJob(tt *testing.T) { w.GetWorkflowJob() } +func TestWorkflowJobRun_GetConclusion(tt *testing.T) { + var zeroValue string + w := &WorkflowJobRun{Conclusion: &zeroValue} + w.GetConclusion() + w = &WorkflowJobRun{} + w.GetConclusion() + w = nil + w.GetConclusion() +} + +func TestWorkflowJobRun_GetCreatedAt(tt *testing.T) { + var zeroValue Timestamp + w := &WorkflowJobRun{CreatedAt: &zeroValue} + w.GetCreatedAt() + w = &WorkflowJobRun{} + w.GetCreatedAt() + w = nil + w.GetCreatedAt() +} + +func TestWorkflowJobRun_GetEnvironment(tt *testing.T) { + var zeroValue string + w := &WorkflowJobRun{Environment: &zeroValue} + w.GetEnvironment() + w = &WorkflowJobRun{} + w.GetEnvironment() + w = nil + w.GetEnvironment() +} + +func TestWorkflowJobRun_GetHTMLURL(tt *testing.T) { + var zeroValue string + w := &WorkflowJobRun{HTMLURL: &zeroValue} + w.GetHTMLURL() + w = &WorkflowJobRun{} + w.GetHTMLURL() + w = nil + w.GetHTMLURL() +} + +func TestWorkflowJobRun_GetID(tt *testing.T) { + var zeroValue int64 + w := &WorkflowJobRun{ID: &zeroValue} + w.GetID() + w = &WorkflowJobRun{} + w.GetID() + w = nil + w.GetID() +} + +func TestWorkflowJobRun_GetName(tt *testing.T) { + var zeroValue string + w := &WorkflowJobRun{Name: &zeroValue} + w.GetName() + w = &WorkflowJobRun{} + w.GetName() + w = nil + w.GetName() +} + +func TestWorkflowJobRun_GetStatus(tt *testing.T) { + var zeroValue string + w := &WorkflowJobRun{Status: &zeroValue} + w.GetStatus() + w = &WorkflowJobRun{} + w.GetStatus() + w = nil + w.GetStatus() +} + +func TestWorkflowJobRun_GetUpdatedAt(tt *testing.T) { + var zeroValue Timestamp + w := &WorkflowJobRun{UpdatedAt: &zeroValue} + w.GetUpdatedAt() + w = &WorkflowJobRun{} + w.GetUpdatedAt() + w = nil + w.GetUpdatedAt() +} + func TestWorkflowRun_GetActor(tt *testing.T) { w := &WorkflowRun{} w.GetActor() diff --git a/github/messages.go b/github/messages.go index 72edbd9feef..a4af8c3f8c1 100644 --- a/github/messages.go +++ b/github/messages.go @@ -57,6 +57,7 @@ var ( "dependabot_alert": &DependabotAlertEvent{}, "deploy_key": &DeployKeyEvent{}, "deployment": &DeploymentEvent{}, + "deployment_review": &DeploymentReviewEvent{}, "deployment_status": &DeploymentStatusEvent{}, "deployment_protection_rule": &DeploymentProtectionRuleEvent{}, "discussion": &DiscussionEvent{}, diff --git a/github/messages_test.go b/github/messages_test.go index 1243d755be8..df77056aa71 100644 --- a/github/messages_test.go +++ b/github/messages_test.go @@ -300,6 +300,10 @@ func TestParseWebHook(t *testing.T) { payload: &DeploymentProtectionRuleEvent{}, messageType: "deployment_protection_rule", }, + { + payload: &DeploymentReviewEvent{}, + messageType: "deployment_review", + }, { payload: &DeploymentStatusEvent{}, messageType: "deployment_status",