Repository: google/go-github
Pull request #2038 (2021-08-11 12:58:10)

Add struct for workflow_job event
This is a new (as of now undocumented) event that has been darkshipped by GitHub.

It provides three actions: queued, started and completed, reusing the existing WorkflowJob struct.

Official documentation is supposedly soon to follow, but advance submission of this PR has been approved by GitHub staff.

You can hold up this PR until it drops. I will update it accordingly.

google-cla[bot]: 
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

:memo: **Please visit <https://cla.developers.google.com/> to sign.**

Once you've signed (or fixed any issues), please reply here with `@googlebot I signed it!` and we'll verify it.

----

#### What to do if you already signed the CLA

##### Individual signers

*   It's possible we don't have your GitHub username or you're using a different email address on your commit. Check [your existing CLA data](https://cla.developers.google.com/clas) and verify that your [email is set on your git commits](https://help.github.com/articles/setting-your-email-in-git/).

##### Corporate signers

*   Your company has a Point of Contact who decides which employees are authorized to participate. Ask your POC to be added to the group of authorized contributors. If you don't know who your Point of Contact is, direct the Google project maintainer to [go/cla#troubleshoot](http://go/cla#troubleshoot) ([Public version](https://opensource.google/docs/cla/#troubleshoot)).
*   The email used to register you as an authorized contributor must be the email used for the Git commit. Check [your existing CLA data](https://cla.developers.google.com/clas) and verify that your [email is set on your git commits](https://help.github.com/articles/setting-your-email-in-git/).
*   The email used to register you as an authorized contributor must also be [attached to your GitHub account](https://github.com/settings/emails).
		

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogle%2Fgo-github%2Fpull%2F2038) for more info**.

<!-- need_sender_cla -->
acuteaura: @googlebot I signed it!
codecov[bot]: # [Codecov](https://codecov.io/gh/google/go-github/pull/2038?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google) Report
> Merging [#2038](https://codecov.io/gh/google/go-github/pull/2038?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google) (6bd26aa) into [master](https://codecov.io/gh/google/go-github/commit/95b92df83a47fc0627dd3030f58172db433cfce7?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google) (95b92df) will **not change** coverage.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/google/go-github/pull/2038/graphs/tree.svg?width=650&height=150&src=pr&token=EgYjGjZlI0&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google)](https://codecov.io/gh/google/go-github/pull/2038?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google)

```diff
@@           Coverage Diff           @@
##           master    #2038   +/-   ##
=======================================
  Coverage   97.87%   97.87%           
=======================================
  Files         107      107           
  Lines        6907     6907           
=======================================
  Hits         6760     6760           
  Misses         81       81           
  Partials       66       66           
```


| [Impacted Files](https://codecov.io/gh/google/go-github/pull/2038?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google) | Coverage Δ | |
|---|---|---|
| [github/event\_types.go](https://codecov.io/gh/google/go-github/pull/2038/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google#diff-Z2l0aHViL2V2ZW50X3R5cGVzLmdv) | `100.00% <ø> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/google/go-github/pull/2038?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/google/go-github/pull/2038?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google). Last update [95b92df...6bd26aa](https://codecov.io/gh/google/go-github/pull/2038?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google).


Patch:
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000..d4960c13
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,18 @@
+version: 2
+updates:
+- package-ecosystem: gomod
+  directory: /
+  schedule:
+    interval: weekly
+- package-ecosystem: gomod
+  directory: scrape
+  schedule:
+    interval: weekly
+- package-ecosystem: gomod
+  directory: update-urls
+  schedule:
+    interval: weekly
+- package-ecosystem: github-actions
+  directory: /
+  schedule:
+    interval: weekly
diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml
new file mode 100644
index 00000000..5f35fac3
--- /dev/null
+++ b/.github/workflows/linter.yml
@@ -0,0 +1,19 @@
+on: [push, pull_request]
+name: linter
+
+jobs:
+  lint:
+    strategy:
+      matrix:
+        go-version: [1.x]
+        platform: [ubuntu-latest]
+    runs-on: ${{ matrix.platform }}
+
+    steps:
+    - uses: actions/checkout@v2
+
+    - name: golangci-lint
+      uses: golangci/golangci-lint-action@5c56cd6c9dc07901af25baab6f2b0d9f3b7c3018 #v2.5.2
+      with:
+        version: v1.41
+        args: --verbose
diff --git a/.gitignore b/.gitignore
index 3d439783..aea73858 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,5 @@ coverage.out
 # intellij files
 .idea/
 vendor/
-.DS_Store
\ No newline at end of file
+.DS_Store
+.vscode
\ No newline at end of file
diff --git a/.golangci.yml b/.golangci.yml
new file mode 100644
index 00000000..afd9675f
--- /dev/null
+++ b/.golangci.yml
@@ -0,0 +1,32 @@
+linters:
+  # TODO: fix errors so that all of the linters below pass.
+  # The linters that are commented out, as well as those explicitly disabled,
+  # are currently failing.  We should fix those failures or define exclusion
+  # rules, and then enable those linters.
+  enable:
+    - dogsled
+    - dupl
+    - gofmt
+    - goimports
+  # - gosec
+    - misspell
+    - nakedret
+  # - stylecheck
+  # - unconvert
+  # - unparam
+  # - whitespace
+  disable:
+    - errcheck
+    - gosimple
+    - staticcheck
+    - ineffassign
+    - unused
+issues: 
+  exclude-rules:
+  - linters:
+    - dogsled
+    text:  "declaration has 3 blank identifiers"
+    path: _test\.go
+  - linters:
+    - dupl
+    path: _test\.go
diff --git a/github/activity_notifications.go b/github/activity_notifications.go
index 9b6fbe2b..009cc5e3 100644
--- a/github/activity_notifications.go
+++ b/github/activity_notifications.go
@@ -51,7 +51,7 @@ type NotificationListOptions struct {
 //
 // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/activity/#list-notifications-for-the-authenticated-user
 func (s *ActivityService) ListNotifications(ctx context.Context, opts *NotificationListOptions) ([]*Notification, *Response, error) {
-	u := fmt.Sprintf("notifications")
+	u := "notifications"
 	u, err := addOptions(u, opts)
 	if err != nil {
 		return nil, nil, err
diff --git a/github/doc.go b/github/doc.go
index d85d254c..8999a126 100644
--- a/github/doc.go
+++ b/github/doc.go
@@ -112,7 +112,7 @@ To detect an API rate limit error, you can check if its type is *github.RateLimi
 	}
 
 Learn more about GitHub rate limiting at
-https://docs.github.com/en/free-pro-team@latest/rest/reference/#rate-limiting.
+https://docs.github.com/en/free-pro-team@latest/rest/overview/resources-in-the-rest-api#rate-limiting.
 
 Accepted Status
 
@@ -138,7 +138,7 @@ instead designed to work with a caching http.Transport. We recommend using
 https://github.com/gregjones/httpcache for that.
 
 Learn more about GitHub conditional requests at
-https://docs.github.com/en/free-pro-team@latest/rest/reference/#conditional-requests.
+https://docs.github.com/en/free-pro-team@latest/rest/overview/resources-in-the-rest-api#conditional-requests.
 
 Creating and Updating Resources
 
diff --git a/github/event.go b/github/event.go
index 4b87142a..8f1a0f2e 100644
--- a/github/event.go
+++ b/github/event.go
@@ -124,6 +124,8 @@ func (e *Event) ParsePayload() (payload interface{}, err error) {
 		payload = &WatchEvent{}
 	case "WorkflowDispatchEvent":
 		payload = &WorkflowDispatchEvent{}
+	case "WorkflowJobEvent":
+		payload = &WorkflowJobEvent{}
 	case "WorkflowRunEvent":
 		payload = &WorkflowRunEvent{}
 	}
diff --git a/github/event_types.go b/github/event_types.go
index f99a1296..384aa3a1 100644
--- a/github/event_types.go
+++ b/github/event_types.go
@@ -1083,6 +1083,20 @@ type WorkflowDispatchEvent struct {
 	Sender *User         `json:"sender,omitempty"`
 }
 
+// WorkflowJobEvent is triggered when a job is queued, started or completed.
+//
+// GitHub API docs: pending
+type WorkflowJobEvent struct {
+	WorkflowJob *WorkflowJob `json:"workflow_job,omitempty"`
+
+	Action *string `json:"action,omitempty"`
+
+	// The following fields are only populated by Webhook events.
+	Org    *Organization `json:"organization,omitempty"`
+	Repo   *Repository   `json:"repository,omitempty"`
+	Sender *User         `json:"sender,omitempty"`
+}
+
 // WorkflowRunEvent is triggered when a GitHub Actions workflow run is requested or completed.
 //
 // GitHub API docs: https://docs.github.com/en/developers/webhooks-and-events/webhook-events-and-payloads#workflow_run
diff --git a/github/github-accessors.go b/github/github-accessors.go
index 37a22830..b0169cbb 100644
--- a/github/github-accessors.go
+++ b/github/github-accessors.go
@@ -1188,6 +1188,46 @@ func (a *AuthorizationUpdateRequest) GetNoteURL() string {
 	return *a.NoteURL
 }
 
+// GetID returns the ID field if it's non-nil, zero value otherwise.
+func (a *Autolink) GetID() int64 {
+	if a == nil || a.ID == nil {
+		return 0
+	}
+	return *a.ID
+}
+
+// GetKeyPrefix returns the KeyPrefix field if it's non-nil, zero value otherwise.
+func (a *Autolink) GetKeyPrefix() string {
+	if a == nil || a.KeyPrefix == nil {
+		return ""
+	}
+	return *a.KeyPrefix
+}
+
+// GetURLTemplate returns the URLTemplate field if it's non-nil, zero value otherwise.
+func (a *Autolink) GetURLTemplate() string {
+	if a == nil || a.URLTemplate == nil {
+		return ""
+	}
+	return *a.URLTemplate
+}
+
+// GetKeyPrefix returns the KeyPrefix field if it's non-nil, zero value otherwise.
+func (a *AutolinkOptions) GetKeyPrefix() string {
+	if a == nil || a.KeyPrefix == nil {
+		return ""
+	}
+	return *a.KeyPrefix
+}
+
+// GetURLTemplate returns the URLTemplate field if it's non-nil, zero value otherwise.
+func (a *AutolinkOptions) GetURLTemplate() string {
+	if a == nil || a.URLTemplate == nil {
+		return ""
+	}
+	return *a.URLTemplate
+}
+
 // GetAppID returns the AppID field if it's non-nil, zero value otherwise.
 func (a *AutoTriggerCheck) GetAppID() int64 {
 	if a == nil || a.AppID == nil {
@@ -4708,6 +4748,14 @@ func (g *GPGKey) GetPublicKey() string {
 	return *g.PublicKey
 }
 
+// GetRawKey returns the RawKey field if it's non-nil, zero value otherwise.
+func (g *GPGKey) GetRawKey() string {
+	if g == nil || g.RawKey == nil {
+		return ""
+	}
+	return *g.RawKey
+}
+
 // GetApp returns the App field.
 func (g *Grant) GetApp() *AuthorizationApp {
 	if g == nil {
@@ -7172,6 +7220,30 @@ func (l *ListRepositories) GetTotalCount() int {
 	return *l.TotalCount
 }
 
+// GetCount returns the Count field if it's non-nil, zero value otherwise.
+func (l *ListSCIMProvisionedIdentitiesOptions) GetCount() int {
+	if l == nil || l.Count == nil {
+		return 0
+	}
+	return *l.Count
+}
+
+// GetFilter returns the Filter field if it's non-nil, zero value otherwise.
+func (l *ListSCIMProvisionedIdentitiesOptions) GetFilter() string {
+	if l == nil || l.Filter == nil {
+		return ""
+	}
+	return *l.Filter
+}
+
+// GetStartIndex returns the StartIndex field if it's non-nil, zero value otherwise.
+func (l *ListSCIMProvisionedIdentitiesOptions) GetStartIndex() int {
+	if l == nil || l.StartIndex == nil {
+		return 0
+	}
+	return *l.StartIndex
+}
+
 // GetEndColumn returns the EndColumn field if it's non-nil, zero value otherwise.
 func (l *Location) GetEndColumn() int {
 	if l == nil || l.EndColumn == nil {
@@ -12556,6 +12628,14 @@ func (r *RepositoriesSearchResult) GetTotal() int {
 	return *r.Total
 }
 
+// GetAllowAutoMerge returns the AllowAutoMerge field if it's non-nil, zero value otherwise.
+func (r *Repository) GetAllowAutoMerge() bool {
+	if r == nil || r.AllowAutoMerge == nil {
+		return false
+	}
+	return *r.AllowAutoMerge
+}
+
 // GetAllowMergeCommit returns the AllowMergeCommit field if it's non-nil, zero value otherwise.
 func (r *Repository) GetAllowMergeCommit() bool {
 	if r == nil || r.AllowMergeCommit == nil {
@@ -14564,6 +14644,54 @@ func (r *RunnerLabels) GetType() string {
 	return *r.Type
 }
 
+// GetActive returns the Active field if it's non-nil, zero value otherwise.
+func (s *SCIMUserAttributes) GetActive() bool {
+	if s == nil || s.Active == nil {
+		return false
+	}
+	return *s.Active
+}
+
+// GetDisplayName returns the DisplayName field if it's non-nil, zero value otherwise.
+func (s *SCIMUserAttributes) GetDisplayName() string {
+	if s == nil || s.DisplayName == nil {
+		return ""
+	}
+	return *s.DisplayName
+}
+
+// GetExternalID returns the ExternalID field if it's non-nil, zero value otherwise.
+func (s *SCIMUserAttributes) GetExternalID() string {
+	if s == nil || s.ExternalID == nil {
+		return ""
+	}
+	return *s.ExternalID
+}
+
+// GetPrimary returns the Primary field if it's non-nil, zero value otherwise.
+func (s *SCIMUserEmail) GetPrimary() bool {
+	if s == nil || s.Primary == nil {
+		return false
+	}
+	return *s.Primary
+}
+
+// GetType returns the Type field if it's non-nil, zero value otherwise.
+func (s *SCIMUserEmail) GetType() string {
+	if s == nil || s.Type == nil {
+		return ""
+	}
+	return *s.Type
+}
+
+// GetFormatted returns the Formatted field if it's non-nil, zero value otherwise.
+func (s *SCIMUserName) GetFormatted() string {
+	if s == nil || s.Formatted == nil {
+		return ""
+	}
+	return *s.Formatted
+}
+
 // GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise.
 func (s *SelectedReposList) GetTotalCount() int {
 	if s == nil || s.TotalCount == nil {
@@ -16108,6 +16236,14 @@ func (t *TreeEntry) GetURL() string {
 	return *t.URL
 }
 
+// GetPath returns the Path field if it's non-nil, zero value otherwise.
+func (u *UpdateAttributeForSCIMUserOperations) GetPath() string {
+	if u == nil || u.Path == nil {
+		return ""
+	}
+	return *u.Path
+}
+
 // GetCompletedAt returns the CompletedAt field if it's non-nil, zero value otherwise.
 func (u *UpdateCheckRunOptions) GetCompletedAt() Timestamp {
 	if u == nil || u.CompletedAt == nil {
@@ -17452,6 +17588,46 @@ func (w *WorkflowJob) GetURL() string {
 	return *w.URL
 }
 
+// GetAction returns the Action field if it's non-nil, zero value otherwise.
+func (w *WorkflowJobEvent) GetAction() string {
+	if w == nil || w.Action == nil {
+		return ""
+	}
+	return *w.Action
+}
+
+// GetOrg returns the Org field.
+func (w *WorkflowJobEvent) GetOrg() *Organization {
+	if w == nil {
+		return nil
+	}
+	return w.Org
+}
+
+// GetRepo returns the Repo field.
+func (w *WorkflowJobEvent) GetRepo() *Repository {
+	if w == nil {
+		return nil
+	}
+	return w.Repo
+}
+
+// GetSender returns the Sender field.
+func (w *WorkflowJobEvent) GetSender() *User {
+	if w == nil {
+		return nil
+	}
+	return w.Sender
+}
+
+// GetWorkflowJob returns the WorkflowJob field.
+func (w *WorkflowJobEvent) GetWorkflowJob() *WorkflowJob {
+	if w == nil {
+		return nil
+	}
+	return w.WorkflowJob
+}
+
 // GetArtifactsURL returns the ArtifactsURL field if it's non-nil, zero value otherwise.
 func (w *WorkflowRun) GetArtifactsURL() string {
 	if w == nil || w.ArtifactsURL == nil {
diff --git a/github/github.go b/github/github.go
index fe686857..b83e4306 100644
--- a/github/github.go
+++ b/github/github.go
@@ -181,6 +181,7 @@ type Client struct {
 	PullRequests   *PullRequestsService
 	Reactions      *ReactionsService
 	Repositories   *RepositoriesService
+	SCIM           *SCIMService
 	Search         *SearchService
 	Teams          *TeamsService
 	Users          *UsersService
@@ -308,6 +309,7 @@ func NewClient(httpClient *http.Client) *Client {
 	c.PullRequests = (*PullRequestsService)(&c.common)
 	c.Reactions = (*ReactionsService)(&c.common)
 	c.Repositories = (*RepositoriesService)(&c.common)
+	c.SCIM = (*SCIMService)(&c.common)
 	c.Search = (*SearchService)(&c.common)
 	c.Teams = (*TeamsService)(&c.common)
 	c.Users = (*UsersService)(&c.common)
@@ -458,7 +460,7 @@ type Response struct {
 	// calling the endpoint again.
 	NextPageToken string
 
-	// For APIs that support cursor pagination, such as RepositoryService.ListRepositoryHookDeliveries,
+	// For APIs that support cursor pagination, such as RepositoriesService.ListHookDeliveries,
 	// the following field will be populated to point to the next page.
 	// Set ListCursorOptions.Cursor to this value when calling the endpoint again.
 	Cursor string
diff --git a/github/messages.go b/github/messages.go
index caa596a2..e46435c9 100644
--- a/github/messages.go
+++ b/github/messages.go
@@ -92,6 +92,7 @@ var (
 		"user":                           "UserEvent",
 		"watch":                          "WatchEvent",
 		"workflow_dispatch":              "WorkflowDispatchEvent",
+		"workflow_job":                   "WorkflowJobEvent",
 		"workflow_run":                   "WorkflowRunEvent",
 	}
 )
diff --git a/github/orgs_hooks_deliveries.go b/github/orgs_hooks_deliveries.go
index 6ab2d7aa..d1fb5c83 100644
--- a/github/orgs_hooks_deliveries.go
+++ b/github/orgs_hooks_deliveries.go
@@ -52,3 +52,22 @@ func (s *OrganizationsService) GetHookDelivery(ctx context.Context, owner string
 
 	return h, resp, nil
 }
+
+// RedeliverHookDelivery redelivers a delivery for a webhook configured in an organization.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/orgs#redeliver-a-delivery-for-an-organization-webhook
+func (s *OrganizationsService) RedeliverHookDelivery(ctx context.Context, owner string, hookID, deliveryID int64) (*HookDelivery, *Response, error) {
+	u := fmt.Sprintf("orgs/%v/hooks/%v/deliveries/%v/attempts", owner, hookID, deliveryID)
+	req, err := s.client.NewRequest("POST", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	h := new(HookDelivery)
+	resp, err := s.client.Do(ctx, req, h)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return h, resp, nil
+}
diff --git a/github/repos.go b/github/repos.go
index eaadbb43..aab18d4d 100644
--- a/github/repos.go
+++ b/github/repos.go
@@ -60,6 +60,7 @@ type Repository struct {
 	AllowRebaseMerge    *bool           `json:"allow_rebase_merge,omitempty"`
 	AllowSquashMerge    *bool           `json:"allow_squash_merge,omitempty"`
 	AllowMergeCommit    *bool           `json:"allow_merge_commit,omitempty"`
+	AllowAutoMerge      *bool           `json:"allow_auto_merge,omitempty"`
 	DeleteBranchOnMerge *bool           `json:"delete_branch_on_merge,omitempty"`
 	Topics              []string        `json:"topics,omitempty"`
 	Archived            *bool           `json:"archived,omitempty"`
@@ -320,6 +321,7 @@ type createRepoRequest struct {
 	AllowSquashMerge    *bool   `json:"allow_squash_merge,omitempty"`
 	AllowMergeCommit    *bool   `json:"allow_merge_commit,omitempty"`
 	AllowRebaseMerge    *bool   `json:"allow_rebase_merge,omitempty"`
+	AllowAutoMerge      *bool   `json:"allow_auto_merge,omitempty"`
 	DeleteBranchOnMerge *bool   `json:"delete_branch_on_merge,omitempty"`
 }
 
@@ -362,6 +364,7 @@ func (s *RepositoriesService) Create(ctx context.Context, org string, repo *Repo
 		AllowSquashMerge:    repo.AllowSquashMerge,
 		AllowMergeCommit:    repo.AllowMergeCommit,
 		AllowRebaseMerge:    repo.AllowRebaseMerge,
+		AllowAutoMerge:      repo.AllowAutoMerge,
 		DeleteBranchOnMerge: repo.DeleteBranchOnMerge,
 	}
 
diff --git a/github/repos_autolinks.go b/github/repos_autolinks.go
new file mode 100644
index 00000000..b6404783
--- /dev/null
+++ b/github/repos_autolinks.go
@@ -0,0 +1,102 @@
+// Copyright 2021 The go-github AUTHORS. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package github
+
+import (
+	"context"
+	"fmt"
+)
+
+// AutolinkOptions specifies parameters for RepositoriesService.AddAutolink method.
+type AutolinkOptions struct {
+	KeyPrefix   *string `json:"key_prefix,omitempty"`
+	URLTemplate *string `json:"url_template,omitempty"`
+}
+
+// Autolink represents autolinks to external resources like JIRA issues and Zendesk tickets.
+type Autolink struct {
+	ID          *int64  `json:"id,omitempty"`
+	KeyPrefix   *string `json:"key_prefix,omitempty"`
+	URLTemplate *string `json:"url_template,omitempty"`
+}
+
+// ListAutolinks returns a list of autolinks configured for the given repository.
+// Information about autolinks are only available to repository administrators.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/repos#list-all-autolinks-of-a-repository
+func (s *RepositoriesService) ListAutolinks(ctx context.Context, owner, repo string, opts *ListOptions) ([]*Autolink, *Response, error) {
+	u := fmt.Sprintf("repos/%v/%v/autolinks", owner, repo)
+	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
+	}
+
+	var autolinks []*Autolink
+	resp, err := s.client.Do(ctx, req, &autolinks)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return autolinks, resp, nil
+}
+
+// AddAutolink creates an autolink reference for a repository.
+// Users with admin access to the repository can create an autolink.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/repos#create-an-autolink-reference-for-a-repository
+func (s *RepositoriesService) AddAutolink(ctx context.Context, owner, repo string, opts *AutolinkOptions) (*Autolink, *Response, error) {
+	u := fmt.Sprintf("repos/%v/%v/autolinks", owner, repo)
+	req, err := s.client.NewRequest("POST", u, opts)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	al := new(Autolink)
+	resp, err := s.client.Do(ctx, req, al)
+	if err != nil {
+		return nil, resp, err
+	}
+	return al, resp, nil
+}
+
+// GetAutolink returns a single autolink reference by ID that was configured for the given repository.
+// Information about autolinks are only available to repository administrators.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/repos#get-an-autolink-reference-of-a-repository
+func (s *RepositoriesService) GetAutolink(ctx context.Context, owner, repo string, id int64) (*Autolink, *Response, error) {
+	u := fmt.Sprintf("repos/%v/%v/autolinks/%v", owner, repo, id)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var autolink *Autolink
+	resp, err := s.client.Do(ctx, req, &autolink)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return autolink, resp, nil
+}
+
+// DeleteAutolink deletes a single autolink reference by ID that was configured for the given repository.
+// Information about autolinks are only available to repository administrators.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/repos#delete-an-autolink-reference-from-a-repository
+func (s *RepositoriesService) DeleteAutolink(ctx context.Context, owner, repo string, id int64) (*Response, error) {
+	u := fmt.Sprintf("repos/%v/%v/autolinks/%v", owner, repo, id)
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+	return s.client.Do(ctx, req, nil)
+}
diff --git a/github/scim.go b/github/scim.go
new file mode 100644
index 00000000..7a12d85b
--- /dev/null
+++ b/github/scim.go
@@ -0,0 +1,163 @@
+// Copyright 2021 The go-github AUTHORS. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package github
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+)
+
+// SCIMService provides access to SCIM related functions in the
+// GitHub API.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/scim
+type SCIMService service
+
+// SCIMUserAttributes represents supported SCIM User attributes.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/scim#supported-scim-user-attributes
+type SCIMUserAttributes struct {
+	UserName    string           `json:"userName"`              // Configured by the admin. Could be an email, login, or username. (Required.)
+	Name        SCIMUserName     `json:"name"`                  // (Required.)
+	DisplayName *string          `json:"displayName,omitempty"` // The name of the user, suitable for display to end-users. (Optional.)
+	Emails      []*SCIMUserEmail `json:"emails"`                // User emails. (Required.)
+	Schemas     []string         `json:"schemas,omitempty"`     // (Optional.)
+	ExternalID  *string          `json:"externalId,omitempty"`  // (Optional.)
+	Groups      []string         `json:"groups,omitempty"`      // (Optional.)
+	Active      *bool            `json:"active,omitempty"`      // (Optional.)
+}
+
+// SCIMUserName represents SCIM user information.
+type SCIMUserName struct {
+	GivenName  string  `json:"givenName"`           // The first name of the user. (Required.)
+	FamilyName string  `json:"familyName"`          // The family name of the user. (Required.)
+	Formatted  *string `json:"formatted,omitempty"` // (Optional.)
+}
+
+//SCIMUserEmail represents SCIM user email.
+type SCIMUserEmail struct {
+	Value   string  `json:"value"`             // (Required.)
+	Primary *bool   `json:"primary,omitempty"` // (Optional.)
+	Type    *string `json:"type,omitempty"`    // (Optional.)
+}
+
+// ListSCIMProvisionedIdentitiesOptions represents options for ListSCIMProvisionedIdentities.
+//
+// Github API docs: https://docs.github.com/en/rest/reference/scim#list-scim-provisioned-identities--parameters
+type ListSCIMProvisionedIdentitiesOptions struct {
+	StartIndex *int `json:"startIndex,omitempty"` // Used for pagination: the index of the first result to return. (Optional.)
+	Count      *int `json:"count,omitempty"`      // Used for pagination: the number of results to return. (Optional.)
+	// Filter results using the equals query parameter operator (eq).
+	// You can filter results that are equal to id, userName, emails, and external_id.
+	// For example, to search for an identity with the userName Octocat, you would use this query: ?filter=userName%20eq%20\"Octocat\".
+	// To filter results for the identity with the email octocat@github.com, you would use this query: ?filter=emails%20eq%20\"octocat@github.com\".
+	// (Optional.)
+	Filter *string `json:"filter,omitempty"`
+}
+
+// ListSCIMProvisionedIdentities lists SCIM provisioned identities.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/scim#list-scim-provisioned-identities
+func (s *SCIMService) ListSCIMProvisionedIdentities(ctx context.Context, org string, opts *ListSCIMProvisionedIdentitiesOptions) (*Response, error) {
+	u := fmt.Sprintf("scim/v2/organizations/%v/Users", org)
+	u, err := addOptions(u, opts)
+	if err != nil {
+		return nil, err
+	}
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, err
+	}
+	return s.client.Do(ctx, req, nil)
+}
+
+// ProvisionAndInviteSCIMUser provisions organization membership for a user, and sends an activation email to the email address.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/scim#provision-and-invite-a-scim-user
+func (s *SCIMService) ProvisionAndInviteSCIMUser(ctx context.Context, org string, opts *SCIMUserAttributes) (*Response, error) {
+	u := fmt.Sprintf("scim/v2/organizations/%v/Users", org)
+	u, err := addOptions(u, opts)
+	if err != nil {
+		return nil, err
+	}
+	req, err := s.client.NewRequest("POST", u, nil)
+	if err != nil {
+		return nil, err
+	}
+	return s.client.Do(ctx, req, nil)
+}
+
+// GetSCIMProvisioningInfoForUser returns SCIM provisioning information for a user.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/scim#get-scim-provisioning-information-for-a-user
+func (s *SCIMService) GetSCIMProvisioningInfoForUser(ctx context.Context, org, scimUserID string) (*Response, error) {
+	u := fmt.Sprintf("scim/v2/organizations/%v/Users/%v", org, scimUserID)
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, err
+	}
+	return s.client.Do(ctx, req, nil)
+}
+
+// UpdateProvisionedOrgMembership updates a provisioned organization membership.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/scim#update-a-provisioned-organization-membership
+func (s *SCIMService) UpdateProvisionedOrgMembership(ctx context.Context, org, scimUserID string, opts *SCIMUserAttributes) (*Response, error) {
+	u := fmt.Sprintf("scim/v2/organizations/%v/Users/%v", org, scimUserID)
+	u, err := addOptions(u, opts)
+	if err != nil {
+		return nil, err
+	}
+	req, err := s.client.NewRequest("PUT", u, nil)
+	if err != nil {
+		return nil, err
+	}
+	return s.client.Do(ctx, req, nil)
+}
+
+// UpdateAttributeForSCIMUserOptions represents options for UpdateAttributeForSCIMUser.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/scim#update-an-attribute-for-a-scim-user--parameters
+type UpdateAttributeForSCIMUserOptions struct {
+	Schemas    []string                             `json:"schemas,omitempty"` // (Optional.)
+	Operations UpdateAttributeForSCIMUserOperations `json:"operations"`        // Set of operations to be performed. (Required.)
+}
+
+// UpdateAttributeForSCIMUserOperations represents operations for UpdateAttributeForSCIMUser.
+type UpdateAttributeForSCIMUserOperations struct {
+	Op    string          `json:"op"`              // (Required.)
+	Path  *string         `json:"path,omitempty"`  // (Optional.)
+	Value json.RawMessage `json:"value,omitempty"` // (Optional.)
+}
+
+// UpdateAttributeForSCIMUser updates an attribute for an SCIM user.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/scim#update-an-attribute-for-a-scim-user
+func (s *SCIMService) UpdateAttributeForSCIMUser(ctx context.Context, org, scimUserID string, opts *UpdateAttributeForSCIMUserOptions) (*Response, error) {
+	u := fmt.Sprintf("scim/v2/organizations/%v/Users/%v", org, scimUserID)
+	u, err := addOptions(u, opts)
+	if err != nil {
+		return nil, err
+	}
+	req, err := s.client.NewRequest("PATCH", u, nil)
+	if err != nil {
+		return nil, err
+	}
+	return s.client.Do(ctx, req, nil)
+}
+
+// DeleteSCIMUserFromOrg deletes SCIM user from an organization.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/scim#delete-a-scim-user-from-an-organization
+func (s *SCIMService) DeleteSCIMUserFromOrg(ctx context.Context, org, scimUserID string) (*Response, error) {
+	u := fmt.Sprintf("scim/v2/organizations/%v/Users/%v", org, scimUserID)
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+	return s.client.Do(ctx, req, nil)
+}
diff --git a/github/users_gpg_keys.go b/github/users_gpg_keys.go
index 34174789..387cc9b0 100644
--- a/github/users_gpg_keys.go
+++ b/github/users_gpg_keys.go
@@ -18,6 +18,7 @@ type GPGKey struct {
 	ID                *int64      `json:"id,omitempty"`
 	PrimaryKeyID      *int64      `json:"primary_key_id,omitempty"`
 	KeyID             *string     `json:"key_id,omitempty"`
+	RawKey            *string     `json:"raw_key,omitempty"`
 	PublicKey         *string     `json:"public_key,omitempty"`
 	Emails            []*GPGEmail `json:"emails,omitempty"`
 	Subkeys           []*GPGKey   `json:"subkeys,omitempty"`
diff --git a/go.mod b/go.mod
index 50d0421d..91d67881 100644
--- a/go.mod
+++ b/go.mod
@@ -3,11 +3,10 @@ module github.com/google/go-github/v38
 require (
 	github.com/golang/protobuf v1.3.2 // indirect
 	github.com/google/go-cmp v0.5.6
-	github.com/google/go-querystring v1.0.0
-	golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
-	golang.org/x/net v0.0.0-20190311183353-d8887717615a // indirect
+	github.com/google/go-querystring v1.1.0
+	golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
 	golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be
-	google.golang.org/appengine v1.1.0
+	google.golang.org/appengine v1.6.7
 )
 
 go 1.16
diff --git a/go.sum b/go.sum
index bbc4342c..7e85c44d 100644
--- a/go.sum
+++ b/go.sum
@@ -1,19 +1,30 @@
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
 github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
-github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
+github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
+github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
+golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs=
-google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
+google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
diff --git a/scrape/go.mod b/scrape/go.mod
index 11b104a5..ee95c062 100644
--- a/scrape/go.mod
+++ b/scrape/go.mod
@@ -3,9 +3,9 @@ module github.com/google/go-github/scrape
 go 1.13
 
 require (
-	github.com/PuerkitoBio/goquery v1.5.0
-	github.com/google/go-cmp v0.3.1
+	github.com/PuerkitoBio/goquery v1.7.1
+	github.com/google/go-cmp v0.5.6
 	github.com/google/go-github/v32 v32.1.0
 	github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119
-	golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582
+	golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d
 )
diff --git a/scrape/go.sum b/scrape/go.sum
index eba0cdd3..f20e765a 100644
--- a/scrape/go.sum
+++ b/scrape/go.sum
@@ -1,10 +1,10 @@
-github.com/PuerkitoBio/goquery v1.5.0 h1:uGvmFXOA73IKluu/F84Xd1tt/z07GYm8X49XKHP7EJk=
-github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg=
-github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o=
-github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
+github.com/PuerkitoBio/goquery v1.7.1 h1:oE+T06D+1T7LNrn91B4aERsRIeCLJ/oPSa6xB9FPnz4=
+github.com/PuerkitoBio/goquery v1.7.1/go.mod h1:XY0pP4kfraEmmV1O7Uf6XyjoslwsneBbgeDjLYuN8xY=
+github.com/andybalholm/cascadia v1.2.0 h1:vuRCkM5Ozh/BfmsaTm26kbjm0mIOM3yS5Ek/F5h18aE=
+github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxBp0T0eFw1RUQY=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II=
 github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
 github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
@@ -14,11 +14,18 @@ github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119/go.mod h1:/nuTSlK+okRfR/
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 h1:p9xBe/w/OzkeYVKm234g55gMdD1nSIooTir5kV11kfA=
-golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c=
+golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
diff --git a/update-urls/go.mod b/update-urls/go.mod
index 7c133f85..53666db8 100644
--- a/update-urls/go.mod
+++ b/update-urls/go.mod
@@ -2,4 +2,7 @@ module github.com/google/go-github/update-urls
 
 go 1.16
 
-require github.com/pmezard/go-difflib v1.0.0
+require (
+	github.com/google/go-cmp v0.5.6
+	github.com/pmezard/go-difflib v1.0.0
+)
diff --git a/update-urls/go.sum b/update-urls/go.sum
index 5d60ca74..cbfdfa22 100644
--- a/update-urls/go.sum
+++ b/update-urls/go.sum
@@ -1,2 +1,6 @@
+github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/update-urls/main.go b/update-urls/main.go
index a82ffbd9..248c7104 100644
--- a/update-urls/main.go
+++ b/update-urls/main.go
@@ -126,7 +126,9 @@ func main() {
 	}
 
 	if err := os.Chdir("./github"); err != nil {
-		log.Fatalf("Please run this from the go-github directory.")
+		if err := os.Chdir("../github"); err != nil {
+			log.Fatalf("Please run this from the go-github directory.")
+		}
 	}
 
 	pkgs, err := parser.ParseDir(fset, ".", sourceFilter, parser.ParseComments)
@@ -427,7 +429,7 @@ func (rafi *realAstFileIterator) Reset() {
 		var count int
 		for _, pkg := range rafi.pkgs {
 			for filename, f := range pkg.Files {
-				logf("Sending file #%v: %v to channel", count, filename)
+				// logf("Sending file #%v: %v to channel", count, filename)
 				rafi.ch <- &filenameAstFilePair{filename: filename, astFile: f}
 				count++
 			}
@@ -443,7 +445,7 @@ func (rafi *realAstFileIterator) Reset() {
 
 func (rafi *realAstFileIterator) Next() *filenameAstFilePair {
 	for pair := range rafi.ch {
-		logf("Next: returning file %v", pair.filename)
+		// logf("Next: returning file %v", pair.filename)
 		return pair
 	}
 	return nil
@@ -704,7 +706,7 @@ func processAST(filename string, f *ast.File, services servicesMap, endpoints en
 
 			receiverName := recv.Names[0].Name
 
-			logf("ast.FuncDecl: %#v", *decl)           // Doc, Recv, Name, Type, Body
+			logf("\n\nast.FuncDecl: %#v", *decl)       // Doc, Recv, Name, Type, Body
 			logf("ast.FuncDecl.Name: %#v", *decl.Name) // NamePos, Name, Obj(nil)
 			// logf("ast.FuncDecl.Recv: %#v", *decl.Recv)  // Opening, List, Closing
 			logf("ast.FuncDecl.Recv.List[0]: %#v", *recv) // Doc, Names, Type, Tag, Comment
@@ -1055,8 +1057,10 @@ func processCallExpr(expr *ast.CallExpr) (recv, funcName string, args []string)
 		case *ast.SelectorExpr: // X, Sel
 			logf("processCallExpr: X recv *ast.SelectorExpr: %#v", x.Sel)
 			recv = x.Sel.Name
+		case *ast.CallExpr: // Fun, LParen, Args, Ellipsis, RParen
+			logf("processCallExpr: X recv *ast.CallExpr: %#v", x)
 		default:
-			log.Fatalf("processCallExpr: unhandled X receiver type: %T", x)
+			log.Fatalf("processCallExpr: unhandled X receiver type: %T, funcName=%q", x, funcName)
 		}
 	default:
 		log.Fatalf("processCallExpr: unhandled Fun: %T", expr.Fun)
@@ -1191,9 +1195,7 @@ func parseEndpoint(s, method string) *Endpoint {
 	// 	eol = v
 	// }
 	path := strings.TrimSpace(s[len(method):eol])
-	if strings.HasPrefix(path, "{server}") { // Hack to remove {server}
-		path = strings.TrimPrefix(path, "{server}")
-	}
+	path = strings.TrimPrefix(path, "{server}")
 	path = paramLegacyRE.ReplaceAllString(path, "%v")
 	path = paramRE.ReplaceAllString(path, "%v")
 	// strip leading garbage


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 2b354674..f360911c 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -30,7 +30,7 @@ jobs:
 
     steps:
     - name: Cancel previous
-      uses: styfle/cancel-workflow-action@89f242ee29e10c53a841bfe71cc0ce7b2f065abc #0.9.0
+      uses: styfle/cancel-workflow-action@a40b8845c0683271d9f53dfcb887a7e181d3918b #0.9.1
       with:
         access_token: ${{ github.token }}
 
@@ -39,23 +39,24 @@ jobs:
         go-version: ${{ matrix.go-version }}
     - uses: actions/checkout@v2
 
+    # Get values for cache paths to be used in later steps 
+    - id: cache-paths
+      run: |
+        echo "::set-output name=go-cache::$(go env GOCACHE)"
+        echo "::set-output name=go-mod-cache::$(go env GOMODCACHE)"
+
     - name: Cache go modules
       uses: actions/cache@v2
       with:
-        path: ~/go/pkg/mod
+        path: |
+          ${{ steps.cache-paths.outputs.go-cache }}
+          ${{ steps.cache-paths.outputs.go-mod-cache }}
         key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
         restore-keys: ${{ runner.os }}-go-
 
-    - name: Run go fmt
-      if: runner.os != 'Windows'
-      run: diff -u <(echo -n) <(gofmt -d -s .)
-
     - name: Ensure go generate produces a zero diff
       shell: bash
-      run:  go generate -x ./... && git diff --exit-code; code=$?; git checkout -- .; (exit $code)
-
-    - name: Run go vet
-      run: go vet ./...
+      run: go generate -x ./... && git diff --exit-code; code=$?; git checkout -- .; (exit $code)
 
     - name: Run go test
       run: go test -v -race -coverprofile coverage.txt -covermode atomic ./...
@@ -71,4 +72,11 @@ jobs:
 
     - name: Upload coverage to Codecov
       if: ${{ matrix.update-coverage }}
-      uses: codecov/codecov-action@v1
+      uses: codecov/codecov-action@5a8bb4701eca7ba3673f21664b887f652c58d0a3 #v2.0.3
+
+    - name: Ensure go generate produces a zero diff for update-urls
+      shell: bash
+      run: cd update-urls && go generate -x ./... && git diff --exit-code; code=$?; git checkout -- .; (exit $code)
+
+    - name: Run go test for update-urls
+      run: cd update-urls && go test -v -race ./...
diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go
index 04bf837a..c6633945 100644
--- a/github/github-accessors_test.go
+++ b/github/github-accessors_test.go
@@ -1417,6 +1417,56 @@ func TestAuthorizationUpdateRequest_GetNoteURL(tt *testing.T) {
 	a.GetNoteURL()
 }
 
+func TestAutolink_GetID(tt *testing.T) {
+	var zeroValue int64
+	a := &Autolink{ID: &zeroValue}
+	a.GetID()
+	a = &Autolink{}
+	a.GetID()
+	a = nil
+	a.GetID()
+}
+
+func TestAutolink_GetKeyPrefix(tt *testing.T) {
+	var zeroValue string
+	a := &Autolink{KeyPrefix: &zeroValue}
+	a.GetKeyPrefix()
+	a = &Autolink{}
+	a.GetKeyPrefix()
+	a = nil
+	a.GetKeyPrefix()
+}
+
+func TestAutolink_GetURLTemplate(tt *testing.T) {
+	var zeroValue string
+	a := &Autolink{URLTemplate: &zeroValue}
+	a.GetURLTemplate()
+	a = &Autolink{}
+	a.GetURLTemplate()
+	a = nil
+	a.GetURLTemplate()
+}
+
+func TestAutolinkOptions_GetKeyPrefix(tt *testing.T) {
+	var zeroValue string
+	a := &AutolinkOptions{KeyPrefix: &zeroValue}
+	a.GetKeyPrefix()
+	a = &AutolinkOptions{}
+	a.GetKeyPrefix()
+	a = nil
+	a.GetKeyPrefix()
+}
+
+func TestAutolinkOptions_GetURLTemplate(tt *testing.T) {
+	var zeroValue string
+	a := &AutolinkOptions{URLTemplate: &zeroValue}
+	a.GetURLTemplate()
+	a = &AutolinkOptions{}
+	a.GetURLTemplate()
+	a = nil
+	a.GetURLTemplate()
+}
+
 func TestAutoTriggerCheck_GetAppID(tt *testing.T) {
 	var zeroValue int64
 	a := &AutoTriggerCheck{AppID: &zeroValue}
@@ -5502,6 +5552,16 @@ func TestGPGKey_GetPublicKey(tt *testing.T) {
 	g.GetPublicKey()
 }
 
+func TestGPGKey_GetRawKey(tt *testing.T) {
+	var zeroValue string
+	g := &GPGKey{RawKey: &zeroValue}
+	g.GetRawKey()
+	g = &GPGKey{}
+	g.GetRawKey()
+	g = nil
+	g.GetRawKey()
+}
+
 func TestGrant_GetApp(tt *testing.T) {
 	g := &Grant{}
 	g.GetApp()
@@ -8417,6 +8477,36 @@ func TestListRepositories_GetTotalCount(tt *testing.T) {
 	l.GetTotalCount()
 }
 
+func TestListSCIMProvisionedIdentitiesOptions_GetCount(tt *testing.T) {
+	var zeroValue int
+	l := &ListSCIMProvisionedIdentitiesOptions{Count: &zeroValue}
+	l.GetCount()
+	l = &ListSCIMProvisionedIdentitiesOptions{}
+	l.GetCount()
+	l = nil
+	l.GetCount()
+}
+
+func TestListSCIMProvisionedIdentitiesOptions_GetFilter(tt *testing.T) {
+	var zeroValue string
+	l := &ListSCIMProvisionedIdentitiesOptions{Filter: &zeroValue}
+	l.GetFilter()
+	l = &ListSCIMProvisionedIdentitiesOptions{}
+	l.GetFilter()
+	l = nil
+	l.GetFilter()
+}
+
+func TestListSCIMProvisionedIdentitiesOptions_GetStartIndex(tt *testing.T) {
+	var zeroValue int
+	l := &ListSCIMProvisionedIdentitiesOptions{StartIndex: &zeroValue}
+	l.GetStartIndex()
+	l = &ListSCIMProvisionedIdentitiesOptions{}
+	l.GetStartIndex()
+	l = nil
+	l.GetStartIndex()
+}
+
 func TestLocation_GetEndColumn(tt *testing.T) {
 	var zeroValue int
 	l := &Location{EndColumn: &zeroValue}
@@ -14631,6 +14721,16 @@ func TestRepositoriesSearchResult_GetTotal(tt *testing.T) {
 	r.GetTotal()
 }
 
+func TestRepository_GetAllowAutoMerge(tt *testing.T) {
+	var zeroValue bool
+	r := &Repository{AllowAutoMerge: &zeroValue}
+	r.GetAllowAutoMerge()
+	r = &Repository{}
+	r.GetAllowAutoMerge()
+	r = nil
+	r.GetAllowAutoMerge()
+}
+
 func TestRepository_GetAllowMergeCommit(tt *testing.T) {
 	var zeroValue bool
 	r := &Repository{AllowMergeCommit: &zeroValue}
@@ -17036,6 +17136,66 @@ func TestRunnerLabels_GetType(tt *testing.T) {
 	r.GetType()
 }
 
+func TestSCIMUserAttributes_GetActive(tt *testing.T) {
+	var zeroValue bool
+	s := &SCIMUserAttributes{Active: &zeroValue}
+	s.GetActive()
+	s = &SCIMUserAttributes{}
+	s.GetActive()
+	s = nil
+	s.GetActive()
+}
+
+func TestSCIMUserAttributes_GetDisplayName(tt *testing.T) {
+	var zeroValue string
+	s := &SCIMUserAttributes{DisplayName: &zeroValue}
+	s.GetDisplayName()
+	s = &SCIMUserAttributes{}
+	s.GetDisplayName()
+	s = nil
+	s.GetDisplayName()
+}
+
+func TestSCIMUserAttributes_GetExternalID(tt *testing.T) {
+	var zeroValue string
+	s := &SCIMUserAttributes{ExternalID: &zeroValue}
+	s.GetExternalID()
+	s = &SCIMUserAttributes{}
+	s.GetExternalID()
+	s = nil
+	s.GetExternalID()
+}
+
+func TestSCIMUserEmail_GetPrimary(tt *testing.T) {
+	var zeroValue bool
+	s := &SCIMUserEmail{Primary: &zeroValue}
+	s.GetPrimary()
+	s = &SCIMUserEmail{}
+	s.GetPrimary()
+	s = nil
+	s.GetPrimary()
+}
+
+func TestSCIMUserEmail_GetType(tt *testing.T) {
+	var zeroValue string
+	s := &SCIMUserEmail{Type: &zeroValue}
+	s.GetType()
+	s = &SCIMUserEmail{}
+	s.GetType()
+	s = nil
+	s.GetType()
+}
+
+func TestSCIMUserName_GetFormatted(tt *testing.T) {
+	var zeroValue string
+	s := &SCIMUserName{Formatted: &zeroValue}
+	s.GetFormatted()
+	s = &SCIMUserName{}
+	s.GetFormatted()
+	s = nil
+	s.GetFormatted()
+}
+
 func TestSelectedReposList_GetTotalCount(tt *testing.T) {
 	var zeroValue int
 	s := &SelectedReposList{TotalCount: &zeroValue}
@@ -18837,6 +18997,16 @@ func TestTreeEntry_GetURL(tt *testing.T) {
 	t.GetURL()
 }
 
+func TestUpdateAttributeForSCIMUserOperations_GetPath(tt *testing.T) {
+	var zeroValue string
+	u := &UpdateAttributeForSCIMUserOperations{Path: &zeroValue}
+	u.GetPath()
+	u = &UpdateAttributeForSCIMUserOperations{}
+	u.GetPath()
+	u = nil
+	u.GetPath()
+}
+
 func TestUpdateCheckRunOptions_GetCompletedAt(tt *testing.T) {
 	var zeroValue Timestamp
 	u := &UpdateCheckRunOptions{CompletedAt: &zeroValue}
@@ -20448,6 +20618,44 @@ func TestWorkflowJob_GetURL(tt *testing.T) {
 	w.GetURL()
 }
 
+func TestWorkflowJobEvent_GetAction(tt *testing.T) {
+	var zeroValue string
+	w := &WorkflowJobEvent{Action: &zeroValue}
+	w.GetAction()
+	w = &WorkflowJobEvent{}
+	w.GetAction()
+	w = nil
+	w.GetAction()
+}
+
+func TestWorkflowJobEvent_GetOrg(tt *testing.T) {
+	w := &WorkflowJobEvent{}
+	w.GetOrg()
+	w = nil
+	w.GetOrg()
+}
+
+func TestWorkflowJobEvent_GetRepo(tt *testing.T) {
+	w := &WorkflowJobEvent{}
+	w.GetRepo()
+	w = nil
+	w.GetRepo()
+}
+
+func TestWorkflowJobEvent_GetSender(tt *testing.T) {
+	w := &WorkflowJobEvent{}
+	w.GetSender()
+	w = nil
+	w.GetSender()
+}
+
+func TestWorkflowJobEvent_GetWorkflowJob(tt *testing.T) {
+	w := &WorkflowJobEvent{}
+	w.GetWorkflowJob()
+	w = nil
+	w.GetWorkflowJob()
+}
+
 func TestWorkflowRun_GetArtifactsURL(tt *testing.T) {
 	var zeroValue string
 	w := &WorkflowRun{ArtifactsURL: &zeroValue}
diff --git a/github/github-stringify_test.go b/github/github-stringify_test.go
index 8ebc11cb..f3cab123 100644
--- a/github/github-stringify_test.go
+++ b/github/github-stringify_test.go
@@ -375,13 +375,14 @@ func TestGPGKey_String(t *testing.T) {
 		ID:                Int64(0),
 		PrimaryKeyID:      Int64(0),
 		KeyID:             String(""),
+		RawKey:            String(""),
 		PublicKey:         String(""),
 		CanSign:           Bool(false),
 		CanEncryptComms:   Bool(false),
 		CanEncryptStorage: Bool(false),
 		CanCertify:        Bool(false),
 	}
-	want := `github.GPGKey{ID:0, PrimaryKeyID:0, KeyID:"", PublicKey:"", CanSign:false, CanEncryptComms:false, CanEncryptStorage:false, CanCertify:false}`
+	want := `github.GPGKey{ID:0, PrimaryKeyID:0, KeyID:"", RawKey:"", PublicKey:"", CanSign:false, CanEncryptComms:false, CanEncryptStorage:false, CanCertify:false}`
 	if got := v.String(); got != want {
 		t.Errorf("GPGKey.String = %v, want %v", got, want)
 	}
@@ -1421,6 +1422,7 @@ func TestRepository_String(t *testing.T) {
 		AllowRebaseMerge:    Bool(false),
 		AllowSquashMerge:    Bool(false),
 		AllowMergeCommit:    Bool(false),
+		AllowAutoMerge:      Bool(false),
 		DeleteBranchOnMerge: Bool(false),
 		Archived:            Bool(false),
 		Disabled:            Bool(false),
@@ -1474,7 +1476,7 @@ func TestRepository_String(t *testing.T) {
 		TeamsURL:            String(""),
 		Visibility:          String(""),
 	}
-	want := `github.Repository{ID:0, NodeID:"", Owner:github.User{}, Name:"", FullName:"", Description:"", Homepage:"", CodeOfConduct:github.CodeOfConduct{}, DefaultBranch:"", MasterBranch:"", CreatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, PushedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, UpdatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, HTMLURL:"", CloneURL:"", GitURL:"", MirrorURL:"", SSHURL:"", SVNURL:"", Language:"", Fork:false, ForksCount:0, NetworkCount:0, OpenIssuesCount:0, OpenIssues:0, StargazersCount:0, SubscribersCount:0, WatchersCount:0, Watchers:0, Size:0, AutoInit:false, Parent:github.Repository{}, Source:github.Repository{}, TemplateRepository:github.Repository{}, Organization:github.Organization{}, AllowRebaseMerge:false, AllowSquashMerge:false, AllowMergeCommit:false, DeleteBranchOnMerge:false, Archived:false, Disabled:false, License:github.License{}, Private:false, HasIssues:false, HasWiki:false, HasPages:false, HasProjects:false, HasDownloads:false, IsTemplate:false, LicenseTemplate:"", GitignoreTemplate:"", TeamID:0, URL:"", ArchiveURL:"", AssigneesURL:"", BlobsURL:"", BranchesURL:"", CollaboratorsURL:"", CommentsURL:"", CommitsURL:"", CompareURL:"", ContentsURL:"", ContributorsURL:"", DeploymentsURL:"", DownloadsURL:"", EventsURL:"", ForksURL:"", GitCommitsURL:"", GitRefsURL:"", GitTagsURL:"", HooksURL:"", IssueCommentURL:"", IssueEventsURL:"", IssuesURL:"", KeysURL:"", LabelsURL:"", LanguagesURL:"", MergesURL:"", MilestonesURL:"", NotificationsURL:"", PullsURL:"", ReleasesURL:"", StargazersURL:"", StatusesURL:"", SubscribersURL:"", SubscriptionURL:"", TagsURL:"", TreesURL:"", TeamsURL:"", Visibility:""}`
+	want := `github.Repository{ID:0, NodeID:"", Owner:github.User{}, Name:"", FullName:"", Description:"", Homepage:"", CodeOfConduct:github.CodeOfConduct{}, DefaultBranch:"", MasterBranch:"", CreatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, PushedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, UpdatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, HTMLURL:"", CloneURL:"", GitURL:"", MirrorURL:"", SSHURL:"", SVNURL:"", Language:"", Fork:false, ForksCount:0, NetworkCount:0, OpenIssuesCount:0, OpenIssues:0, StargazersCount:0, SubscribersCount:0, WatchersCount:0, Watchers:0, Size:0, AutoInit:false, Parent:github.Repository{}, Source:github.Repository{}, TemplateRepository:github.Repository{}, Organization:github.Organization{}, AllowRebaseMerge:false, AllowSquashMerge:false, AllowMergeCommit:false, AllowAutoMerge:false, DeleteBranchOnMerge:false, Archived:false, Disabled:false, License:github.License{}, Private:false, HasIssues:false, HasWiki:false, HasPages:false, HasProjects:false, HasDownloads:false, IsTemplate:false, LicenseTemplate:"", GitignoreTemplate:"", TeamID:0, URL:"", ArchiveURL:"", AssigneesURL:"", BlobsURL:"", BranchesURL:"", CollaboratorsURL:"", CommentsURL:"", CommitsURL:"", CompareURL:"", ContentsURL:"", ContributorsURL:"", DeploymentsURL:"", DownloadsURL:"", EventsURL:"", ForksURL:"", GitCommitsURL:"", GitRefsURL:"", GitTagsURL:"", HooksURL:"", IssueCommentURL:"", IssueEventsURL:"", IssuesURL:"", KeysURL:"", LabelsURL:"", LanguagesURL:"", MergesURL:"", MilestonesURL:"", NotificationsURL:"", PullsURL:"", ReleasesURL:"", StargazersURL:"", StatusesURL:"", SubscribersURL:"", SubscriptionURL:"", TagsURL:"", TreesURL:"", TeamsURL:"", Visibility:""}`
 	if got := v.String(); got != want {
 		t.Errorf("Repository.String = %v, want %v", got, want)
 	}
diff --git a/github/messages_test.go b/github/messages_test.go
index 9880a2a5..da8c3331 100644
--- a/github/messages_test.go
+++ b/github/messages_test.go
@@ -450,6 +450,10 @@ func TestParseWebHook(t *testing.T) {
 			payload:     &WorkflowDispatchEvent{},
 			messageType: "workflow_dispatch",
 		},
+		{
+			payload:     &WorkflowJobEvent{},
+			messageType: "workflow_job",
+		},
 		{
 			payload:     &WorkflowRunEvent{},
 			messageType: "workflow_run",
diff --git a/github/orgs_hooks_deliveries_test.go b/github/orgs_hooks_deliveries_test.go
index c1efc527..cd0bd109 100644
--- a/github/orgs_hooks_deliveries_test.go
+++ b/github/orgs_hooks_deliveries_test.go
@@ -104,3 +104,47 @@ func TestOrganizationsService_GetHookDelivery_invalidOwner(t *testing.T) {
 	_, _, err := client.Organizations.GetHookDelivery(ctx, "%", 1, 1)
 	testURLParseError(t, err)
 }
+
+func TestOrganizationsService_RedeliverHookDelivery(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/orgs/o/hooks/1/deliveries/1/attempts", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "POST")
+		fmt.Fprint(w, `{"id":1}`)
+	})
+
+	ctx := context.Background()
+	hook, _, err := client.Organizations.RedeliverHookDelivery(ctx, "o", 1, 1)
+	if err != nil {
+		t.Errorf("Organizations.RedeliverHookDelivery returned error: %v", err)
+	}
+
+	want := &HookDelivery{ID: Int64(1)}
+	if !cmp.Equal(hook, want) {
+		t.Errorf("Organizations.RedeliverHookDelivery returned %+v, want %+v", hook, want)
+	}
+
+	const methodName = "Rede;overHookDelivery"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Organizations.RedeliverHookDelivery(ctx, "\n", -1, -1)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Organizations.RedeliverHookDelivery(ctx, "o", 1, 1)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
+func TestOrganizationsService_RedeliverHookDelivery_invalidOwner(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	ctx := context.Background()
+	_, _, err := client.Organizations.RedeliverHookDelivery(ctx, "%", 1, 1)
+	testURLParseError(t, err)
+}
diff --git a/github/repos_autolinks_test.go b/github/repos_autolinks_test.go
new file mode 100644
index 00000000..b6121d2c
--- /dev/null
+++ b/github/repos_autolinks_test.go
@@ -0,0 +1,154 @@
+// Copyright 2021 The go-github AUTHORS. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package github
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+)
+
+func TestRepositoriesService_ListAutolinks(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/repos/o/r/autolinks", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testFormValues(t, r, values{"page": "2"})
+		fmt.Fprintf(w, `[{"id":1, "key_prefix": "TICKET-", "url_template": "https://example.com/TICKET?query=<num>"}, {"id":2, "key_prefix": "STORY-", "url_template": "https://example.com/STORY?query=<num>"}]`)
+	})
+
+	opt := &ListOptions{
+		Page: 2,
+	}
+	ctx := context.Background()
+	autolinks, _, err := client.Repositories.ListAutolinks(ctx, "o", "r", opt)
+	if err != nil {
+		t.Errorf("Repositories.ListAutolinks returned error: %v", err)
+	}
+
+	want := []*Autolink{
+		{ID: Int64(1), KeyPrefix: String("TICKET-"), URLTemplate: String("https://example.com/TICKET?query=<num>")},
+		{ID: Int64(2), KeyPrefix: String("STORY-"), URLTemplate: String("https://example.com/STORY?query=<num>")},
+	}
+
+	if !cmp.Equal(autolinks, want) {
+		t.Errorf("Repositories.ListAutolinks returned %+v, want %+v", autolinks, want)
+	}
+
+	const methodName = "ListAutolinks"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Repositories.ListAutolinks(ctx, "\n", "\n", opt)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Repositories.ListAutolinks(ctx, "o", "r", opt)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
+func TestRepositoriesService_AddAutolink(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	opt := &AutolinkOptions{KeyPrefix: String("TICKET-"), URLTemplate: String("https://example.com/TICKET?query=<num>")}
+	mux.HandleFunc("/repos/o/r/autolinks", func(w http.ResponseWriter, r *http.Request) {
+		v := new(AutolinkOptions)
+		json.NewDecoder(r.Body).Decode(v)
+		testMethod(t, r, "POST")
+		if !cmp.Equal(v, opt) {
+			t.Errorf("Request body = %+v, want %+v", v, opt)
+		}
+		w.WriteHeader(http.StatusOK)
+		w.Write([]byte(`{"key_prefix": "TICKET-","url_template": "https://example.com/TICKET?query=<num>"}`))
+	})
+	ctx := context.Background()
+	autolink, _, err := client.Repositories.AddAutolink(ctx, "o", "r", opt)
+	if err != nil {
+		t.Errorf("Repositories.AddAutolink returned error: %v", err)
+	}
+	want := &Autolink{
+		KeyPrefix:   String("TICKET-"),
+		URLTemplate: String("https://example.com/TICKET?query=<num>"),
+	}
+
+	if !cmp.Equal(autolink, want) {
+		t.Errorf("AddAutolink returned %+v, want %+v", autolink, want)
+	}
+
+	const methodName = "AddAutolink"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Repositories.AddAutolink(ctx, "\n", "\n", opt)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Repositories.AddAutolink(ctx, "o", "r", opt)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
+func TestRepositoriesService_GetAutolink(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/repos/o/r/autolinks/1", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		fmt.Fprintf(w, `{"id":1, "key_prefix": "TICKET-", "url_template": "https://example.com/TICKET?query=<num>"}`)
+	})
+
+	ctx := context.Background()
+	autolink, _, err := client.Repositories.GetAutolink(ctx, "o", "r", 1)
+	if err != nil {
+		t.Errorf("Repositories.GetAutolink returned error: %v", err)
+	}
+
+	want := &Autolink{ID: Int64(1), KeyPrefix: String("TICKET-"), URLTemplate: String("https://example.com/TICKET?query=<num>")}
+	if !cmp.Equal(autolink, want) {
+		t.Errorf("Repositories.GetAutolink returned %+v, want %+v", autolink, want)
+	}
+
+	const methodName = "GetAutolink"
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Repositories.GetAutolink(ctx, "o", "r", 2)
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+}
+
+func TestRepositoriesService_DeleteAutolink(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/repos/o/r/autolinks/1", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "DELETE")
+		w.WriteHeader(http.StatusNoContent)
+	})
+
+	ctx := context.Background()
+	_, err := client.Repositories.DeleteAutolink(ctx, "o", "r", 1)
+	if err != nil {
+		t.Errorf("Repositories.DeleteAutolink returned error: %v", err)
+	}
+
+	const methodName = "DeleteAutolink"
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		return client.Repositories.DeleteAutolink(ctx, "o", "r", 2)
+	})
+}
diff --git a/github/repos_environments_test.go b/github/repos_environments_test.go
index 535ae232..4165ad75 100644
--- a/github/repos_environments_test.go
+++ b/github/repos_environments_test.go
@@ -238,3 +238,91 @@ func TestRepositoriesService_DeleteEnvironment(t *testing.T) {
 		return client.Repositories.DeleteEnvironment(ctx, "o", "r", "e")
 	})
 }
+
+func TestRepoEnvironment_Marshal(t *testing.T) {
+	testJSONMarshal(t, &EnvResponse{}, "{}")
+
+	repoEnv := &EnvResponse{
+		TotalCount: Int(1),
+		Environments: []*Environment{
+			{
+				Owner:           String("me"),
+				Repo:            String("se"),
+				EnvironmentName: String("dev"),
+				WaitTimer:       Int(123),
+				Reviewers: []*EnvReviewers{
+					{
+						Type: String("main"),
+						ID:   Int64(1),
+					},
+					{
+						Type: String("rev"),
+						ID:   Int64(2),
+					},
+				},
+				DeploymentBranchPolicy: &BranchPolicy{
+					ProtectedBranches:    Bool(false),
+					CustomBranchPolicies: Bool(false),
+				},
+				ID:        Int64(2),
+				NodeID:    String("star"),
+				Name:      String("eg"),
+				URL:       String("https://hey.in"),
+				HTMLURL:   String("htmlurl"),
+				CreatedAt: &Timestamp{referenceTime},
+				UpdatedAt: &Timestamp{referenceTime},
+				ProtectionRules: []*ProtectionRule{
+					{
+						ID:        Int64(21),
+						NodeID:    String("mnb"),
+						Type:      String("ewq"),
+						WaitTimer: Int(9090),
+					},
+				},
+			},
+		},
+	}
+
+	want := `{
+		"total_count":1,
+		"environments":[
+		   {
+			  "owner":"me",
+			  "repo":"se",
+			  "environment_name":"dev",
+			  "wait_timer":123,
+			  "reviewers":[
+				 {
+					"type":"main",
+					"id":1
+				 },
+				 {
+					"type":"rev",
+					"id":2
+				 }
+			  ],
+			  "deployment_branch_policy":{
+				 "protected_branches":false,
+				 "custom_branch_policies":false
+			  },
+			  "id":2,
+			  "node_id":"star",
+			  "name":"eg",
+			  "url":"https://hey.in",
+			  "html_url":"htmlurl",
+			  "created_at":` + referenceTimeStr + `,
+			  "updated_at":` + referenceTimeStr + `,
+			  "protection_rules":[
+				 {
+					"id":21,
+					"node_id":"mnb",
+					"type":"ewq",
+					"wait_timer":9090
+				 }
+			  ]
+		   }
+		]
+	 }`
+
+	testJSONMarshal(t, repoEnv, want)
+}
diff --git a/github/repos_hooks_deliveries_test.go b/github/repos_hooks_deliveries_test.go
index 5c6fb86d..b970eb49 100644
--- a/github/repos_hooks_deliveries_test.go
+++ b/github/repos_hooks_deliveries_test.go
@@ -155,6 +155,7 @@ var hookDeliveryPayloadTypeToStruct = map[string]interface{}{
 	"user":                           &UserEvent{},
 	"watch":                          &WatchEvent{},
 	"workflow_dispatch":              &WorkflowDispatchEvent{},
+	"workflow_job":                   &WorkflowJobEvent{},
 	"workflow_run":                   &WorkflowRunEvent{},
 }
 
diff --git a/github/repos_invitations_test.go b/github/repos_invitations_test.go
index e05ff3cd..74bda793 100644
--- a/github/repos_invitations_test.go
+++ b/github/repos_invitations_test.go
@@ -111,3 +111,55 @@ func TestRepositoriesService_UpdateInvitation(t *testing.T) {
 		return resp, err
 	})
 }
+
+func TestRepositoryInvitation_Marshal(t *testing.T) {
+	testJSONMarshal(t, &RepositoryInvitation{}, "{}")
+
+	r := &RepositoryInvitation{
+		ID: Int64(1),
+		Repo: &Repository{
+			ID:   Int64(1),
+			Name: String("n"),
+			URL:  String("u"),
+		},
+		Invitee: &User{
+			ID:   Int64(1),
+			Name: String("n"),
+			URL:  String("u"),
+		},
+		Inviter: &User{
+			ID:   Int64(1),
+			Name: String("n"),
+			URL:  String("u"),
+		},
+		Permissions: String("p"),
+		CreatedAt:   &Timestamp{referenceTime},
+		URL:         String("u"),
+		HTMLURL:     String("h"),
+	}
+
+	want := `{
+		"id":1,
+		"repository":{
+			"id":1,
+			"name":"n",
+			"url":"u"
+		},
+		"invitee":{
+			"id":1,
+			"name":"n",
+			"url":"u"
+		},
+		"inviter":{
+			"id":1,
+			"name":"n",
+			"url":"u"
+		},
+		"permissions":"p",
+		"created_at":` + referenceTimeStr + `,
+		"url":"u",
+		"html_url":"h"
+	}`
+
+	testJSONMarshal(t, r, want)
+}
diff --git a/github/repos_merging_test.go b/github/repos_merging_test.go
index 0d099552..05263100 100644
--- a/github/repos_merging_test.go
+++ b/github/repos_merging_test.go
@@ -62,3 +62,21 @@ func TestRepositoriesService_Merge(t *testing.T) {
 		return resp, err
 	})
 }
+
+func TestRepositoryMergeRequest_Marshal(t *testing.T) {
+	testJSONMarshal(t, &RepositoryMergeRequest{}, "{}")
+
+	u := &RepositoryMergeRequest{
+		Base:          String("base"),
+		Head:          String("head"),
+		CommitMessage: String("cm"),
+	}
+
+	want := `{
+		"base": "base",
+		"head": "head",
+		"commit_message": "cm"
+	}`
+
+	testJSONMarshal(t, u, want)
+}
diff --git a/github/repos_pages_test.go b/github/repos_pages_test.go
index 6a4d2ad5..85069f94 100644
--- a/github/repos_pages_test.go
+++ b/github/repos_pages_test.go
@@ -357,3 +357,133 @@ func TestRepositoriesService_RequestPageBuild(t *testing.T) {
 		return resp, err
 	})
 }
+
+func TestPagesSource_Marshal(t *testing.T) {
+	testJSONMarshal(t, &PagesSource{}, "{}")
+
+	u := &PagesSource{
+		Branch: String("branch"),
+		Path:   String("path"),
+	}
+
+	want := `{
+		"branch": "branch",
+		"path": "path"
+	}`
+
+	testJSONMarshal(t, u, want)
+}
+
+func TestPagesError_Marshal(t *testing.T) {
+	testJSONMarshal(t, &PagesError{}, "{}")
+
+	u := &PagesError{
+		Message: String("message"),
+	}
+
+	want := `{
+		"message": "message"
+	}`
+
+	testJSONMarshal(t, u, want)
+}
+
+func TestPagesUpdate_Marshal(t *testing.T) {
+	testJSONMarshal(t, &PagesUpdate{}, "{}")
+
+	u := &PagesUpdate{
+		CNAME:  String("cname"),
+		Source: String("src"),
+	}
+
+	want := `{
+		"cname": "cname",
+		"source": "src"
+	}`
+
+	testJSONMarshal(t, u, want)
+}
+
+func TestPages_Marshal(t *testing.T) {
+	testJSONMarshal(t, &Pages{}, "{}")
+
+	u := &Pages{
+		URL:       String("url"),
+		Status:    String("status"),
+		CNAME:     String("cname"),
+		Custom404: Bool(false),
+		HTMLURL:   String("hurl"),
+		Source: &PagesSource{
+			Branch: String("branch"),
+			Path:   String("path"),
+		},
+	}
+
+	want := `{
+		"url": "url",
+		"status": "status",
+		"cname": "cname",
+		"custom_404": false,
+		"html_url": "hurl",
+		"source": {
+			"branch": "branch",
+			"path": "path"
+		}
+	}`
+
+	testJSONMarshal(t, u, want)
+}
+
+func TestPagesBuild_Marshal(t *testing.T) {
+	testJSONMarshal(t, &PagesBuild{}, "{}")
+
+	u := &PagesBuild{
+		URL:    String("url"),
+		Status: String("status"),
+		Error: &PagesError{
+			Message: String("message"),
+		},
+		Pusher:    &User{ID: Int64(1)},
+		Commit:    String("commit"),
+		Duration:  Int(1),
+		CreatedAt: &Timestamp{referenceTime},
+		UpdatedAt: &Timestamp{referenceTime},
+	}
+
+	want := `{
+		"url": "url",
+		"status": "status",
+		"error": {
+			"message": "message"
+		},
+		"pusher": {
+			"id": 1
+		},
+		"commit": "commit",
+		"duration": 1,
+		"created_at": ` + referenceTimeStr + `,
+		"updated_at": ` + referenceTimeStr + `
+	}`
+
+	testJSONMarshal(t, u, want)
+}
+
+func TestCreatePagesRequest_Marshal(t *testing.T) {
+	testJSONMarshal(t, &createPagesRequest{}, "{}")
+
+	u := &createPagesRequest{
+		Source: &PagesSource{
+			Branch: String("branch"),
+			Path:   String("path"),
+		},
+	}
+
+	want := `{
+		"source": {
+			"branch": "branch",
+			"path": "path"
+		}
+	}`
+
+	testJSONMarshal(t, u, want)
+}
diff --git a/github/repos_prereceive_hooks_test.go b/github/repos_prereceive_hooks_test.go
index 90178bd5..303e0e12 100644
--- a/github/repos_prereceive_hooks_test.go
+++ b/github/repos_prereceive_hooks_test.go
@@ -194,3 +194,23 @@ func TestRepositoriesService_DeletePreReceiveHook_invalidOwner(t *testing.T) {
 	_, err := client.Repositories.DeletePreReceiveHook(ctx, "%", "%", 1)
 	testURLParseError(t, err)
 }
+
+func TestPreReceiveHook_Marshal(t *testing.T) {
+	testJSONMarshal(t, &PreReceiveHook{}, "{}")
+
+	u := &PreReceiveHook{
+		ID:          Int64(1),
+		Name:        String("name"),
+		Enforcement: String("e"),
+		ConfigURL:   String("curl"),
+	}
+
+	want := `{
+		"id": 1,
+		"name": "name",
+		"enforcement": "e",
+		"configuration_url": "curl"
+	}`
+
+	testJSONMarshal(t, u, want)
+}
diff --git a/github/repos_releases_test.go b/github/repos_releases_test.go
index 9f1fbe8d..69041c0c 100644
--- a/github/repos_releases_test.go
+++ b/github/repos_releases_test.go
@@ -653,3 +653,125 @@ func TestRepositoriesService_UploadReleaseAsset(t *testing.T) {
 		})
 	}
 }
+
+func TestRepositoryReleaseRequest_Marshal(t *testing.T) {
+	testJSONMarshal(t, &repositoryReleaseRequest{}, "{}")
+
+	u := &repositoryReleaseRequest{
+		TagName:                String("tn"),
+		TargetCommitish:        String("tc"),
+		Name:                   String("name"),
+		Body:                   String("body"),
+		Draft:                  Bool(false),
+		Prerelease:             Bool(false),
+		DiscussionCategoryName: String("dcn"),
+	}
+
+	want := `{
+		"tag_name": "tn",
+		"target_commitish": "tc",
+		"name": "name",
+		"body": "body",
+		"draft": false,
+		"prerelease": false,
+		"discussion_category_name": "dcn"
+	}`
+
+	testJSONMarshal(t, u, want)
+}
+
+func TestReleaseAsset_Marshal(t *testing.T) {
+	testJSONMarshal(t, &ReleaseAsset{}, "{}")
+
+	u := &ReleaseAsset{
+		ID:                 Int64(1),
+		URL:                String("url"),
+		Name:               String("name"),
+		Label:              String("label"),
+		State:              String("state"),
+		ContentType:        String("ct"),
+		Size:               Int(1),
+		DownloadCount:      Int(1),
+		CreatedAt:          &Timestamp{referenceTime},
+		UpdatedAt:          &Timestamp{referenceTime},
+		BrowserDownloadURL: String("bdu"),
+		Uploader:           &User{ID: Int64(1)},
+		NodeID:             String("nid"),
+	}
+
+	want := `{
+		"id": 1,
+		"url": "url",
+		"name": "name",
+		"label": "label",
+		"state": "state",
+		"content_type": "ct",
+		"size": 1,
+		"download_count": 1,
+		"created_at": ` + referenceTimeStr + `,
+		"updated_at": ` + referenceTimeStr + `,
+		"browser_download_url": "bdu",
+		"uploader": {
+			"id": 1
+		},
+		"node_id": "nid"
+	}`
+
+	testJSONMarshal(t, u, want)
+}
+
+func TestRepositoryRelease_Marshal(t *testing.T) {
+	testJSONMarshal(t, &RepositoryRelease{}, "{}")
+
+	u := &RepositoryRelease{
+		TagName:                String("tn"),
+		TargetCommitish:        String("tc"),
+		Name:                   String("name"),
+		Body:                   String("body"),
+		Draft:                  Bool(false),
+		Prerelease:             Bool(false),
+		DiscussionCategoryName: String("dcn"),
+		ID:                     Int64(1),
+		CreatedAt:              &Timestamp{referenceTime},
+		PublishedAt:            &Timestamp{referenceTime},
+		URL:                    String("url"),
+		HTMLURL:                String("hurl"),
+		AssetsURL:              String("aurl"),
+		Assets:                 []*ReleaseAsset{{ID: Int64(1)}},
+		UploadURL:              String("uurl"),
+		ZipballURL:             String("zurl"),
+		TarballURL:             String("turl"),
+		Author:                 &User{ID: Int64(1)},
+		NodeID:                 String("nid"),
+	}
+
+	want := `{
+		"tag_name": "tn",
+		"target_commitish": "tc",
+		"name": "name",
+		"body": "body",
+		"draft": false,
+		"prerelease": false,
+		"discussion_category_name": "dcn",
+		"id": 1,
+		"created_at": ` + referenceTimeStr + `,
+		"published_at": ` + referenceTimeStr + `,
+		"url": "url",
+		"html_url": "hurl",
+		"assets_url": "aurl",
+		"assets": [
+			{
+				"id": 1
+			}
+		],
+		"upload_url": "uurl",
+		"zipball_url": "zurl",
+		"tarball_url": "turl",
+		"author": {
+			"id": 1
+		},
+		"node_id": "nid"
+	}`
+
+	testJSONMarshal(t, u, want)
+}
diff --git a/github/repos_stats_test.go b/github/repos_stats_test.go
index efb36674..1babaca6 100644
--- a/github/repos_stats_test.go
+++ b/github/repos_stats_test.go
@@ -327,3 +327,93 @@ func TestRepositoriesService_AcceptedError(t *testing.T) {
 		return resp, err
 	})
 }
+
+func TestRepositoryParticipation_Marshal(t *testing.T) {
+	testJSONMarshal(t, &RepositoryParticipation{}, "{}")
+
+	u := &RepositoryParticipation{
+		All:   []int{1},
+		Owner: []int{1},
+	}
+
+	want := `{
+		"all": [1],
+		"owner": [1]
+	}`
+
+	testJSONMarshal(t, u, want)
+}
+
+func TestWeeklyCommitActivity_Marshal(t *testing.T) {
+	testJSONMarshal(t, &WeeklyCommitActivity{}, "{}")
+
+	u := &WeeklyCommitActivity{
+		Days:  []int{1},
+		Total: Int(1),
+		Week:  &Timestamp{referenceTime},
+	}
+
+	want := `{
+		"days": [
+			1
+		],
+		"total": 1,
+		"week": ` + referenceTimeStr + `
+	}`
+
+	testJSONMarshal(t, u, want)
+}
+
+func TestWeeklyStats_Marshal(t *testing.T) {
+	testJSONMarshal(t, &WeeklyStats{}, "{}")
+
+	u := &WeeklyStats{
+		Week:      &Timestamp{referenceTime},
+		Additions: Int(1),
+		Deletions: Int(1),
+		Commits:   Int(1),
+	}
+
+	want := `{
+		"w": ` + referenceTimeStr + `,
+		"a": 1,
+		"d": 1,
+		"c": 1
+	}`
+
+	testJSONMarshal(t, u, want)
+}
+
+func TestContributorStats_Marshal(t *testing.T) {
+	testJSONMarshal(t, &ContributorStats{}, "{}")
+
+	u := &ContributorStats{
+		Author: &Contributor{ID: Int64(1)},
+		Total:  Int(1),
+		Weeks: []*WeeklyStats{
+			{
+				Week:      &Timestamp{referenceTime},
+				Additions: Int(1),
+				Deletions: Int(1),
+				Commits:   Int(1),
+			},
+		},
+	}
+
+	want := `{
+		"author": {
+			"id": 1
+		},
+		"total": 1,
+		"weeks": [
+			{
+				"w": ` + referenceTimeStr + `,
+				"a": 1,
+				"d": 1,
+				"c": 1
+			}
+		]
+	}`
+
+	testJSONMarshal(t, u, want)
+}
diff --git a/github/repos_statuses_test.go b/github/repos_statuses_test.go
index 3fa2ca7c..62fe3336 100644
--- a/github/repos_statuses_test.go
+++ b/github/repos_statuses_test.go
@@ -149,3 +149,95 @@ func TestRepositoriesService_GetCombinedStatus(t *testing.T) {
 		return resp, err
 	})
 }
+
+func TestRepoStatus_Marshal(t *testing.T) {
+	testJSONMarshal(t, &RepoStatus{}, "{}")
+
+	u := &RepoStatus{
+		ID:          Int64(1),
+		NodeID:      String("nid"),
+		URL:         String("url"),
+		State:       String("state"),
+		TargetURL:   String("turl"),
+		Description: String("desc"),
+		Context:     String("ctx"),
+		AvatarURL:   String("aurl"),
+		Creator:     &User{ID: Int64(1)},
+		CreatedAt:   &referenceTime,
+		UpdatedAt:   &referenceTime,
+	}
+
+	want := `{
+		"id": 1,
+		"node_id": "nid",
+		"url": "url",
+		"state": "state",
+		"target_url": "turl",
+		"description": "desc",
+		"context": "ctx",
+		"avatar_url": "aurl",
+		"creator": {
+			"id": 1
+		},
+		"created_at": ` + referenceTimeStr + `,
+		"updated_at": ` + referenceTimeStr + `
+	}`
+
+	testJSONMarshal(t, u, want)
+}
+
+func TestCombinedStatus_Marshal(t *testing.T) {
+	testJSONMarshal(t, &CombinedStatus{}, "{}")
+
+	u := &CombinedStatus{
+		State:      String("state"),
+		Name:       String("name"),
+		SHA:        String("sha"),
+		TotalCount: Int(1),
+		Statuses: []*RepoStatus{
+			{
+				ID:          Int64(1),
+				NodeID:      String("nid"),
+				URL:         String("url"),
+				State:       String("state"),
+				TargetURL:   String("turl"),
+				Description: String("desc"),
+				Context:     String("ctx"),
+				AvatarURL:   String("aurl"),
+				Creator:     &User{ID: Int64(1)},
+				CreatedAt:   &referenceTime,
+				UpdatedAt:   &referenceTime,
+			},
+		},
+		CommitURL:     String("curl"),
+		RepositoryURL: String("rurl"),
+	}
+
+	want := `{
+		"state": "state",
+		"name": "name",
+		"sha": "sha",
+		"total_count": 1,
+		"statuses": [
+			{
+				"id": 1,
+				"node_id": "nid",
+				"url": "url",
+				"state": "state",
+				"target_url": "turl",
+				"description": "desc",
+				"context": "ctx",
+				"avatar_url": "aurl",
+				"creator": {
+					"id": 1
+				},
+				"created_at": ` + referenceTimeStr + `,
+				"updated_at": ` + referenceTimeStr + `
+			}
+		],
+		"commit_url": "curl",
+		"repository_url": "rurl"
+	}`
+
+	testJSONMarshal(t, u, want)
+}
diff --git a/github/scim_test.go b/github/scim_test.go
new file mode 100644
index 00000000..3338a28a
--- /dev/null
+++ b/github/scim_test.go
@@ -0,0 +1,194 @@
+// Copyright 2021 The go-github AUTHORS. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package github
+
+import (
+	"context"
+	"net/http"
+	"testing"
+)
+
+func TestSCIMService_ListSCIMProvisionedIdentities(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/scim/v2/organizations/o/Users", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		w.WriteHeader(http.StatusOK)
+	})
+
+	ctx := context.Background()
+	opts := &ListSCIMProvisionedIdentitiesOptions{}
+	_, err := client.SCIM.ListSCIMProvisionedIdentities(ctx, "o", opts)
+	if err != nil {
+		t.Errorf("SCIM.ListSCIMProvisionedIdentities returned error: %v", err)
+	}
+
+	const methodName = "ListSCIMProvisionedIdentities"
+	testBadOptions(t, methodName, func() (err error) {
+		_, err = client.SCIM.ListSCIMProvisionedIdentities(ctx, "\n", opts)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		return client.SCIM.ListSCIMProvisionedIdentities(ctx, "o", opts)
+	})
+}
+
+func TestSCIMService_ProvisionAndInviteSCIMUser(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/scim/v2/organizations/o/Users", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "POST")
+		w.WriteHeader(http.StatusOK)
+	})
+
+	ctx := context.Background()
+	opts := &SCIMUserAttributes{
+		UserName: "userName",
+		Name: SCIMUserName{
+			GivenName:  "givenName",
+			FamilyName: "familyName",
+		},
+		Emails: []*SCIMUserEmail{
+			{
+				Value: "octocat@github.com",
+			},
+		},
+	}
+	_, err := client.SCIM.ProvisionAndInviteSCIMUser(ctx, "o", opts)
+	if err != nil {
+		t.Errorf("SCIM.ListSCIMProvisionedIdentities returned error: %v", err)
+	}
+
+	const methodName = "ProvisionAndInviteSCIMUser"
+	testBadOptions(t, methodName, func() (err error) {
+		_, err = client.SCIM.ProvisionAndInviteSCIMUser(ctx, "\n", opts)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		return client.SCIM.ProvisionAndInviteSCIMUser(ctx, "o", opts)
+	})
+}
+
+func TestSCIMService_GetSCIMProvisioningInfoForUser(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/scim/v2/organizations/o/Users/123", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		w.WriteHeader(http.StatusOK)
+	})
+
+	ctx := context.Background()
+	_, err := client.SCIM.GetSCIMProvisioningInfoForUser(ctx, "o", "123")
+	if err != nil {
+		t.Errorf("SCIM.GetSCIMProvisioningInfoForUser returned error: %v", err)
+	}
+
+	const methodName = "GetSCIMProvisioningInfoForUser"
+	testBadOptions(t, methodName, func() error {
+		_, err := client.SCIM.GetSCIMProvisioningInfoForUser(ctx, "\n", "123")
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		return client.SCIM.GetSCIMProvisioningInfoForUser(ctx, "o", "123")
+	})
+}
+
+func TestSCIMService_UpdateProvisionedOrgMembership(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/scim/v2/organizations/o/Users/123", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "PUT")
+		w.WriteHeader(http.StatusOK)
+	})
+
+	ctx := context.Background()
+	opts := &SCIMUserAttributes{
+		UserName: "userName",
+		Name: SCIMUserName{
+			GivenName:  "givenName",
+			FamilyName: "familyName",
+		},
+		Emails: []*SCIMUserEmail{
+			{
+				Value: "octocat@github.com",
+			},
+		},
+	}
+	_, err := client.SCIM.UpdateProvisionedOrgMembership(ctx, "o", "123", opts)
+	if err != nil {
+		t.Errorf("SCIM.UpdateProvisionedOrgMembership returned error: %v", err)
+	}
+
+	const methodName = "UpdateProvisionedOrgMembership"
+	testBadOptions(t, methodName, func() error {
+		_, err := client.SCIM.UpdateProvisionedOrgMembership(ctx, "\n", "123", opts)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		return client.SCIM.UpdateProvisionedOrgMembership(ctx, "o", "123", opts)
+	})
+}
+
+func TestSCIMService_UpdateAttributeForSCIMUser(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/scim/v2/organizations/o/Users/123", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "PATCH")
+		w.WriteHeader(http.StatusNoContent)
+	})
+
+	ctx := context.Background()
+	opts := &UpdateAttributeForSCIMUserOptions{}
+	_, err := client.SCIM.UpdateAttributeForSCIMUser(ctx, "o", "123", opts)
+	if err != nil {
+		t.Errorf("SCIM.UpdateAttributeForSCIMUser returned error: %v", err)
+	}
+
+	const methodName = "UpdateAttributeForSCIMUser"
+	testBadOptions(t, methodName, func() error {
+		_, err := client.SCIM.UpdateAttributeForSCIMUser(ctx, "\n", "123", opts)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		return client.SCIM.UpdateAttributeForSCIMUser(ctx, "o", "123", opts)
+	})
+}
+
+func TestSCIMService_DeleteSCIMUserFromOrg(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/scim/v2/organizations/o/Users/123", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "DELETE")
+		w.WriteHeader(http.StatusNoContent)
+	})
+
+	ctx := context.Background()
+	_, err := client.SCIM.DeleteSCIMUserFromOrg(ctx, "o", "123")
+	if err != nil {
+		t.Errorf("SCIM.DeleteSCIMUserFromOrg returned error: %v", err)
+	}
+
+	const methodName = "DeleteSCIMUserFromOrg"
+	testBadOptions(t, methodName, func() error {
+		_, err := client.SCIM.DeleteSCIMUserFromOrg(ctx, "\n", "")
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		return client.SCIM.DeleteSCIMUserFromOrg(ctx, "o", "123")
+	})
+}
diff --git a/update-urls/main_test.go b/update-urls/main_test.go
index 9db289a1..e9c5ef3d 100644
--- a/update-urls/main_test.go
+++ b/update-urls/main_test.go
@@ -433,6 +433,10 @@ func TestSortAndMergeFileEdits(t *testing.T) {
 		},
 	}
 
