Repository: google/go-github (go)

Issue:
Incorrect type in HookDelivery
[Here](https://github.com/google/go-github/blob/1d9884e7ac8ca3c6d3d469af28af227fc773a246/github/repos_hooks_deliveries.go#L29) the `HookDelivery` defines the `InstallationID` as type `string`, but from the [documentation](https://docs.github.com/en/rest/reference/webhooks#list-deliveries-for-a-repository-webhook) it seems like a number. When testing I receive the error string 

```
json: cannot unmarshal number into Go struct field HookDelivery.installation_id of type string
```

Is this a possible bug?

Pull request:
Change type of HookDelivery.InstallationID to Int64.
Resolves #2234 

Patch:
diff --git a/.gitignore b/.gitignore
index c903cf6b..704f4ef5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,6 @@ vendor/
 .vscode
 # vim temp files
 *.swp
+
+# goenv local version. See https://github.com/syndbg/goenv/blob/master/COMMANDS.md#goenv-local for more info.
+.go-version
diff --git a/github/actions_workflow_runs.go b/github/actions_workflow_runs.go
index 2c90956c..1e1ff61a 100644
--- a/github/actions_workflow_runs.go
+++ b/github/actions_workflow_runs.go
@@ -14,33 +14,36 @@ import (
 
 // WorkflowRun represents a repository action workflow run.
 type WorkflowRun struct {
-	ID               *int64         `json:"id,omitempty"`
-	Name             *string        `json:"name,omitempty"`
-	NodeID           *string        `json:"node_id,omitempty"`
-	HeadBranch       *string        `json:"head_branch,omitempty"`
-	HeadSHA          *string        `json:"head_sha,omitempty"`
-	RunNumber        *int           `json:"run_number,omitempty"`
-	Event            *string        `json:"event,omitempty"`
-	Status           *string        `json:"status,omitempty"`
-	Conclusion       *string        `json:"conclusion,omitempty"`
-	WorkflowID       *int64         `json:"workflow_id,omitempty"`
-	CheckSuiteID     *int64         `json:"check_suite_id,omitempty"`
-	CheckSuiteNodeID *string        `json:"check_suite_node_id,omitempty"`
-	URL              *string        `json:"url,omitempty"`
-	HTMLURL          *string        `json:"html_url,omitempty"`
-	PullRequests     []*PullRequest `json:"pull_requests,omitempty"`
-	CreatedAt        *Timestamp     `json:"created_at,omitempty"`
-	UpdatedAt        *Timestamp     `json:"updated_at,omitempty"`
-	JobsURL          *string        `json:"jobs_url,omitempty"`
-	LogsURL          *string        `json:"logs_url,omitempty"`
-	CheckSuiteURL    *string        `json:"check_suite_url,omitempty"`
-	ArtifactsURL     *string        `json:"artifacts_url,omitempty"`
-	CancelURL        *string        `json:"cancel_url,omitempty"`
-	RerunURL         *string        `json:"rerun_url,omitempty"`
-	HeadCommit       *HeadCommit    `json:"head_commit,omitempty"`
-	WorkflowURL      *string        `json:"workflow_url,omitempty"`
-	Repository       *Repository    `json:"repository,omitempty"`
-	HeadRepository   *Repository    `json:"head_repository,omitempty"`
+	ID                 *int64         `json:"id,omitempty"`
+	Name               *string        `json:"name,omitempty"`
+	NodeID             *string        `json:"node_id,omitempty"`
+	HeadBranch         *string        `json:"head_branch,omitempty"`
+	HeadSHA            *string        `json:"head_sha,omitempty"`
+	RunNumber          *int           `json:"run_number,omitempty"`
+	RunAttempt         *int           `json:"run_attempt,omitempty"`
+	Event              *string        `json:"event,omitempty"`
+	Status             *string        `json:"status,omitempty"`
+	Conclusion         *string        `json:"conclusion,omitempty"`
+	WorkflowID         *int64         `json:"workflow_id,omitempty"`
+	CheckSuiteID       *int64         `json:"check_suite_id,omitempty"`
+	CheckSuiteNodeID   *string        `json:"check_suite_node_id,omitempty"`
+	URL                *string        `json:"url,omitempty"`
+	HTMLURL            *string        `json:"html_url,omitempty"`
+	PullRequests       []*PullRequest `json:"pull_requests,omitempty"`
+	CreatedAt          *Timestamp     `json:"created_at,omitempty"`
+	UpdatedAt          *Timestamp     `json:"updated_at,omitempty"`
+	RunStartedAt       *Timestamp     `json:"run_started_at,omitempty"`
+	JobsURL            *string        `json:"jobs_url,omitempty"`
+	LogsURL            *string        `json:"logs_url,omitempty"`
+	CheckSuiteURL      *string        `json:"check_suite_url,omitempty"`
+	ArtifactsURL       *string        `json:"artifacts_url,omitempty"`
+	CancelURL          *string        `json:"cancel_url,omitempty"`
+	RerunURL           *string        `json:"rerun_url,omitempty"`
+	PreviousAttemptURL *string        `json:"previous_attempt_url,omitempty"`
+	HeadCommit         *HeadCommit    `json:"head_commit,omitempty"`
+	WorkflowURL        *string        `json:"workflow_url,omitempty"`
+	Repository         *Repository    `json:"repository,omitempty"`
+	HeadRepository     *Repository    `json:"head_repository,omitempty"`
 }
 
 // WorkflowRuns represents a slice of repository action workflow run.
diff --git a/github/checks.go b/github/checks.go
index 07afb7c4..253d3518 100644
--- a/github/checks.go
+++ b/github/checks.go
@@ -234,6 +234,7 @@ type ListCheckRunsOptions struct {
 	CheckName *string `url:"check_name,omitempty"` // Returns check runs with the specified name.
 	Status    *string `url:"status,omitempty"`     // Returns check runs with the specified status. Can be one of "queued", "in_progress", or "completed".
 	Filter    *string `url:"filter,omitempty"`     // Filters check runs by their completed_at timestamp. Can be one of "latest" (returning the most recent check runs) or "all". Default: "latest"
+	AppID     *int64  `url:"app_id,omitempty"`     // Filters check runs by GitHub App ID.
 
 	ListOptions
 }
diff --git a/github/github-accessors.go b/github/github-accessors.go
index 189e68b3..7ee63226 100644
--- a/github/github-accessors.go
+++ b/github/github-accessors.go
@@ -4428,6 +4428,78 @@ func (e *Event) GetType() string {
 	return *e.Type
 }
 
+// GetGroupID returns the GroupID field if it's non-nil, zero value otherwise.
+func (e *ExternalGroup) GetGroupID() int64 {
+	if e == nil || e.GroupID == nil {
+		return 0
+	}
+	return *e.GroupID
+}
+
+// GetGroupName returns the GroupName field if it's non-nil, zero value otherwise.
+func (e *ExternalGroup) GetGroupName() string {
+	if e == nil || e.GroupName == nil {
+		return ""
+	}
+	return *e.GroupName
+}
+
+// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise.
+func (e *ExternalGroup) GetUpdatedAt() Timestamp {
+	if e == nil || e.UpdatedAt == nil {
+		return Timestamp{}
+	}
+	return *e.UpdatedAt
+}
+
+// GetMemberEmail returns the MemberEmail field if it's non-nil, zero value otherwise.
+func (e *ExternalGroupMember) GetMemberEmail() string {
+	if e == nil || e.MemberEmail == nil {
+		return ""
+	}
+	return *e.MemberEmail
+}
+
+// GetMemberID returns the MemberID field if it's non-nil, zero value otherwise.
+func (e *ExternalGroupMember) GetMemberID() int64 {
+	if e == nil || e.MemberID == nil {
+		return 0
+	}
+	return *e.MemberID
+}
+
+// GetMemberLogin returns the MemberLogin field if it's non-nil, zero value otherwise.
+func (e *ExternalGroupMember) GetMemberLogin() string {
+	if e == nil || e.MemberLogin == nil {
+		return ""
+	}
+	return *e.MemberLogin
+}
+
+// GetMemberName returns the MemberName field if it's non-nil, zero value otherwise.
+func (e *ExternalGroupMember) GetMemberName() string {
+	if e == nil || e.MemberName == nil {
+		return ""
+	}
+	return *e.MemberName
+}
+
+// GetTeamID returns the TeamID field if it's non-nil, zero value otherwise.
+func (e *ExternalGroupTeam) GetTeamID() int64 {
+	if e == nil || e.TeamID == nil {
+		return 0
+	}
+	return *e.TeamID
+}
+
+// GetTeamName returns the TeamName field if it's non-nil, zero value otherwise.
+func (e *ExternalGroupTeam) GetTeamName() string {
+	if e == nil || e.TeamName == nil {
+		return ""
+	}
+	return *e.TeamName
+}
+
 // GetHRef returns the HRef field if it's non-nil, zero value otherwise.
 func (f *FeedLink) GetHRef() string {
 	if f == nil || f.HRef == nil {
@@ -5381,9 +5453,9 @@ func (h *HookDelivery) GetID() int64 {
 }
 
 // GetInstallationID returns the InstallationID field if it's non-nil, zero value otherwise.
-func (h *HookDelivery) GetInstallationID() string {
+func (h *HookDelivery) GetInstallationID() int64 {
 	if h == nil || h.InstallationID == nil {
-		return ""
+		return 0
 	}
 	return *h.InstallationID
 }
@@ -7524,6 +7596,14 @@ func (l *License) GetURL() string {
 	return *l.URL
 }
 
+// GetAppID returns the AppID field if it's non-nil, zero value otherwise.
+func (l *ListCheckRunsOptions) GetAppID() int64 {
+	if l == nil || l.AppID == nil {
+		return 0
+	}
+	return *l.AppID
+}
+
 // GetCheckName returns the CheckName field if it's non-nil, zero value otherwise.
 func (l *ListCheckRunsOptions) GetCheckName() string {
 	if l == nil || l.CheckName == nil {
@@ -7588,6 +7668,14 @@ func (l *ListCollaboratorOptions) GetAffiliation() string {
 	return *l.Affiliation
 }
 
+// GetDisplayName returns the DisplayName field if it's non-nil, zero value otherwise.
+func (l *ListExternalGroupsOptions) GetDisplayName() string {
+	if l == nil || l.DisplayName == nil {
+		return ""
+	}
+	return *l.DisplayName
+}
+
 // GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise.
 func (l *ListRepositories) GetTotalCount() int {
 	if l == nil || l.TotalCount == nil {
@@ -16076,6 +16164,14 @@ func (t *Team) GetDescription() string {
 	return *t.Description
 }
 
+// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise.
+func (t *Team) GetHTMLURL() string {
+	if t == nil || t.HTMLURL == nil {
+		return ""
+	}
+	return *t.HTMLURL
+}
+
 // GetID returns the ID field if it's non-nil, zero value otherwise.
 func (t *Team) GetID() int64 {
 	if t == nil || t.ID == nil {
@@ -18780,6 +18876,14 @@ func (w *WorkflowRun) GetNodeID() string {
 	return *w.NodeID
 }
 
+// GetPreviousAttemptURL returns the PreviousAttemptURL field if it's non-nil, zero value otherwise.
+func (w *WorkflowRun) GetPreviousAttemptURL() string {
+	if w == nil || w.PreviousAttemptURL == nil {
+		return ""
+	}
+	return *w.PreviousAttemptURL
+}
+
 // GetRepository returns the Repository field.
 func (w *WorkflowRun) GetRepository() *Repository {
 	if w == nil {
@@ -18796,6 +18900,14 @@ func (w *WorkflowRun) GetRerunURL() string {
 	return *w.RerunURL
 }
 
+// GetRunAttempt returns the RunAttempt field if it's non-nil, zero value otherwise.
+func (w *WorkflowRun) GetRunAttempt() int {
+	if w == nil || w.RunAttempt == nil {
+		return 0
+	}
+	return *w.RunAttempt
+}
+
 // GetRunNumber returns the RunNumber field if it's non-nil, zero value otherwise.
 func (w *WorkflowRun) GetRunNumber() int {
 	if w == nil || w.RunNumber == nil {
@@ -18804,6 +18916,14 @@ func (w *WorkflowRun) GetRunNumber() int {
 	return *w.RunNumber
 }
 
+// GetRunStartedAt returns the RunStartedAt field if it's non-nil, zero value otherwise.
+func (w *WorkflowRun) GetRunStartedAt() Timestamp {
+	if w == nil || w.RunStartedAt == nil {
+		return Timestamp{}
+	}
+	return *w.RunStartedAt
+}
+
 // GetStatus returns the Status field if it's non-nil, zero value otherwise.
 func (w *WorkflowRun) GetStatus() string {
 	if w == nil || w.Status == nil {
diff --git a/github/repos_hooks_deliveries.go b/github/repos_hooks_deliveries.go
index 12267446..17132695 100644
--- a/github/repos_hooks_deliveries.go
+++ b/github/repos_hooks_deliveries.go
@@ -17,17 +17,17 @@ import (
 // - https://docs.github.com/en/rest/reference/repos#list-deliveries-for-a-repository-webhook
 // - https://docs.github.com/en/rest/reference/repos#get-a-delivery-for-a-repository-webhook
 type HookDelivery struct {
-	ID             *int64     `json:"id"`
-	GUID           *string    `json:"guid"`
-	DeliveredAt    *Timestamp `json:"delivered_at"`
-	Redelivery     *bool      `json:"redelivery"`
-	Duration       *float64   `json:"duration"`
-	Status         *string    `json:"status"`
-	StatusCode     *int       `json:"status_code"`
-	Event          *string    `json:"event"`
-	Action         *string    `json:"action"`
-	InstallationID *string    `json:"installation_id"`
-	RepositoryID   *int64     `json:"repository_id"`
+	ID             *int64     `json:"id,omitempty"`
+	GUID           *string    `json:"guid,omitempty"`
+	DeliveredAt    *Timestamp `json:"delivered_at,omitempty"`
+	Redelivery     *bool      `json:"redelivery,omitempty"`
+	Duration       *float64   `json:"duration,omitempty"`
+	Status         *string    `json:"status,omitempty"`
+	StatusCode     *int       `json:"status_code,omitempty"`
+	Event          *string    `json:"event,omitempty"`
+	Action         *string    `json:"action,omitempty"`
+	InstallationID *int64     `json:"installation_id,omitempty"`
+	RepositoryID   *int64     `json:"repository_id,omitempty"`
 
 	// Request is populated by GetHookDelivery.
 	Request *HookRequest `json:"request,omitempty"`
diff --git a/github/teams.go b/github/teams.go
index 7a8a5d8a..82d4093b 100644
--- a/github/teams.go
+++ b/github/teams.go
@@ -46,6 +46,7 @@ type Team struct {
 	MembersCount    *int          `json:"members_count,omitempty"`
 	ReposCount      *int          `json:"repos_count,omitempty"`
 	Organization    *Organization `json:"organization,omitempty"`
+	HTMLURL         *string       `json:"html_url,omitempty"`
 	MembersURL      *string       `json:"members_url,omitempty"`
 	RepositoriesURL *string       `json:"repositories_url,omitempty"`
 	Parent          *Team         `json:"parent,omitempty"`
@@ -854,3 +855,116 @@ func (s *TeamsService) CreateOrUpdateIDPGroupConnectionsBySlug(ctx context.Conte
 
 	return groups, resp, nil
 }
+
+// ExternalGroupMember represents a member of an external group.
+type ExternalGroupMember struct {
+	MemberID    *int64  `json:"member_id,omitempty"`
+	MemberLogin *string `json:"member_login,omitempty"`
+	MemberName  *string `json:"member_name,omitempty"`
+	MemberEmail *string `json:"member_email,omitempty"`
+}
+
+// ExternalGroupTeam represents a team connected to an external group.
+type ExternalGroupTeam struct {
+	TeamID   *int64  `json:"team_id,omitempty"`
+	TeamName *string `json:"team_name,omitempty"`
+}
+
+// ExternalGroup represents an external group.
+type ExternalGroup struct {
+	GroupID   *int64                 `json:"group_id,omitempty"`
+	GroupName *string                `json:"group_name,omitempty"`
+	UpdatedAt *Timestamp             `json:"updated_at,omitempty"`
+	Teams     []*ExternalGroupTeam   `json:"teams,omitempty"`
+	Members   []*ExternalGroupMember `json:"members,omitempty"`
+}
+
+// ExternalGroupList represents a list of external groups.
+type ExternalGroupList struct {
+	Groups []*ExternalGroup `json:"groups"`
+}
+
+// GetExternalGroup fetches an external group.
+//
+// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/reference/teams#get-an-external-group
+func (s *TeamsService) GetExternalGroup(ctx context.Context, org string, groupID int64) (*ExternalGroup, *Response, error) {
+	u := fmt.Sprintf("orgs/%v/external-group/%v", org, groupID)
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	externalGroup := new(ExternalGroup)
+	resp, err := s.client.Do(ctx, req, externalGroup)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return externalGroup, resp, nil
+}
+
+// ListExternalGroupsOptions specifies the optional parameters to the
+// TeamsService.ListExternalGroups method.
+type ListExternalGroupsOptions struct {
+	DisplayName *string `url:"display_name,omitempty"`
+
+	ListOptions
+}
+
+// ListExternalGroups lists external groups connected to a team on GitHub.
+//
+// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/reference/teams#list-external-groups-in-an-organization
+func (s *TeamsService) ListExternalGroups(ctx context.Context, org string, opts *ListExternalGroupsOptions) (*ExternalGroupList, *Response, error) {
+	u := fmt.Sprintf("orgs/%v/external-groups", org)
+	u, err := addOptions(u, opts)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	externalGroups := new(ExternalGroupList)
+	resp, err := s.client.Do(ctx, req, externalGroups)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return externalGroups, resp, nil
+}
+
+// UpdateConnectedExternalGroup updates the connection between an external group and a team.
+//
+// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/reference/teams#update-the-connection-between-an-external-group-and-a-team
+func (s *TeamsService) UpdateConnectedExternalGroup(ctx context.Context, org, slug string, eg *ExternalGroup) (*ExternalGroup, *Response, error) {
+	u := fmt.Sprintf("orgs/%v/teams/%v/external-groups", org, slug)
+
+	req, err := s.client.NewRequest("PATCH", u, eg)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	externalGroup := new(ExternalGroup)
+	resp, err := s.client.Do(ctx, req, externalGroup)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return externalGroup, resp, nil
+}
+
+// RemoveConnectedExternalGroup removes the connection between an external group and a team.
+//
+// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/reference/teams#remove-the-connection-between-an-external-group-and-a-team
+func (s *TeamsService) RemoveConnectedExternalGroup(ctx context.Context, org, slug string) (*Response, error) {
+	u := fmt.Sprintf("orgs/%v/teams/%v/external-groups", org, slug)
+
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(ctx, req, nil)
+}


Test patch:
diff --git a/github/actions_workflow_runs_test.go b/github/actions_workflow_runs_test.go
index d3623621..7ebdbf58 100644
--- a/github/actions_workflow_runs_test.go
+++ b/github/actions_workflow_runs_test.go
@@ -464,6 +464,7 @@ func TestWorkflowRun_Marshal(t *testing.T) {
 		HeadBranch: String("hb"),
 		HeadSHA:    String("hs"),
 		RunNumber:  Int(1),
+		RunAttempt: Int(1),
 		Event:      String("e"),
 		Status:     String("s"),
 		Conclusion: String("c"),
@@ -495,14 +496,16 @@ func TestWorkflowRun_Marshal(t *testing.T) {
 				},
 			},
 		},
-		CreatedAt:     &Timestamp{referenceTime},
-		UpdatedAt:     &Timestamp{referenceTime},
-		JobsURL:       String("j"),
-		LogsURL:       String("l"),
-		CheckSuiteURL: String("c"),
-		ArtifactsURL:  String("a"),
-		CancelURL:     String("c"),
-		RerunURL:      String("r"),
+		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{
@@ -542,6 +545,7 @@ func TestWorkflowRun_Marshal(t *testing.T) {
 		"head_branch": "hb",
 		"head_sha": "hs",
 		"run_number": 1,
+		"run_attempt": 1,
 		"event": "e",
 		"status": "s",
 		"conclusion": "c",
@@ -575,12 +579,14 @@ func TestWorkflowRun_Marshal(t *testing.T) {
 		],
 		"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": {
@@ -629,6 +635,7 @@ func TestWorkflowRuns_Marshal(t *testing.T) {
 				HeadBranch: String("hb"),
 				HeadSHA:    String("hs"),
 				RunNumber:  Int(1),
+				RunAttempt: Int(1),
 				Event:      String("e"),
 				Status:     String("s"),
 				Conclusion: String("c"),
@@ -660,14 +667,16 @@ func TestWorkflowRuns_Marshal(t *testing.T) {
 						},
 					},
 				},
-				CreatedAt:     &Timestamp{referenceTime},
-				UpdatedAt:     &Timestamp{referenceTime},
-				JobsURL:       String("j"),
-				LogsURL:       String("l"),
-				CheckSuiteURL: String("c"),
-				ArtifactsURL:  String("a"),
-				CancelURL:     String("c"),
-				RerunURL:      String("r"),
+				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{
@@ -712,6 +721,7 @@ func TestWorkflowRuns_Marshal(t *testing.T) {
 				"head_branch": "hb",
 				"head_sha": "hs",
 				"run_number": 1,
+				"run_attempt": 1,
 				"event": "e",
 				"status": "s",
 				"conclusion": "c",
@@ -745,12 +755,14 @@ func TestWorkflowRuns_Marshal(t *testing.T) {
 				],
 				"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": {
diff --git a/github/checks_test.go b/github/checks_test.go
index 26da9abf..1e07d314 100644
--- a/github/checks_test.go
+++ b/github/checks_test.go
@@ -319,6 +319,7 @@ func TestChecksService_ListCheckRunsForRef(t *testing.T) {
 			"page":       "1",
 			"status":     "completed",
 			"filter":     "all",
+			"app_id":     "1",
 		})
 		fmt.Fprint(w, `{"total_count":1,
                                 "check_runs": [{
@@ -327,7 +328,9 @@ func TestChecksService_ListCheckRunsForRef(t *testing.T) {
                                     "status": "completed",
                                     "conclusion": "neutral",
                                     "started_at": "2018-05-04T01:14:52Z",
-                                    "completed_at": "2018-05-04T01:14:52Z"}]}`,
+                                    "completed_at": "2018-05-04T01:14:52Z",
+                                    "app": {
+                                      "id": 1}}]}`,
 		)
 	})
 
@@ -335,6 +338,7 @@ func TestChecksService_ListCheckRunsForRef(t *testing.T) {
 		CheckName:   String("testing"),
 		Status:      String("completed"),
 		Filter:      String("all"),
+		AppID:       Int64(1),
 		ListOptions: ListOptions{Page: 1},
 	}
 	ctx := context.Background()
@@ -352,6 +356,7 @@ func TestChecksService_ListCheckRunsForRef(t *testing.T) {
 			CompletedAt: &Timestamp{startedAt},
 			Conclusion:  String("neutral"),
 			HeadSHA:     String("deadbeef"),
+			App:         &App{ID: Int64(1)},
 		}},
 	}
 
diff --git a/github/event_types_test.go b/github/event_types_test.go
index bb5dd40d..a434a009 100644
--- a/github/event_types_test.go
+++ b/github/event_types_test.go
@@ -8359,6 +8359,7 @@ func TestWorkflowRunEvent_Marshal(t *testing.T) {
 			HeadBranch: String("hb"),
 			HeadSHA:    String("hs"),
 			RunNumber:  Int(1),
+			RunAttempt: Int(1),
 			Event:      String("e"),
 			Status:     String("s"),
 			Conclusion: String("c"),
@@ -8390,14 +8391,16 @@ func TestWorkflowRunEvent_Marshal(t *testing.T) {
 					},
 				},
 			},
-			CreatedAt:     &Timestamp{referenceTime},
-			UpdatedAt:     &Timestamp{referenceTime},
-			JobsURL:       String("j"),
-			LogsURL:       String("l"),
-			CheckSuiteURL: String("c"),
-			ArtifactsURL:  String("a"),
-			CancelURL:     String("c"),
-			RerunURL:      String("r"),
+			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{
@@ -8488,6 +8491,7 @@ func TestWorkflowRunEvent_Marshal(t *testing.T) {
 			"head_branch": "hb",
 			"head_sha": "hs",
 			"run_number": 1,
+			"run_attempt": 1,
 			"event": "e",
 			"status": "s",
 			"conclusion": "c",
@@ -8521,12 +8525,14 @@ func TestWorkflowRunEvent_Marshal(t *testing.T) {
 			],
 			"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": {
diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go
index 69ed4030..c9c27bb4 100644
--- a/github/github-accessors_test.go
+++ b/github/github-accessors_test.go
@@ -5182,6 +5182,96 @@ func TestEvent_GetType(tt *testing.T) {
 	e.GetType()
 }
 
+func TestExternalGroup_GetGroupID(tt *testing.T) {
+	var zeroValue int64
+	e := &ExternalGroup{GroupID: &zeroValue}
+	e.GetGroupID()
+	e = &ExternalGroup{}
+	e.GetGroupID()
+	e = nil
+	e.GetGroupID()
+}
+
+func TestExternalGroup_GetGroupName(tt *testing.T) {
+	var zeroValue string
+	e := &ExternalGroup{GroupName: &zeroValue}
+	e.GetGroupName()
+	e = &ExternalGroup{}
+	e.GetGroupName()
+	e = nil
+	e.GetGroupName()
+}
+
+func TestExternalGroup_GetUpdatedAt(tt *testing.T) {
+	var zeroValue Timestamp
+	e := &ExternalGroup{UpdatedAt: &zeroValue}
+	e.GetUpdatedAt()
+	e = &ExternalGroup{}
+	e.GetUpdatedAt()
+	e = nil
+	e.GetUpdatedAt()
+}
+
+func TestExternalGroupMember_GetMemberEmail(tt *testing.T) {
+	var zeroValue string
+	e := &ExternalGroupMember{MemberEmail: &zeroValue}
+	e.GetMemberEmail()
+	e = &ExternalGroupMember{}
+	e.GetMemberEmail()
+	e = nil
+	e.GetMemberEmail()
+}
+
+func TestExternalGroupMember_GetMemberID(tt *testing.T) {
+	var zeroValue int64
+	e := &ExternalGroupMember{MemberID: &zeroValue}
+	e.GetMemberID()
+	e = &ExternalGroupMember{}
+	e.GetMemberID()
+	e = nil
+	e.GetMemberID()
+}
+
+func TestExternalGroupMember_GetMemberLogin(tt *testing.T) {
+	var zeroValue string
+	e := &ExternalGroupMember{MemberLogin: &zeroValue}
+	e.GetMemberLogin()
+	e = &ExternalGroupMember{}
+	e.GetMemberLogin()
+	e = nil
+	e.GetMemberLogin()
+}
+
+func TestExternalGroupMember_GetMemberName(tt *testing.T) {
+	var zeroValue string
+	e := &ExternalGroupMember{MemberName: &zeroValue}
+	e.GetMemberName()
+	e = &ExternalGroupMember{}
+	e.GetMemberName()
+	e = nil
+	e.GetMemberName()
+}
+
+func TestExternalGroupTeam_GetTeamID(tt *testing.T) {
+	var zeroValue int64
+	e := &ExternalGroupTeam{TeamID: &zeroValue}
+	e.GetTeamID()
+	e = &ExternalGroupTeam{}
+	e.GetTeamID()
+	e = nil
+	e.GetTeamID()
+}
+
+func TestExternalGroupTeam_GetTeamName(tt *testing.T) {
+	var zeroValue string
+	e := &ExternalGroupTeam{TeamName: &zeroValue}
+	e.GetTeamName()
+	e = &ExternalGroupTeam{}
+	e.GetTeamName()
+	e = nil
+	e.GetTeamName()
+}
+
 func TestFeedLink_GetHRef(tt *testing.T) {
 	var zeroValue string
 	f := &FeedLink{HRef: &zeroValue}
@@ -6298,7 +6388,7 @@ func TestHookDelivery_GetID(tt *testing.T) {
 }
 
 func TestHookDelivery_GetInstallationID(tt *testing.T) {
-	var zeroValue string
+	var zeroValue int64
 	h := &HookDelivery{InstallationID: &zeroValue}
 	h.GetInstallationID()
 	h = &HookDelivery{}
@@ -8821,6 +8911,16 @@ func TestLicense_GetURL(tt *testing.T) {
 	l.GetURL()
 }
 
+func TestListCheckRunsOptions_GetAppID(tt *testing.T) {
+	var zeroValue int64
+	l := &ListCheckRunsOptions{AppID: &zeroValue}
+	l.GetAppID()
+	l = &ListCheckRunsOptions{}
+	l.GetAppID()
+	l = nil
+	l.GetAppID()
+}
+
 func TestListCheckRunsOptions_GetCheckName(tt *testing.T) {
 	var zeroValue string
 	l := &ListCheckRunsOptions{CheckName: &zeroValue}
@@ -8901,6 +9001,16 @@ func TestListCollaboratorOptions_GetAffiliation(tt *testing.T) {
 	l.GetAffiliation()
 }
 
+func TestListExternalGroupsOptions_GetDisplayName(tt *testing.T) {
+	var zeroValue string
+	l := &ListExternalGroupsOptions{DisplayName: &zeroValue}
+	l.GetDisplayName()
+	l = &ListExternalGroupsOptions{}
+	l.GetDisplayName()
+	l = nil
+	l.GetDisplayName()
+}
+
 func TestListRepositories_GetTotalCount(tt *testing.T) {
 	var zeroValue int
 	l := &ListRepositories{TotalCount: &zeroValue}
@@ -18800,6 +18910,16 @@ func TestTeam_GetDescription(tt *testing.T) {
 	t.GetDescription()
 }
 
+func TestTeam_GetHTMLURL(tt *testing.T) {
+	var zeroValue string
+	t := &Team{HTMLURL: &zeroValue}
+	t.GetHTMLURL()
+	t = &Team{}
+	t.GetHTMLURL()
+	t = nil
+	t.GetHTMLURL()
+}
+
 func TestTeam_GetID(tt *testing.T) {
 	var zeroValue int64
 	t := &Team{ID: &zeroValue}
@@ -21979,6 +22099,16 @@ func TestWorkflowRun_GetNodeID(tt *testing.T) {
 	w.GetNodeID()
 }
 
+func TestWorkflowRun_GetPreviousAttemptURL(tt *testing.T) {
+	var zeroValue string
+	w := &WorkflowRun{PreviousAttemptURL: &zeroValue}
+	w.GetPreviousAttemptURL()
+	w = &WorkflowRun{}
+	w.GetPreviousAttemptURL()
+	w = nil
+	w.GetPreviousAttemptURL()
+}
+
 func TestWorkflowRun_GetRepository(tt *testing.T) {
 	w := &WorkflowRun{}
 	w.GetRepository()
@@ -21996,6 +22126,16 @@ func TestWorkflowRun_GetRerunURL(tt *testing.T) {
 	w.GetRerunURL()
 }
 
+func TestWorkflowRun_GetRunAttempt(tt *testing.T) {
+	var zeroValue int
+	w := &WorkflowRun{RunAttempt: &zeroValue}
+	w.GetRunAttempt()
+	w = &WorkflowRun{}
+	w.GetRunAttempt()
+	w = nil
+	w.GetRunAttempt()
+}
+
 func TestWorkflowRun_GetRunNumber(tt *testing.T) {
 	var zeroValue int
 	w := &WorkflowRun{RunNumber: &zeroValue}
@@ -22006,6 +22146,16 @@ func TestWorkflowRun_GetRunNumber(tt *testing.T) {
 	w.GetRunNumber()
 }
 
+func TestWorkflowRun_GetRunStartedAt(tt *testing.T) {
+	var zeroValue Timestamp
+	w := &WorkflowRun{RunStartedAt: &zeroValue}
+	w.GetRunStartedAt()
+	w = &WorkflowRun{}
+	w.GetRunStartedAt()
+	w = nil
+	w.GetRunStartedAt()
+}
+
 func TestWorkflowRun_GetStatus(tt *testing.T) {
 	var zeroValue string
 	w := &WorkflowRun{Status: &zeroValue}
diff --git a/github/github-stringify_test.go b/github/github-stringify_test.go
index 41228378..2d961348 100644
--- a/github/github-stringify_test.go
+++ b/github/github-stringify_test.go
@@ -568,12 +568,12 @@ func TestHookDelivery_String(t *testing.T) {
 		StatusCode:     Int(0),
 		Event:          String(""),
 		Action:         String(""),
-		InstallationID: String(""),
+		InstallationID: Int64(0),
 		RepositoryID:   Int64(0),
 		Request:        &HookRequest{},
 		Response:       &HookResponse{},
 	}
-	want := `github.HookDelivery{ID:0, GUID:"", DeliveredAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, Redelivery:false, Duration:0, Status:"", StatusCode:0, Event:"", Action:"", InstallationID:"", RepositoryID:0, Request:github.HookRequest{}, Response:github.HookResponse{}}`
+	want := `github.HookDelivery{ID:0, GUID:"", DeliveredAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, Redelivery:false, Duration:0, Status:"", StatusCode:0, Event:"", Action:"", InstallationID:0, RepositoryID:0, Request:github.HookRequest{}, Response:github.HookResponse{}}`
 	if got := v.String(); got != want {
 		t.Errorf("HookDelivery.String = %v, want %v", got, want)
 	}
@@ -1672,12 +1672,13 @@ func TestTeam_String(t *testing.T) {
 		MembersCount:    Int(0),
 		ReposCount:      Int(0),
 		Organization:    &Organization{},
+		HTMLURL:         String(""),
 		MembersURL:      String(""),
 		RepositoriesURL: String(""),
 		Parent:          &Team{},
 		LDAPDN:          String(""),
 	}
-	want := `github.Team{ID:0, NodeID:"", Name:"", Description:"", URL:"", Slug:"", Permission:"", Privacy:"", MembersCount:0, ReposCount:0, Organization:github.Organization{}, MembersURL:"", RepositoriesURL:"", Parent:github.Team{}, LDAPDN:""}`
+	want := `github.Team{ID:0, NodeID:"", Name:"", Description:"", URL:"", Slug:"", Permission:"", Privacy:"", MembersCount:0, ReposCount:0, Organization:github.Organization{}, HTMLURL:"", MembersURL:"", RepositoriesURL:"", Parent:github.Team{}, LDAPDN:""}`
 	if got := v.String(); got != want {
 		t.Errorf("Team.String = %v, want %v", got, want)
 	}
diff --git a/github/repos_hooks_deliveries_test.go b/github/repos_hooks_deliveries_test.go
index 8724e863..a7788831 100644
--- a/github/repos_hooks_deliveries_test.go
+++ b/github/repos_hooks_deliveries_test.go
@@ -288,7 +288,7 @@ func TestHookDelivery_Marshal(t *testing.T) {
 		StatusCode:     Int(1),
 		Event:          String("guid"),
 		Action:         String("guid"),
-		InstallationID: String("guid"),
+		InstallationID: Int64(1),
 		RepositoryID:   Int64(1),
 		Request: &HookRequest{
 			Headers:    header,
@@ -310,7 +310,7 @@ func TestHookDelivery_Marshal(t *testing.T) {
 		"status_code": 1,
 		"event": "guid",
 		"action": "guid",
-		"installation_id": "guid",
+		"installation_id": 1,
 		"repository_id": 1,
 		"request": {
 			"headers": {
diff --git a/github/teams_test.go b/github/teams_test.go
index 26cf2c03..83f559be 100644
--- a/github/teams_test.go
+++ b/github/teams_test.go
@@ -1745,3 +1745,356 @@ func TestIDPGroup_Marshal(t *testing.T) {
 
 	testJSONMarshal(t, u, want)
 }
+
+func TestTeamsService_GetExternalGroup(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/orgs/o/external-group/123", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		fmt.Fprint(w, `{
+			"group_id": 123,
+			"group_name": "Octocat admins",
+			"updated_at": "2006-01-02T15:04:05Z",
+			"teams": [
+				{
+					"team_id": 1,
+					"team_name": "team-test"
+				},
+				{
+					"team_id": 2,
+					"team_name": "team-test2"
+				}
+			],
+			"members": [
+				{
+					"member_id": 1,
+					"member_login": "mona-lisa_eocsaxrs",
+					"member_name": "Mona Lisa",
+					"member_email": "mona_lisa@github.com"
+				},
+				{
+					"member_id": 2,
+					"member_login": "octo-lisa_eocsaxrs",
+					"member_name": "Octo Lisa",
+					"member_email": "octo_lisa@github.com"
+				}
+			]
+		}`)
+	})
+
+	ctx := context.Background()
+	externalGroup, _, err := client.Teams.GetExternalGroup(ctx, "o", 123)
+	if err != nil {
+		t.Errorf("Teams.GetExternalGroup returned error: %v", err)
+	}
+
+	want := &ExternalGroup{
+		GroupID:   Int64(123),
+		GroupName: String("Octocat admins"),
+		UpdatedAt: &Timestamp{Time: referenceTime},
+		Teams: []*ExternalGroupTeam{
+			{
+				TeamID:   Int64(1),
+				TeamName: String("team-test"),
+			},
+			{
+				TeamID:   Int64(2),
+				TeamName: String("team-test2"),
+			},
+		},
+		Members: []*ExternalGroupMember{
+			{
+				MemberID:    Int64(1),
+				MemberLogin: String("mona-lisa_eocsaxrs"),
+				MemberName:  String("Mona Lisa"),
+				MemberEmail: String("mona_lisa@github.com"),
+			},
+			{
+				MemberID:    Int64(2),
+				MemberLogin: String("octo-lisa_eocsaxrs"),
+				MemberName:  String("Octo Lisa"),
+				MemberEmail: String("octo_lisa@github.com"),
+			},
+		},
+	}
+	if !cmp.Equal(externalGroup, want) {
+		t.Errorf("Teams.GetExternalGroup returned %+v, want %+v", externalGroup, want)
+	}
+
+	const methodName = "GetExternalGroup"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Teams.GetExternalGroup(ctx, "\n", -1)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Teams.GetExternalGroup(ctx, "o", 123)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
+func TestTeamsService_GetExternalGroup_notFound(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/orgs/o/external-group/123", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		w.WriteHeader(http.StatusNotFound)
+	})
+
+	ctx := context.Background()
+	eg, resp, err := client.Teams.GetExternalGroup(ctx, "o", 123)
+	if err == nil {
+		t.Errorf("Expected HTTP 404 response")
+	}
+	if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want {
+		t.Errorf("Teams.GetExternalGroup returned status %d, want %d", got, want)
+	}
+	if eg != nil {
+		t.Errorf("Teams.GetExternalGroup returned %+v, want nil", eg)
+	}
+}
+
+func TestTeamsService_ListExternalGroups(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/orgs/o/external-groups", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		fmt.Fprint(w, `{
+			"groups": [
+				{
+					"group_id": 123,
+					"group_name": "Octocat admins",
+					"updated_at": "2006-01-02T15:04:05Z"
+				}
+			]
+		}`)
+	})
+
+	ctx := context.Background()
+	opts := &ListExternalGroupsOptions{
+		DisplayName: String("Octocat"),
+	}
+	list, _, err := client.Teams.ListExternalGroups(ctx, "o", opts)
+	if err != nil {
+		t.Errorf("Teams.ListExternalGroups returned error: %v", err)
+	}
+
+	want := &ExternalGroupList{
+		Groups: []*ExternalGroup{
+			{
+				GroupID:   Int64(123),
+				GroupName: String("Octocat admins"),
+				UpdatedAt: &Timestamp{Time: referenceTime},
+			},
+		},
+	}
+	if !cmp.Equal(list, want) {
+		t.Errorf("Teams.ListExternalGroups returned %+v, want %+v", list, want)
+	}
+
+	const methodName = "ListExternalGroups"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Teams.ListExternalGroups(ctx, "\n", opts)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Teams.ListExternalGroups(ctx, "o", opts)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
+func TestTeamsService_ListExternalGroups_notFound(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/orgs/o/external-groups", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		w.WriteHeader(http.StatusNotFound)
+	})
+
+	ctx := context.Background()
+	eg, resp, err := client.Teams.ListExternalGroups(ctx, "o", nil)
+	if err == nil {
+		t.Errorf("Expected HTTP 404 response")
+	}
+	if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want {
+		t.Errorf("Teams.ListExternalGroups returned status %d, want %d", got, want)
+	}
+	if eg != nil {
+		t.Errorf("Teams.ListExternalGroups returned %+v, want nil", eg)
+	}
+}
+
+func TestTeamsService_UpdateConnectedExternalGroup(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/orgs/o/teams/t/external-groups", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "PATCH")
+		fmt.Fprint(w, `{
+			"group_id": 123,
+			"group_name": "Octocat admins",
+			"updated_at": "2006-01-02T15:04:05Z",
+			"teams": [
+				{
+					"team_id": 1,
+					"team_name": "team-test"
+				},
+				{
+					"team_id": 2,
+					"team_name": "team-test2"
+				}
+			],
+			"members": [
+				{
+					"member_id": 1,
+					"member_login": "mona-lisa_eocsaxrs",
+					"member_name": "Mona Lisa",
+					"member_email": "mona_lisa@github.com"
+				},
+				{
+					"member_id": 2,
+					"member_login": "octo-lisa_eocsaxrs",
+					"member_name": "Octo Lisa",
+					"member_email": "octo_lisa@github.com"
+				}
+			]
+		}`)
+	})
+
+	ctx := context.Background()
+	body := &ExternalGroup{
+		GroupID: Int64(123),
+	}
+	externalGroup, _, err := client.Teams.UpdateConnectedExternalGroup(ctx, "o", "t", body)
+	if err != nil {
+		t.Errorf("Teams.UpdateConnectedExternalGroup returned error: %v", err)
+	}
+
+	want := &ExternalGroup{
+		GroupID:   Int64(123),
+		GroupName: String("Octocat admins"),
+		UpdatedAt: &Timestamp{Time: referenceTime},
+		Teams: []*ExternalGroupTeam{
+			{
+				TeamID:   Int64(1),
+				TeamName: String("team-test"),
+			},
+			{
+				TeamID:   Int64(2),
+				TeamName: String("team-test2"),
+			},
+		},
+		Members: []*ExternalGroupMember{
+			{
+				MemberID:    Int64(1),
+				MemberLogin: String("mona-lisa_eocsaxrs"),
+				MemberName:  String("Mona Lisa"),
+				MemberEmail: String("mona_lisa@github.com"),
+			},
+			{
+				MemberID:    Int64(2),
+				MemberLogin: String("octo-lisa_eocsaxrs"),
+				MemberName:  String("Octo Lisa"),
+				MemberEmail: String("octo_lisa@github.com"),
+			},
+		},
+	}
+	if !cmp.Equal(externalGroup, want) {
+		t.Errorf("Teams.GetExternalGroup returned %+v, want %+v", externalGroup, want)
+	}
+
+	const methodName = "UpdateConnectedExternalGroup"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Teams.UpdateConnectedExternalGroup(ctx, "\n", "\n", body)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Teams.UpdateConnectedExternalGroup(ctx, "o", "t", body)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
+func TestTeamsService_UpdateConnectedExternalGroup_notFound(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/orgs/o/teams/t/external-groups", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "PATCH")
+		w.WriteHeader(http.StatusNotFound)
+	})
+
+	ctx := context.Background()
+	body := &ExternalGroup{
+		GroupID: Int64(123),
+	}
+	eg, resp, err := client.Teams.UpdateConnectedExternalGroup(ctx, "o", "t", body)
+	if err == nil {
+		t.Errorf("Expected HTTP 404 response")
+	}
+	if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want {
+		t.Errorf("Teams.UpdateConnectedExternalGroup returned status %d, want %d", got, want)
+	}
+	if eg != nil {
+		t.Errorf("Teams.UpdateConnectedExternalGroup returned %+v, want nil", eg)
+	}
+}
+
+func TestTeamsService_RemoveConnectedExternalGroup(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/orgs/o/teams/t/external-groups", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "DELETE")
+		w.WriteHeader(http.StatusNoContent)
+	})
+
+	ctx := context.Background()
+	_, err := client.Teams.RemoveConnectedExternalGroup(ctx, "o", "t")
+	if err != nil {
+		t.Errorf("Teams.RemoveConnectedExternalGroup returned error: %v", err)
+	}
+
+	const methodName = "RemoveConnectedExternalGroup"
+	testBadOptions(t, methodName, func() (err error) {
+		_, err = client.Teams.RemoveConnectedExternalGroup(ctx, "\n", "\n")
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		return client.Teams.RemoveConnectedExternalGroup(ctx, "o", "t")
+	})
+}
+
+func TestTeamsService_RemoveConnectedExternalGroup_notFound(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/orgs/o/teams/t/external-groups", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "DELETE")
+		w.WriteHeader(http.StatusNotFound)
+	})
+
+	ctx := context.Background()
+	resp, err := client.Teams.RemoveConnectedExternalGroup(ctx, "o", "t")
+	if err == nil {
+		t.Errorf("Expected HTTP 404 response")
+	}
+	if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want {
+		t.Errorf("Teams.GetExternalGroup returned status %d, want %d", got, want)
+	}
+}