+	fileEditEqual := cmp.Comparer(func(a, b *FileEdit) bool {
+		return a.fromText == b.fromText && a.pos == b.pos && a.toText == b.toText
+	})
+
 	for i, tt := range tests {
 		t.Run(fmt.Sprintf("test #%v: %v", i, tt.name), func(t *testing.T) {
 			got := sortAndMergeFileEdits(tt.fileEdits)
@@ -445,7 +449,7 @@ func TestSortAndMergeFileEdits(t *testing.T) {
 				if i < len(tt.want) {
 					wantFileEdit = tt.want[i]
 				}
-				if !cmp.Equal(got[i], wantFileEdit) {
+				if !cmp.Equal(got[i], wantFileEdit, fileEditEqual) {
 					t.Errorf("got[%v] =\n%#v\nwant[%v]:\n%#v", i, got[i], i, wantFileEdit)
 				}
 			}
@@ -538,6 +542,13 @@ func TestGitURL(t *testing.T) {
 	}
 }
 
+var endpointEqual = cmp.Comparer(func(a, b *Endpoint) bool {
+	if a.httpMethod != b.httpMethod {
+		return false
+	}
+	return cmp.Equal(a.urlFormats, b.urlFormats)
+})
+
 func testWebPageHelper(t *testing.T, got, want map[string][]*Endpoint) {
 	t.Helper()
 
@@ -551,7 +562,7 @@ func testWebPageHelper(t *testing.T, got, want map[string][]*Endpoint) {
 			if ok && i < len(w) {
 				wantEndpoint = w[i]
 			}
-			if !cmp.Equal(got[k][i], wantEndpoint) {
+			if !cmp.Equal(got[k][i], wantEndpoint, endpointEqual) {
 				t.Errorf("got[%q][%v] =\n%#v\nwant[%q][%v]:\n%#v", k, i, got[k][i], k, i, wantEndpoint)
 			}
 		}
@@ -590,7 +601,7 @@ func TestParseEndpoint(t *testing.T) {
 		t.Run(fmt.Sprintf("test #%v: %v", i, tt.name), func(t *testing.T) {
 			got := parseEndpoint(tt.s, tt.method)
 
-			if !cmp.Equal(got, tt.want) {
+			if !cmp.Equal(got, tt.want, endpointEqual) {
 				t.Errorf("parseEndpoint = %#v, want %#v", got, tt.want)
 			}
 		})