Repository: google/go-github
Pull request #1820 (2021-03-09 15:15:57)

Audit Log REST API(Beta) Implementation
This PR implements the new AuditLog REST API Beta which was GA-ed recently. 

You can read more about it here: 
https://github.blog/changelog/2021-02-03-audit-log-git-events-and-rest-api-are-now-in-public-beta/

Most notably it exposes 2 new endpoints for Enterprises Accounts only 
* `orgs/<org>/audit-log`
* `enterprises/<enterprise>/audit-log` 

In this PR
* Extend `OrganizationsService` to implement `GetAuditLog` call
* Extend `EnterpriseService` to implement `GetAuditLog` call
* Tests for both services

I chose to put these into 2 separate files because they define 2 separate endpoints (I can be persuaded to have this live in one file if it makes it easier). 
API reference docs : https://docs.github.com/en/rest/reference/orgs#get-the-audit-log-for-an-organization 



gmlewis: Thank you, @sridharavinash - it looks like you might need to run `go generate ./...` as described in our CONTRIBUTING.md guide.

Hey, by the way... do you know what happened to this blog site: https://developer.github.com/changes/ ?  I haven't seen any changes on it since October 1, 2020, and your PR is the first I've seen of a different blog site URL.
sridharavinash: >Thank you, @sridharavinash - it looks like you might need to run go generate ./... as described in our CONTRIBUTING.md guide.

@gmlewis 👋🏾 . I think this was `fmt` failure. Hopefully the last commit fixes that. 

>Hey, by the way... do you know what happened to this blog site: https://developer.github.com/changes/ ? I haven't seen any changes on it since October 1, 2020, and your PR is the first I've seen of a different blog site URL.

Good question. I'll find out more if that's being deprecated. Maybe in favor of OpenAPI descriptions 
 - https://github.com/github/rest-api-description 🤔 . 

Patch:
diff --git a/AUTHORS b/AUTHORS
index cafdf91d..f8b2328d 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -13,6 +13,7 @@
 413x <dedifferentiator@gmail.com>
 Abhinav Gupta <mail@abhinavg.net>
 adrienzieba <adrien.zieba@appdirect.com>
+afdesk <work@afdesk.com>
 Ahmed Hagy <a.akram93@gmail.com>
 Aidan Steele <aidan.steele@glassechidna.com.au>
 Ainsley Chong <ainsley.chong@gmail.com>
@@ -23,7 +24,9 @@ Alec Thomas <alec@swapoff.org>
 Aleks Clark <aleks.clark@gmail.com>
 Alex Bramley <a.bramley@gmail.com>
 Alex Orr <Alexorr.CSE@gmail.com>
+Alex Unger <zyxancf@gmail.com>
 Alexander Harkness <me@bearbin.net>
+Ali Farooq <ali.farooq0@pm.me>
 Allen Sun <shlallen1990@gmail.com>
 Amey Sakhadeo <me@ameyms.com>
 Anders Janmyr <anders@janmyr.com>
@@ -37,22 +40,28 @@ anjanashenoy <anjanashenoy1@gmail.com>
 Anshuman Bhartiya <anshuman.bhartiya@gmail.com>
 Antoine <antoine.tu@mail.mcgill.ca>
 Antoine Pelisse <apelisse@gmail.com>
+Anton Nguyen <afnguyen85@gmail.com>
 Anubha Kushwaha <anubha_bt2k14@dtu.ac.in>
 appilon <apilon@hashicorp.com>
+aprp <doelaudi@gmail.com>
 Aravind <aravindkp@outlook.in>
 Arda Kuyumcu <kuyumcuarda@gmail.com>
 Arıl Bozoluk <arilbozoluk@hotmail.com>
+Asier Marruedo <asiermarruedo@gmail.com>
 Austin Burdine <acburdine@gmail.com>
 Austin Dizzy <dizzy@wow.com>
 Ben Batha <bhbatha@gmail.com>
 Benjamen Keroack <benjamen@dollarshaveclub.com>
 Beshr Kayali <beshrkayali@gmail.com>
 Beyang Liu <beyang.liu@gmail.com>
+Billy Keyes <bluekeyes@gmail.com>
 Billy Lynch <wlynch92@gmail.com>
 Björn Häuser <b.haeuser@rebuy.de>
+boljen <bol.christophe@gmail.com>
 Brad Harris <bmharris@gmail.com>
 Brad Moylan <moylan.brad@gmail.com>
 Bradley Falzon <brad@teambrad.net>
+Bradley McAllister <brad.mcallister@hotmail.com>
 Brandon Cook <phylake@gmail.com>
 Brian Egizi <brian@mojotech.com>
 Bryan Boreham <bryan@weave.works>
@@ -74,6 +83,7 @@ Colin Misare <github.com/cmisare>
 Craig Peterson <cpeterson@stackoverflow.com>
 Cristian Maglie <c.maglie@bug.st>
 Daehyeok Mun <daehyeok@gmail.com>
+Daniel Lanner <lanner.dan@gmail.com>
 Daniel Leavitt <daniel.leavitt@gmail.com>
 Daniel Nilsson <daniel.nilsson1989@gmail.com>
 Daoq <masseto2002@gmail.com>
@@ -81,6 +91,7 @@ Dave Du Cros <davidducros@gmail.com>
 Dave Henderson <dhenderson@gmail.com>
 Dave Protasowski <dprotaso@gmail.com>
 David Deng <daviddengcn@gmail.com>
+David J. M. Karlsen <david@davidkarlsen.com>
 David Jannotta <djannotta@gmail.com>
 David Ji <github.com/davidji99>
 David Lopez Reyes <davidlopezre@gmail.com>
@@ -93,12 +104,14 @@ dmnlk <seikima2demon@gmail.com>
 Don Petersen <don@donpetersen.net>
 Doug Turner <doug.turner@gmail.com>
 Drew Fradette <drew.fradette@gmail.com>
+Dustin Deus <deusdustin@gmail.com>
 Eivind <eivindkn@gmail.com>
 Eli Uriegas <seemethere101@gmail.com>
 Elliott Beach <elliott2.71828@gmail.com>
 Emerson Wood <emersonwood94@gmail.com>
 eperm <staffordworrell@gmail.com>
 Erick Fejta <erick@fejta.com>
+Erik Nobel <hendrik.nobel@transferwise.com>
 erwinvaneyk <erwinvaneyk@gmail.com>
 Evan Elias <evanjelias@gmail.com>
 Fabrice <fabrice.vaillant@student.ecp.fr>
@@ -129,13 +142,18 @@ huydx <doxuanhuy@gmail.com>
 i2bskn <i2bskn@gmail.com>
 Ioannis Georgoulas <igeorgoulas21@gmail.com>
 Isao Jonas <isao.jonas@gmail.com>
+ishan upadhyay <ishanupadhyay412@gmail.com>
 isqua <isqua@isqua.ru>
+Jacob Valdemar <jan@lunar.app>
+Jake Krammer <jake.krammer1@gmail.com>
 Jameel Haffejee <RC1140@republiccommandos.co.za>
 James Cockbain <james.cockbain@ibm.com>
 Jan Kosecki <jan.kosecki91@gmail.com>
 Javier Campanini <jcampanini@palantir.com>
+Jef LeCompte <jeffreylec@gmail.com>
 Jens Rantil <jens.rantil@gmail.com>
 Jeremy Morris <jeremylevanmorris@gmail.com>
+Jesse Haka <haka.jesse@gmail.com>
 Jesse Newland <jesse@jnewland.com>
 Jihoon Chung <j.c@navercorp.com>
 Jimmi Dyson <jimmidyson@gmail.com>
@@ -143,11 +161,13 @@ Joan Saum <joan.saum@epitech.eu>
 Joe Tsai <joetsai@digital-static.net>
 John Barton <jrbarton@gmail.com>
 John Engelman <john.r.engelman@gmail.com>
+John Liu <john.liu@mongodb.com>
 Jordan Brockopp <jdbro94@gmail.com>
 Jordan Sussman <jordansail22@gmail.com>
 Joshua Bezaleel Abednego <joshua.bezaleel@gmail.com>
 JP Phillips <jonphill9@gmail.com>
 jpbelanger-mtl <jp.belanger@gmail.com>
+Juan <juan.rios.28@gmail.com>
 Juan Basso <jrbasso@gmail.com>
 Julien Garcia Gonzalez <garciagonzalez.julien@gmail.com>
 Julien Rostand <jrostand@users.noreply.github.com>
@@ -164,6 +184,7 @@ Konrad Malawski <konrad.malawski@project13.pl>
 Kookheon Kwon <kucuny@gmail.com>
 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
 Kshitij Saraogi <KshitijSaraogi@gmail.com>
+Kumar Saurabh <itsksaurabh@gmail.com>
 kyokomi <kyoko1220adword@gmail.com>
 Laurent Verdoïa <verdoialaurent@gmail.com>
 Liam Galvin <liam@liam-galvin.co.uk>
@@ -175,7 +196,9 @@ Luke Roberts <email@luke-roberts.co.uk>
 Luke Young <luke@hydrantlabs.org>
 lynn [they] <lynncyrin@gmail.com>
 Maksim Zhylinski <uzzable@gmail.com>
+Marcelo Carlos <marcelo@permutive.com>
 Mark Tareshawty <tarebyte@github.com>
+Martin Holman <me@martinholman.co.nz>
 Martin-Louis Bright <mlbright@gmail.com>
 Martins Sipenko <martins.sipenko@gmail.com>
 Marwan Sulaiman <marwan.sameer@gmail.com>
@@ -185,22 +208,28 @@ Matt <alpmatthew@gmail.com>
 Matt Brender <mjbrender@gmail.com>
 Matt Gaunt <matt@gauntface.co.uk>
 Matt Landis <landis.matt@gmail.com>
+Matt Moore <mattmoor@vmware.com>
 Maxime Bury <maxime.bury@gmail.com>
 Michael Spiegel <michael.m.spiegel@gmail.com>
 Michael Tiller <michael.tiller@gmail.com>
 Michał Glapa <michal.glapa@gmail.com>
+Michelangelo Morrillo <michelangelo@morrillo.it>
+Mukundan Senthil <mukundan314@gmail.com>
 Nadav Kaner <nadavkaner1@gmail.com>
 Nathan VanBenschoten <nvanbenschoten@gmail.com>
 Navaneeth Suresh <navaneeths1998@gmail.com>
 Neil O'Toole <neilotoole@apache.org>
 Nick Miyake <nmiyake@palantir.com>
+Nick Platt <hello@nickplatt.co.uk>
 Nick Spragg <nick.spragg@bbc.co.uk>
 Nikhita Raghunath <nikitaraghunath@gmail.com>
+Nilesh Singh <nilesh.singh24@outlook.com>
 Noah Zoschke <noah+sso2@convox.com>
 ns-cweber <cweber@narrativescience.com>
 Ole Orhagen <ole.orhagen@northern.tech>
 Oleg Kovalov <iamolegkovalov@gmail.com>
 Ondřej Kupka <ondra.cap@gmail.com>
+Pablo Pérez Schröder <pablo.perezschroder@wetransfer.com>
 Palash Nigam <npalash25@gmail.com>
 Panagiotis Moustafellos <pmoust@gmail.com>
 Parham Alvani <parham.alvani@gmail.com>
@@ -213,6 +242,7 @@ Pete Wagner <thepwagner@github.com>
 Petr Shevtsov <petr.shevtsov@gmail.com>
 Pierre Carrier <pierre@meteor.com>
 Piotr Zurek <p.zurek@gmail.com>
+Piyush Chugh <piyushchugh1993@gmail.com>
 Pratik Mallya <pratik.mallya@gmail.com>
 Qais Patankar <qaisjp@gmail.com>
 Quang Le Hong <iamquang95@gmail.com>
@@ -228,12 +258,15 @@ Ravi Shekhar Jethani <rsjethani@gmail.com>
 RaviTeja Pothana <ravi-teja@live.com>
 rc1140 <jameel@republiccommandos.co.za>
 Red Hat, Inc.
+Reetuparna Mukherjee <reetuparna.1988@gmail.com>
 Reinier Timmer <reinier.timmer@ah.nl>
+Renjith R <renjithr201097@gmail.com>
 Ricco Førgaard <ricco@fiskeben.dk>
 Rob Figueiredo <robfig@yext.com>
 Rohit Upadhyay <urohit011@gmail.com>
 Ronak Jain <ronakjain@outlook.in>
 Ruben Vereecken <rubenvereecken@gmail.com>
+Russell Boley <raboley@gmail.com>
 Ryan Leung <rleungx@gmail.com>
 Ryan Lower <rpjlower@gmail.com>
 Ryo Nakao <nakabonne@gmail.com>
@@ -251,6 +284,7 @@ Sebastian Mandrean <sebastian.mandrean@gmail.com>
 Sebastian Mæland Pedersen <sem.pedersen@stud.uis.no>
 Sergey Romanov <xxsmotur@gmail.com>
 Sergio Garcia <sergio.garcia@gmail.com>
+Seth Vargo <seth@sethvargo.com>
 Sevki <s@sevki.org>
 Shagun Khemka <shagun.khemka60@gmail.com>
 shakeelrao <shakeelrao79@gmail.com>
@@ -258,17 +292,23 @@ Shawn Catanzarite <me@shawncatz.com>
 Shawn Smith <shawnpsmith@gmail.com>
 Shibasis Patel <patelshibasis@gmail.com>
 Shrikrishna Singh <krishnasingh.ss30@gmail.com>
+Simon Davis <sdavis@hashicorp.com>
 sona-tar <sona.zip@gmail.com>
 SoundCloud, Ltd.
 Sridhar Mocherla <srmocher@microsoft.com>
 SriVignessh Pss <sriknowledge@gmail.com>
 Stefan Sedich <stefan.sedich@gmail.com>
+Steve Teuber <github@steveteuber.com>
 Stian Eikeland <stian@eikeland.se>
 Suhaib Mujahid <suhaibmujahid@gmail.com>
 Szymon Kodrebski <simonkey007@gmail.com>
+Søren Hansen <soren@dinero.dk>
 Takayuki Watanabe <takanabe.w@gmail.com>
+Taketoshi Fujiwara <fujiwara@leapmind.io>
 Taketoshi Fujiwara <taketoshi.fujiwara@gmail.com>
 Tasya Aditya Rukmana <tadityar@gmail.com>
+Theo Henson <theodorehenson@protonmail.com>
+Thomas Aidan Curran <thomas@ory.sh>
 Thomas Bruyelle <thomas.bruyelle@gmail.com>
 Timothée Peignier <timothee.peignier@tryphon.org>
 tkhandel <tarunkhandelwal.iitr@gmail.com>
diff --git a/github/enterprise_audit_log.go b/github/enterprise_audit_log.go
new file mode 100644
index 00000000..b889a7e5
--- /dev/null
+++ b/github/enterprise_audit_log.go
@@ -0,0 +1,35 @@
+// 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"
+)
+
+// GetAuditLog gets the audit-log entries for an organization.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/enterprise-admin#get-the-audit-log-for-an-enterprise
+func (s *EnterpriseService) GetAuditLog(ctx context.Context, enterprise string, opts *GetAuditLogOptions) ([]*AuditEntry, *Response, error) {
+	u := fmt.Sprintf("enterprises/%v/audit-log", enterprise)
+	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 auditEntries []*AuditEntry
+	resp, err := s.client.Do(ctx, req, &auditEntries)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return auditEntries, resp, nil
+}
diff --git a/github/github-accessors.go b/github/github-accessors.go
index eba8d4cb..d6e13c1b 100644
--- a/github/github-accessors.go
+++ b/github/github-accessors.go
@@ -524,6 +524,430 @@ func (a *Attachment) GetTitle() string {
 	return *a.Title
 }
 
+// GetAction returns the Action field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetAction() string {
+	if a == nil || a.Action == nil {
+		return ""
+	}
+	return *a.Action
+}
+
+// GetActive returns the Active field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetActive() bool {
+	if a == nil || a.Active == nil {
+		return false
+	}
+	return *a.Active
+}
+
+// GetActiveWas returns the ActiveWas field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetActiveWas() bool {
+	if a == nil || a.ActiveWas == nil {
+		return false
+	}
+	return *a.ActiveWas
+}
+
+// GetActor returns the Actor field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetActor() string {
+	if a == nil || a.Actor == nil {
+		return ""
+	}
+	return *a.Actor
+}
+
+// GetBlockedUser returns the BlockedUser field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetBlockedUser() string {
+	if a == nil || a.BlockedUser == nil {
+		return ""
+	}
+	return *a.BlockedUser
+}
+
+// GetBusiness returns the Business field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetBusiness() string {
+	if a == nil || a.Business == nil {
+		return ""
+	}
+	return *a.Business
+}
+
+// GetCancelledAt returns the CancelledAt field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetCancelledAt() Timestamp {
+	if a == nil || a.CancelledAt == nil {
+		return Timestamp{}
+	}
+	return *a.CancelledAt
+}
+
+// GetCompletedAt returns the CompletedAt field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetCompletedAt() Timestamp {
+	if a == nil || a.CompletedAt == nil {
+		return Timestamp{}
+	}
+	return *a.CompletedAt
+}
+
+// GetConclusion returns the Conclusion field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetConclusion() string {
+	if a == nil || a.Conclusion == nil {
+		return ""
+	}
+	return *a.Conclusion
+}
+
+// GetConfig returns the Config field.
+func (a *AuditEntry) GetConfig() *HookConfig {
+	if a == nil {
+		return nil
+	}
+	return a.Config
+}
+
+// GetConfigWas returns the ConfigWas field.
+func (a *AuditEntry) GetConfigWas() *HookConfig {
+	if a == nil {
+		return nil
+	}
+	return a.ConfigWas
+}
+
+// GetContentType returns the ContentType field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetContentType() string {
+	if a == nil || a.ContentType == nil {
+		return ""
+	}
+	return *a.ContentType
+}
+
+// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetCreatedAt() Timestamp {
+	if a == nil || a.CreatedAt == nil {
+		return Timestamp{}
+	}
+	return *a.CreatedAt
+}
+
+// GetDeployKeyFingerprint returns the DeployKeyFingerprint field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetDeployKeyFingerprint() string {
+	if a == nil || a.DeployKeyFingerprint == nil {
+		return ""
+	}
+	return *a.DeployKeyFingerprint
+}
+
+// GetDocumentID returns the DocumentID field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetDocumentID() string {
+	if a == nil || a.DocumentID == nil {
+		return ""
+	}
+	return *a.DocumentID
+}
+
+// GetEmoji returns the Emoji field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetEmoji() string {
+	if a == nil || a.Emoji == nil {
+		return ""
+	}
+	return *a.Emoji
+}
+
+// GetEnvironmentName returns the EnvironmentName field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetEnvironmentName() string {
+	if a == nil || a.EnvironmentName == nil {
+		return ""
+	}
+	return *a.EnvironmentName
+}
+
+// GetEvent returns the Event field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetEvent() string {
+	if a == nil || a.Event == nil {
+		return ""
+	}
+	return *a.Event
+}
+
+// GetExplanation returns the Explanation field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetExplanation() string {
+	if a == nil || a.Explanation == nil {
+		return ""
+	}
+	return *a.Explanation
+}
+
+// GetFingerprint returns the Fingerprint field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetFingerprint() string {
+	if a == nil || a.Fingerprint == nil {
+		return ""
+	}
+	return *a.Fingerprint
+}
+
+// GetHeadBranch returns the HeadBranch field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetHeadBranch() string {
+	if a == nil || a.HeadBranch == nil {
+		return ""
+	}
+	return *a.HeadBranch
+}
+
+// GetHeadSHA returns the HeadSHA field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetHeadSHA() string {
+	if a == nil || a.HeadSHA == nil {
+		return ""
+	}
+	return *a.HeadSHA
+}
+
+// GetHookID returns the HookID field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetHookID() string {
+	if a == nil || a.HookID == nil {
+		return ""
+	}
+	return *a.HookID
+}
+
+// GetIsHostedRunner returns the IsHostedRunner field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetIsHostedRunner() bool {
+	if a == nil || a.IsHostedRunner == nil {
+		return false
+	}
+	return *a.IsHostedRunner
+}
+
+// GetJobName returns the JobName field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetJobName() string {
+	if a == nil || a.JobName == nil {
+		return ""
+	}
+	return *a.JobName
+}
+
+// GetLimitedAvailability returns the LimitedAvailability field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetLimitedAvailability() bool {
+	if a == nil || a.LimitedAvailability == nil {
+		return false
+	}
+	return *a.LimitedAvailability
+}
+
+// GetMessage returns the Message field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetMessage() string {
+	if a == nil || a.Message == nil {
+		return ""
+	}
+	return *a.Message
+}
+
+// GetName returns the Name field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetName() string {
+	if a == nil || a.Name == nil {
+		return ""
+	}
+	return *a.Name
+}
+
+// GetOldUser returns the OldUser field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetOldUser() string {
+	if a == nil || a.OldUser == nil {
+		return ""
+	}
+	return *a.OldUser
+}
+
+// GetOpenSSHPublicKey returns the OpenSSHPublicKey field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetOpenSSHPublicKey() string {
+	if a == nil || a.OpenSSHPublicKey == nil {
+		return ""
+	}
+	return *a.OpenSSHPublicKey
+}
+
+// GetOrg returns the Org field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetOrg() string {
+	if a == nil || a.Org == nil {
+		return ""
+	}
+	return *a.Org
+}
+
+// GetPreviousVisibility returns the PreviousVisibility field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetPreviousVisibility() string {
+	if a == nil || a.PreviousVisibility == nil {
+		return ""
+	}
+	return *a.PreviousVisibility
+}
+
+// GetReadOnly returns the ReadOnly field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetReadOnly() string {
+	if a == nil || a.ReadOnly == nil {
+		return ""
+	}
+	return *a.ReadOnly
+}
+
+// GetRepo returns the Repo field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetRepo() string {
+	if a == nil || a.Repo == nil {
+		return ""
+	}
+	return *a.Repo
+}
+
+// GetRepository returns the Repository field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetRepository() string {
+	if a == nil || a.Repository == nil {
+		return ""
+	}
+	return *a.Repository
+}
+
+// GetRepositoryPublic returns the RepositoryPublic field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetRepositoryPublic() bool {
+	if a == nil || a.RepositoryPublic == nil {
+		return false
+	}
+	return *a.RepositoryPublic
+}
+
+// GetRunnerGroupID returns the RunnerGroupID field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetRunnerGroupID() string {
+	if a == nil || a.RunnerGroupID == nil {
+		return ""
+	}
+	return *a.RunnerGroupID
+}
+
+// GetRunnerGroupName returns the RunnerGroupName field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetRunnerGroupName() string {
+	if a == nil || a.RunnerGroupName == nil {
+		return ""
+	}
+	return *a.RunnerGroupName
+}
+
+// GetRunnerID returns the RunnerID field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetRunnerID() string {
+	if a == nil || a.RunnerID == nil {
+		return ""
+	}
+	return *a.RunnerID
+}
+
+// GetRunnerName returns the RunnerName field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetRunnerName() string {
+	if a == nil || a.RunnerName == nil {
+		return ""
+	}
+	return *a.RunnerName
+}
+
+// GetSourceVersion returns the SourceVersion field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetSourceVersion() string {
+	if a == nil || a.SourceVersion == nil {
+		return ""
+	}
+	return *a.SourceVersion
+}
+
+// GetStartedAt returns the StartedAt field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetStartedAt() Timestamp {
+	if a == nil || a.StartedAt == nil {
+		return Timestamp{}
+	}
+	return *a.StartedAt
+}
+
+// GetTargetLogin returns the TargetLogin field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetTargetLogin() string {
+	if a == nil || a.TargetLogin == nil {
+		return ""
+	}
+	return *a.TargetLogin
+}
+
+// GetTargetVersion returns the TargetVersion field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetTargetVersion() string {
+	if a == nil || a.TargetVersion == nil {
+		return ""
+	}
+	return *a.TargetVersion
+}
+
+// GetTeam returns the Team field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetTeam() string {
+	if a == nil || a.Team == nil {
+		return ""
+	}
+	return *a.Team
+}
+
+// GetTimestamp returns the Timestamp field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetTimestamp() Timestamp {
+	if a == nil || a.Timestamp == nil {
+		return Timestamp{}
+	}
+	return *a.Timestamp
+}
+
+// GetTransportProtocol returns the TransportProtocol field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetTransportProtocol() int {
+	if a == nil || a.TransportProtocol == nil {
+		return 0
+	}
+	return *a.TransportProtocol
+}
+
+// GetTransportProtocolName returns the TransportProtocolName field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetTransportProtocolName() string {
+	if a == nil || a.TransportProtocolName == nil {
+		return ""
+	}
+	return *a.TransportProtocolName
+}
+
+// GetTriggerID returns the TriggerID field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetTriggerID() int64 {
+	if a == nil || a.TriggerID == nil {
+		return 0
+	}
+	return *a.TriggerID
+}
+
+// GetUser returns the User field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetUser() string {
+	if a == nil || a.User == nil {
+		return ""
+	}
+	return *a.User
+}
+
+// GetVisibility returns the Visibility field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetVisibility() string {
+	if a == nil || a.Visibility == nil {
+		return ""
+	}
+	return *a.Visibility
+}
+
+// GetWorkflowID returns the WorkflowID field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetWorkflowID() int64 {
+	if a == nil || a.WorkflowID == nil {
+		return 0
+	}
+	return *a.WorkflowID
+}
+
+// GetWorkflowRunID returns the WorkflowRunID field if it's non-nil, zero value otherwise.
+func (a *AuditEntry) GetWorkflowRunID() int64 {
+	if a == nil || a.WorkflowRunID == nil {
+		return 0
+	}
+	return *a.WorkflowRunID
+}
+
 // GetApp returns the App field.
 func (a *Authorization) GetApp() *AuthorizationApp {
 	if a == nil {
@@ -3404,6 +3828,30 @@ func (f *ForkEvent) GetSender() *User {
 	return f.Sender
 }
 
+// GetInclude returns the Include field if it's non-nil, zero value otherwise.
+func (g *GetAuditLogOptions) GetInclude() string {
+	if g == nil || g.Include == nil {
+		return ""
+	}
+	return *g.Include
+}
+
+// GetOrder returns the Order field if it's non-nil, zero value otherwise.
+func (g *GetAuditLogOptions) GetOrder() string {
+	if g == nil || g.Order == nil {
+		return ""
+	}
+	return *g.Order
+}
+
+// GetPhrase returns the Phrase field if it's non-nil, zero value otherwise.
+func (g *GetAuditLogOptions) GetPhrase() string {
+	if g == nil || g.Phrase == nil {
+		return ""
+	}
+	return *g.Phrase
+}
+
 // GetComments returns the Comments field if it's non-nil, zero value otherwise.
 func (g *Gist) GetComments() int {
 	if g == nil || g.Comments == nil {
@@ -4060,6 +4508,30 @@ func (h *Hook) GetURL() string {
 	return *h.URL
 }
 
+// GetContentType returns the ContentType field if it's non-nil, zero value otherwise.
+func (h *HookConfig) GetContentType() string {
+	if h == nil || h.ContentType == nil {
+		return ""
+	}
+	return *h.ContentType
+}
+
+// GetInsecureSSL returns the InsecureSSL field if it's non-nil, zero value otherwise.
+func (h *HookConfig) GetInsecureSSL() string {
+	if h == nil || h.InsecureSSL == nil {
+		return ""
+	}
+	return *h.InsecureSSL
+}
+
+// GetURL returns the URL field if it's non-nil, zero value otherwise.
+func (h *HookConfig) GetURL() string {
+	if h == nil || h.URL == nil {
+		return ""
+	}
+	return *h.URL
+}
+
 // GetActiveHooks returns the ActiveHooks field if it's non-nil, zero value otherwise.
 func (h *HookStats) GetActiveHooks() int {
 	if h == nil || h.ActiveHooks == nil {
diff --git a/github/github.go b/github/github.go
index e9dfa923..4489dab2 100644
--- a/github/github.go
+++ b/github/github.go
@@ -204,6 +204,12 @@ type ListCursorOptions struct {
 
 	// For paginated result sets, the number of results to include per page.
 	PerPage int `url:"per_page,omitempty"`
+
+	// A cursor, as given in the Link header. If specified, the query only searches for events after this cursor.
+	After string `url:"after,omitempty"`
+
+	// A cursor, as given in the Link header. If specified, the query only searches for events before this cursor.
+	Before string `url:"before,omitempty"`
 }
 
 // UploadOptions specifies the parameters to methods that support uploads.
diff --git a/github/orgs_audit_log.go b/github/orgs_audit_log.go
new file mode 100644
index 00000000..e91f0009
--- /dev/null
+++ b/github/orgs_audit_log.go
@@ -0,0 +1,113 @@
+// 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"
+)
+
+// GetAuditLogOptions sets up optional parameters to query audit-log endpoint.
+type GetAuditLogOptions struct {
+	Phrase  *string `json:"phrase,omitempty"`  // A search phrase. (Optional.)
+	Include *string `json:"include,omitempty"` // Event type includes. Can be one of "web", "git", "all". Default: "web". (Optional.)
+	Order   *string `json:"order,omitempty"`   // The order of audit log events. Can be one of "asc" or "desc". Default: "desc". (Optional.)
+
+	ListCursorOptions
+}
+
+// HookConfig describes metadata about a webhook configuration.
+type HookConfig struct {
+	ContentType *string `json:"content_type,omitempty"`
+	InsecureSSL *string `json:"insecure_ssl,omitempty"`
+	URL         *string `json:"url,omitempty"`
+}
+
+// AuditEntry describes the fields that may be represented by various audit-log "action" entries.
+// For a list of actions see - https://docs.github.com/en/github/setting-up-and-managing-organizations-and-teams/reviewing-the-audit-log-for-your-organization#audit-log-actions
+type AuditEntry struct {
+	Action                *string     `json:"action,omitempty"` // The name of the action that was performed, for example `user.login` or `repo.create`.
+	Active                *bool       `json:"active,omitempty"`
+	ActiveWas             *bool       `json:"active_was,omitempty"`
+	Actor                 *string     `json:"actor,omitempty"` // The actor who performed the action.
+	BlockedUser           *string     `json:"blocked_user,omitempty"`
+	Business              *string     `json:"business,omitempty"`
+	CancelledAt           *Timestamp  `json:"cancelled_at,omitempty"`
+	CompletedAt           *Timestamp  `json:"completed_at,omitempty"`
+	Conclusion            *string     `json:"conclusion,omitempty"`
+	Config                *HookConfig `json:"config,omitempty"`
+	ConfigWas             *HookConfig `json:"config_was,omitempty"`
+	ContentType           *string     `json:"content_type,omitempty"`
+	CreatedAt             *Timestamp  `json:"created_at,omitempty"`
+	DeployKeyFingerprint  *string     `json:"deploy_key_fingerprint,omitempty"`
+	DocumentID            *string     `json:"_document_id,omitempty"`
+	Emoji                 *string     `json:"emoji,omitempty"`
+	EnvironmentName       *string     `json:"environment_name,omitempty"`
+	Event                 *string     `json:"event,omitempty"`
+	Events                []string    `json:"events,omitempty"`
+	EventsWere            []string    `json:"events_were,omitempty"`
+	Explanation           *string     `json:"explanation,omitempty"`
+	Fingerprint           *string     `json:"fingerprint,omitempty"`
+	HeadBranch            *string     `json:"head_branch,omitempty"`
+	HeadSHA               *string     `json:"head_sha,omitempty"`
+	HookID                *string     `json:"hook_id,omitempty"`
+	IsHostedRunner        *bool       `json:"is_hosted_runner,omitempty"`
+	JobName               *string     `json:"job_name,omitempty"`
+	LimitedAvailability   *bool       `json:"limited_availability,omitempty"`
+	Message               *string     `json:"message,omitempty"`
+	Name                  *string     `json:"name,omitempty"`
+	OldUser               *string     `json:"old_user,omitempty"`
+	OpenSSHPublicKey      *string     `json:"openssh_public_key,omitempty"`
+	Org                   *string     `json:"org,omitempty"`
+	PreviousVisibility    *string     `json:"previous_visibility,omitempty"`
+	ReadOnly              *string     `json:"read_only,omitempty"`
+	Repo                  *string     `json:"repo,omitempty"`
+	Repository            *string     `json:"repository,omitempty"`
+	RepositoryPublic      *bool       `json:"repository_public,omitempty"`
+	RunnerGroupID         *string     `json:"runner_group_id,omitempty"`
+	RunnerGroupName       *string     `json:"runner_group_name,omitempty"`
+	RunnerID              *string     `json:"runner_id,omitempty"`
+	RunnerLabels          []string    `json:"runner_labels,omitempty"`
+	RunnerName            *string     `json:"runner_name,omitempty"`
+	SecretsPassed         []string    `json:"secrets_passed,omitempty"`
+	SourceVersion         *string     `json:"source_version,omitempty"`
+	StartedAt             *Timestamp  `json:"started_at,omitempty"`
+	TargetLogin           *string     `json:"target_login,omitempty"`
+	TargetVersion         *string     `json:"target_version,omitempty"`
+	Team                  *string     `json:"team,omitempty"`
+	Timestamp             *Timestamp  `json:"@timestamp,omitempty"`              // The time the audit log event occurred, given as a [Unix timestamp](http://en.wikipedia.org/wiki/Unix_time).
+	TransportProtocolName *string     `json:"transport_protocol_name,omitempty"` // A human readable name for the protocol (for example, HTTP or SSH) used to transfer Git data.
+	TransportProtocol     *int        `json:"transport_protocol,omitempty"`      // The type of protocol (for example, HTTP=1 or SSH=2) used to transfer Git data.
+	TriggerID             *int64      `json:"trigger_id,omitempty"`
+	User                  *string     `json:"user,omitempty"`       // The user that was affected by the action performed (if available).
+	Visibility            *string     `json:"visibility,omitempty"` // The repository visibility, for example `public` or `private`.
+	WorkflowID            *int64      `json:"workflow_id,omitempty"`
+	WorkflowRunID         *int64      `json:"workflow_run_id,omitempty"`
+}
+
+// GetAuditLog gets the audit-log entries for an organization.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/orgs#get-the-audit-log-for-an-organization
+func (s *OrganizationsService) GetAuditLog(ctx context.Context, org string, opts *GetAuditLogOptions) ([]*AuditEntry, *Response, error) {
+	u := fmt.Sprintf("orgs/%v/audit-log", 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
+	}
+
+	var auditEntries []*AuditEntry
+	resp, err := s.client.Do(ctx, req, &auditEntries)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return auditEntries, resp, nil
+}
diff --git a/github/pulls_reviews.go b/github/pulls_reviews.go
index a917108d..becd2e00 100644
--- a/github/pulls_reviews.go
+++ b/github/pulls_reviews.go
@@ -101,10 +101,6 @@ func (r PullRequestReviewDismissalRequest) String() string {
 
 // ListReviews lists all reviews on the specified pull request.
 //
-// TODO: Follow up with GitHub support about an issue with this method's
-// returned error format and remove this comment once it's fixed.
-// Read more about it here - https://github.com/google/go-github/issues/540
-//
 // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/pulls/#list-reviews-for-a-pull-request
 func (s *PullRequestsService) ListReviews(ctx context.Context, owner, repo string, number int, opts *ListOptions) ([]*PullRequestReview, *Response, error) {
 	u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews", owner, repo, number)


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index cb8e77b3..ffef1176 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -1,4 +1,11 @@
-on: [push, pull_request]
+on:
+  push:
+    branches:
+    - master
+  pull_request:
+    branches:
+    - master
+
 name: tests
 env:
   GO111MODULE: on
@@ -8,20 +15,35 @@ jobs:
     strategy:
       matrix:
         go-version: [1.x, 1.15.x]
-        platform: [ubuntu-latest, windows-latest]
+        platform: [ubuntu-latest]
+        include:
+          # include windows, but only with the latest Go version, since there
+          # is very little in the library that is platform specific
+          - go-version: 1.x
+            platform: windows-latest
+
+          # only update test coverage stats with the most recent go version on linux
+          - go-version: 1.x
+            platform: ubuntu-latest
+            update-coverage: true
     runs-on: ${{ matrix.platform }}
 
     steps:
+    - name: Cancel previous
+      uses: styfle/cancel-workflow-action@0.8.0
+      with:
+        access_token: ${{ github.token }}
+
     - uses: actions/setup-go@v1
       with:
         go-version: ${{ matrix.go-version }}
     - uses: actions/checkout@v2
 
     - name: Cache go modules
-      uses: actions/cache@v1
+      uses: actions/cache@v2
       with:
         path: ~/go/pkg/mod
-        key: ${{ runner.os }}-go-${{ hashFiles('go.sum') }}
+        key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
         restore-keys: ${{ runner.os }}-go-
 
     - name: Run go fmt
@@ -48,6 +70,7 @@ jobs:
         go test ./...
 
     - name: Upload coverage to Codecov
+      if: ${{ matrix.update-coverage }}
       uses: codecov/codecov-action@v1
       with:
         token: ${{ secrets.CODECOV_TOKEN }}
diff --git a/github/enterprise_audit_log_test.go b/github/enterprise_audit_log_test.go
new file mode 100644
index 00000000..2e13408e
--- /dev/null
+++ b/github/enterprise_audit_log_test.go
@@ -0,0 +1,99 @@
+// 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"
+	"net/http"
+	"reflect"
+	"testing"
+	"time"
+)
+
+func TestEnterpriseService_GetAuditLog(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprises/e/audit-log", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+
+		fmt.Fprint(w, `[
+		{
+        "workflow_id": 123456,
+        "head_branch": "master",
+        "org": "o",
+        "trigger_id": null,
+        "repo": "o/blue-crayon-1",
+        "created_at": 1615077308538,
+        "head_sha": "5acdeadbeef64d1a62388e901e5cdc9358644b37",
+        "conclusion": "success",
+        "actor": "testactor",
+        "completed_at": "2021-03-07T00:35:08.000Z",
+        "@timestamp": 1615077308538,
+        "name": "Code scanning - action",
+        "action": "workflows.completed_workflow_run",
+        "started_at": "2021-03-07T00:33:04.000Z",
+        "event": "schedule",
+        "workflow_run_id": 628312345,
+        "_document_id": "beeZYapIUe-wKg5-beadb33"
+		}
+		]`)
+	})
+	getOpts := GetAuditLogOptions{
+		Include: String("all"),
+		Phrase:  String("action:workflows"),
+		Order:   String("asc"),
+	}
+	ctx := context.Background()
+	auditEntries, _, err := client.Enterprise.GetAuditLog(ctx, "e", &getOpts)
+	if err != nil {
+		t.Errorf("Enterprise.GetAuditLog returned error: %v", err)
+	}
+	startedAt, _ := time.Parse(time.RFC3339, "2021-03-07T00:33:04.000Z")
+	completedAt, _ := time.Parse(time.RFC3339, "2021-03-07T00:35:08.000Z")
+	timestamp := time.Unix(1615077308538, 0)
+
+	want := []*AuditEntry{
+		{
+			Timestamp:     &Timestamp{timestamp},
+			DocumentID:    String("beeZYapIUe-wKg5-beadb33"),
+			Action:        String("workflows.completed_workflow_run"),
+			Actor:         String("testactor"),
+			CompletedAt:   &Timestamp{completedAt},
+			Conclusion:    String("success"),
+			CreatedAt:     &Timestamp{timestamp},
+			Event:         String("schedule"),
+			HeadBranch:    String("master"),
+			HeadSHA:       String("5acdeadbeef64d1a62388e901e5cdc9358644b37"),
+			Name:          String("Code scanning - action"),
+			Org:           String("o"),
+			Repo:          String("o/blue-crayon-1"),
+			StartedAt:     &Timestamp{startedAt},
+			WorkflowID:    Int64(123456),
+			WorkflowRunID: Int64(628312345),
+		},
+	}
+
+	if !reflect.DeepEqual(auditEntries, want) {
+		t.Errorf("Enterprise.GetAuditLog return \ngot: %+v,\nwant:%+v", auditEntries, want)
+	}
+
+	const methodName = "GetAuditLog"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Enterprise.GetAuditLog(ctx, "\n", &getOpts)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Enterprise.GetAuditLog(ctx, "o", &GetAuditLogOptions{})
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+
+}
diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go
index 53d459b0..bc4ff4e2 100644
--- a/github/github-accessors_test.go
+++ b/github/github-accessors_test.go
@@ -611,6 +611,530 @@ func TestAttachment_GetTitle(tt *testing.T) {
 	a.GetTitle()
 }
 
+func TestAuditEntry_GetAction(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{Action: &zeroValue}
+	a.GetAction()
+	a = &AuditEntry{}
+	a.GetAction()
+	a = nil
+	a.GetAction()
+}
+
+func TestAuditEntry_GetActive(tt *testing.T) {
+	var zeroValue bool
+	a := &AuditEntry{Active: &zeroValue}
+	a.GetActive()
+	a = &AuditEntry{}
+	a.GetActive()
+	a = nil
+	a.GetActive()
+}
+
+func TestAuditEntry_GetActiveWas(tt *testing.T) {
+	var zeroValue bool
+	a := &AuditEntry{ActiveWas: &zeroValue}
+	a.GetActiveWas()
+	a = &AuditEntry{}
+	a.GetActiveWas()
+	a = nil
+	a.GetActiveWas()
+}
+
+func TestAuditEntry_GetActor(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{Actor: &zeroValue}
+	a.GetActor()
+	a = &AuditEntry{}
+	a.GetActor()
+	a = nil
+	a.GetActor()
+}
+
+func TestAuditEntry_GetBlockedUser(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{BlockedUser: &zeroValue}
+	a.GetBlockedUser()
+	a = &AuditEntry{}
+	a.GetBlockedUser()
+	a = nil
+	a.GetBlockedUser()
+}
+
+func TestAuditEntry_GetBusiness(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{Business: &zeroValue}
+	a.GetBusiness()
+	a = &AuditEntry{}
+	a.GetBusiness()
+	a = nil
+	a.GetBusiness()
+}
+
+func TestAuditEntry_GetCancelledAt(tt *testing.T) {
+	var zeroValue Timestamp
+	a := &AuditEntry{CancelledAt: &zeroValue}
+	a.GetCancelledAt()
+	a = &AuditEntry{}
+	a.GetCancelledAt()
+	a = nil
+	a.GetCancelledAt()
+}
+
+func TestAuditEntry_GetCompletedAt(tt *testing.T) {
+	var zeroValue Timestamp
+	a := &AuditEntry{CompletedAt: &zeroValue}
+	a.GetCompletedAt()
+	a = &AuditEntry{}
+	a.GetCompletedAt()
+	a = nil
+	a.GetCompletedAt()
+}
+
+func TestAuditEntry_GetConclusion(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{Conclusion: &zeroValue}
+	a.GetConclusion()
+	a = &AuditEntry{}
+	a.GetConclusion()
+	a = nil
+	a.GetConclusion()
+}
+
+func TestAuditEntry_GetConfig(tt *testing.T) {
+	a := &AuditEntry{}
+	a.GetConfig()
+	a = nil
+	a.GetConfig()
+}
+
+func TestAuditEntry_GetConfigWas(tt *testing.T) {
+	a := &AuditEntry{}
+	a.GetConfigWas()
+	a = nil
+	a.GetConfigWas()
+}
+
+func TestAuditEntry_GetContentType(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{ContentType: &zeroValue}
+	a.GetContentType()
+	a = &AuditEntry{}
+	a.GetContentType()
+	a = nil
+	a.GetContentType()
+}
+
+func TestAuditEntry_GetCreatedAt(tt *testing.T) {
+	var zeroValue Timestamp
+	a := &AuditEntry{CreatedAt: &zeroValue}
+	a.GetCreatedAt()
+	a = &AuditEntry{}
+	a.GetCreatedAt()
+	a = nil
+	a.GetCreatedAt()
+}
+
+func TestAuditEntry_GetDeployKeyFingerprint(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{DeployKeyFingerprint: &zeroValue}
+	a.GetDeployKeyFingerprint()
+	a = &AuditEntry{}
+	a.GetDeployKeyFingerprint()
+	a = nil
+	a.GetDeployKeyFingerprint()
+}
+
+func TestAuditEntry_GetDocumentID(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{DocumentID: &zeroValue}
+	a.GetDocumentID()
+	a = &AuditEntry{}
+	a.GetDocumentID()
+	a = nil
+	a.GetDocumentID()
+}
+
+func TestAuditEntry_GetEmoji(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{Emoji: &zeroValue}
+	a.GetEmoji()
+	a = &AuditEntry{}
+	a.GetEmoji()
+	a = nil
+	a.GetEmoji()
+}
+
+func TestAuditEntry_GetEnvironmentName(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{EnvironmentName: &zeroValue}
+	a.GetEnvironmentName()
+	a = &AuditEntry{}
+	a.GetEnvironmentName()
+	a = nil
+	a.GetEnvironmentName()
+}
+
+func TestAuditEntry_GetEvent(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{Event: &zeroValue}
+	a.GetEvent()
+	a = &AuditEntry{}
+	a.GetEvent()
+	a = nil
+	a.GetEvent()
+}
+
+func TestAuditEntry_GetExplanation(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{Explanation: &zeroValue}
+	a.GetExplanation()
+	a = &AuditEntry{}
+	a.GetExplanation()
+	a = nil
+	a.GetExplanation()
+}
+
+func TestAuditEntry_GetFingerprint(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{Fingerprint: &zeroValue}
+	a.GetFingerprint()
+	a = &AuditEntry{}
+	a.GetFingerprint()
+	a = nil
+	a.GetFingerprint()
+}
+
+func TestAuditEntry_GetHeadBranch(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{HeadBranch: &zeroValue}
+	a.GetHeadBranch()
+	a = &AuditEntry{}
+	a.GetHeadBranch()
+	a = nil
+	a.GetHeadBranch()
+}
+
+func TestAuditEntry_GetHeadSHA(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{HeadSHA: &zeroValue}
+	a.GetHeadSHA()
+	a = &AuditEntry{}
+	a.GetHeadSHA()
+	a = nil
+	a.GetHeadSHA()
+}
+
+func TestAuditEntry_GetHookID(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{HookID: &zeroValue}
+	a.GetHookID()
+	a = &AuditEntry{}
+	a.GetHookID()
+	a = nil
+	a.GetHookID()
+}
+
+func TestAuditEntry_GetIsHostedRunner(tt *testing.T) {
+	var zeroValue bool
+	a := &AuditEntry{IsHostedRunner: &zeroValue}
+	a.GetIsHostedRunner()
+	a = &AuditEntry{}
+	a.GetIsHostedRunner()
+	a = nil
+	a.GetIsHostedRunner()
+}
+
+func TestAuditEntry_GetJobName(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{JobName: &zeroValue}
+	a.GetJobName()
+	a = &AuditEntry{}
+	a.GetJobName()
+	a = nil
+	a.GetJobName()
+}
+
+func TestAuditEntry_GetLimitedAvailability(tt *testing.T) {
+	var zeroValue bool
+	a := &AuditEntry{LimitedAvailability: &zeroValue}
+	a.GetLimitedAvailability()
+	a = &AuditEntry{}
+	a.GetLimitedAvailability()
+	a = nil
+	a.GetLimitedAvailability()
+}
+
+func TestAuditEntry_GetMessage(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{Message: &zeroValue}
+	a.GetMessage()
+	a = &AuditEntry{}
+	a.GetMessage()
+	a = nil
+	a.GetMessage()
+}
+
+func TestAuditEntry_GetName(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{Name: &zeroValue}
+	a.GetName()
+	a = &AuditEntry{}
+	a.GetName()
+	a = nil
+	a.GetName()
+}
+
+func TestAuditEntry_GetOldUser(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{OldUser: &zeroValue}
+	a.GetOldUser()
+	a = &AuditEntry{}
+	a.GetOldUser()
+	a = nil
+	a.GetOldUser()
+}
+
+func TestAuditEntry_GetOpenSSHPublicKey(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{OpenSSHPublicKey: &zeroValue}
+	a.GetOpenSSHPublicKey()
+	a = &AuditEntry{}
+	a.GetOpenSSHPublicKey()
+	a = nil
+	a.GetOpenSSHPublicKey()
+}
+
+func TestAuditEntry_GetOrg(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{Org: &zeroValue}
+	a.GetOrg()
+	a = &AuditEntry{}
+	a.GetOrg()
+	a = nil
+	a.GetOrg()
+}
+
+func TestAuditEntry_GetPreviousVisibility(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{PreviousVisibility: &zeroValue}
+	a.GetPreviousVisibility()
+	a = &AuditEntry{}
+	a.GetPreviousVisibility()
+	a = nil
+	a.GetPreviousVisibility()
+}
+
+func TestAuditEntry_GetReadOnly(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{ReadOnly: &zeroValue}
+	a.GetReadOnly()
+	a = &AuditEntry{}
+	a.GetReadOnly()
+	a = nil
+	a.GetReadOnly()
+}
+
+func TestAuditEntry_GetRepo(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{Repo: &zeroValue}
+	a.GetRepo()
+	a = &AuditEntry{}
+	a.GetRepo()
+	a = nil
+	a.GetRepo()
+}
+
+func TestAuditEntry_GetRepository(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{Repository: &zeroValue}
+	a.GetRepository()
+	a = &AuditEntry{}
+	a.GetRepository()
+	a = nil
+	a.GetRepository()
+}
+
+func TestAuditEntry_GetRepositoryPublic(tt *testing.T) {
+	var zeroValue bool
+	a := &AuditEntry{RepositoryPublic: &zeroValue}
+	a.GetRepositoryPublic()
+	a = &AuditEntry{}
+	a.GetRepositoryPublic()
+	a = nil
+	a.GetRepositoryPublic()
+}
+
+func TestAuditEntry_GetRunnerGroupID(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{RunnerGroupID: &zeroValue}
+	a.GetRunnerGroupID()
+	a = &AuditEntry{}
+	a.GetRunnerGroupID()
+	a = nil
+	a.GetRunnerGroupID()
+}
+
+func TestAuditEntry_GetRunnerGroupName(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{RunnerGroupName: &zeroValue}
+	a.GetRunnerGroupName()
+	a = &AuditEntry{}
+	a.GetRunnerGroupName()
+	a = nil
+	a.GetRunnerGroupName()
+}
+
+func TestAuditEntry_GetRunnerID(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{RunnerID: &zeroValue}
+	a.GetRunnerID()
+	a = &AuditEntry{}
+	a.GetRunnerID()
+	a = nil
+	a.GetRunnerID()
+}
+
+func TestAuditEntry_GetRunnerName(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{RunnerName: &zeroValue}
+	a.GetRunnerName()
+	a = &AuditEntry{}
+	a.GetRunnerName()
+	a = nil
+	a.GetRunnerName()
+}
+
+func TestAuditEntry_GetSourceVersion(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{SourceVersion: &zeroValue}
+	a.GetSourceVersion()
+	a = &AuditEntry{}
+	a.GetSourceVersion()
+	a = nil
+	a.GetSourceVersion()
+}
+
+func TestAuditEntry_GetStartedAt(tt *testing.T) {
+	var zeroValue Timestamp
+	a := &AuditEntry{StartedAt: &zeroValue}
+	a.GetStartedAt()
+	a = &AuditEntry{}
+	a.GetStartedAt()
+	a = nil
+	a.GetStartedAt()
+}
+
+func TestAuditEntry_GetTargetLogin(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{TargetLogin: &zeroValue}
+	a.GetTargetLogin()
+	a = &AuditEntry{}
+	a.GetTargetLogin()
+	a = nil
+	a.GetTargetLogin()
+}
+
+func TestAuditEntry_GetTargetVersion(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{TargetVersion: &zeroValue}
+	a.GetTargetVersion()
+	a = &AuditEntry{}
+	a.GetTargetVersion()
+	a = nil
+	a.GetTargetVersion()
+}
+
+func TestAuditEntry_GetTeam(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{Team: &zeroValue}
+	a.GetTeam()
+	a = &AuditEntry{}
+	a.GetTeam()
+	a = nil
+	a.GetTeam()
+}
+
+func TestAuditEntry_GetTimestamp(tt *testing.T) {
+	var zeroValue Timestamp
+	a := &AuditEntry{Timestamp: &zeroValue}
+	a.GetTimestamp()
+	a = &AuditEntry{}
+	a.GetTimestamp()
+	a = nil
+	a.GetTimestamp()
+}
+
+func TestAuditEntry_GetTransportProtocol(tt *testing.T) {
+	var zeroValue int
+	a := &AuditEntry{TransportProtocol: &zeroValue}
+	a.GetTransportProtocol()
+	a = &AuditEntry{}
+	a.GetTransportProtocol()
+	a = nil
+	a.GetTransportProtocol()
+}
+
+func TestAuditEntry_GetTransportProtocolName(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{TransportProtocolName: &zeroValue}
+	a.GetTransportProtocolName()
+	a = &AuditEntry{}
+	a.GetTransportProtocolName()
+	a = nil
+	a.GetTransportProtocolName()
+}
+
+func TestAuditEntry_GetTriggerID(tt *testing.T) {
+	var zeroValue int64
+	a := &AuditEntry{TriggerID: &zeroValue}
+	a.GetTriggerID()
+	a = &AuditEntry{}
+	a.GetTriggerID()
+	a = nil
+	a.GetTriggerID()
+}
+
+func TestAuditEntry_GetUser(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{User: &zeroValue}
+	a.GetUser()
+	a = &AuditEntry{}
+	a.GetUser()
+	a = nil
+	a.GetUser()
+}
+
+func TestAuditEntry_GetVisibility(tt *testing.T) {
+	var zeroValue string
+	a := &AuditEntry{Visibility: &zeroValue}
+	a.GetVisibility()
+	a = &AuditEntry{}
+	a.GetVisibility()
+	a = nil
+	a.GetVisibility()
+}
+
+func TestAuditEntry_GetWorkflowID(tt *testing.T) {
+	var zeroValue int64
+	a := &AuditEntry{WorkflowID: &zeroValue}
+	a.GetWorkflowID()
+	a = &AuditEntry{}
+	a.GetWorkflowID()
+	a = nil
+	a.GetWorkflowID()
+}
+
+func TestAuditEntry_GetWorkflowRunID(tt *testing.T) {
+	var zeroValue int64
+	a := &AuditEntry{WorkflowRunID: &zeroValue}
+	a.GetWorkflowRunID()
+	a = &AuditEntry{}
+	a.GetWorkflowRunID()
+	a = nil
+	a.GetWorkflowRunID()
+}
+
 func TestAuthorization_GetApp(tt *testing.T) {
 	a := &Authorization{}
 	a.GetApp()
@@ -3962,6 +4486,36 @@ func TestForkEvent_GetSender(tt *testing.T) {
 	f.GetSender()
 }
 
+func TestGetAuditLogOptions_GetInclude(tt *testing.T) {
+	var zeroValue string
+	g := &GetAuditLogOptions{Include: &zeroValue}
+	g.GetInclude()
+	g = &GetAuditLogOptions{}
+	g.GetInclude()
+	g = nil
+	g.GetInclude()
+}
+
+func TestGetAuditLogOptions_GetOrder(tt *testing.T) {
+	var zeroValue string
+	g := &GetAuditLogOptions{Order: &zeroValue}
+	g.GetOrder()
+	g = &GetAuditLogOptions{}
+	g.GetOrder()
+	g = nil
+	g.GetOrder()
+}
+
+func TestGetAuditLogOptions_GetPhrase(tt *testing.T) {
+	var zeroValue string
+	g := &GetAuditLogOptions{Phrase: &zeroValue}
+	g.GetPhrase()
+	g = &GetAuditLogOptions{}
+	g.GetPhrase()
+	g = nil
+	g.GetPhrase()
+}
+
 func TestGist_GetComments(tt *testing.T) {
 	var zeroValue int
 	g := &Gist{Comments: &zeroValue}
@@ -4746,6 +5300,36 @@ func TestHook_GetURL(tt *testing.T) {
 	h.GetURL()
 }
 
+func TestHookConfig_GetContentType(tt *testing.T) {
+	var zeroValue string
+	h := &HookConfig{ContentType: &zeroValue}
+	h.GetContentType()
+	h = &HookConfig{}
+	h.GetContentType()
+	h = nil
+	h.GetContentType()
+}
+
+func TestHookConfig_GetInsecureSSL(tt *testing.T) {
+	var zeroValue string
+	h := &HookConfig{InsecureSSL: &zeroValue}
+	h.GetInsecureSSL()
+	h = &HookConfig{}
+	h.GetInsecureSSL()
+	h = nil
+	h.GetInsecureSSL()
+}
+
+func TestHookConfig_GetURL(tt *testing.T) {
+	var zeroValue string
+	h := &HookConfig{URL: &zeroValue}
+	h.GetURL()
+	h = &HookConfig{}
+	h.GetURL()
+	h = nil
+	h.GetURL()
+}
+
 func TestHookStats_GetActiveHooks(tt *testing.T) {
 	var zeroValue int
 	h := &HookStats{ActiveHooks: &zeroValue}
diff --git a/github/orgs_audit_log_test.go b/github/orgs_audit_log_test.go
new file mode 100644
index 00000000..c6287d87
--- /dev/null
+++ b/github/orgs_audit_log_test.go
@@ -0,0 +1,112 @@
+// 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"
+	"net/http"
+	"reflect"
+	"testing"
+	"time"
+)
+
+func TestOrganizationService_GetAuditLog(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/orgs/o/audit-log", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+
+		fmt.Fprint(w, `[
+		{
+        "active": true,
+        "workflow_id": 123456,
+        "head_branch": "master",
+        "org": "o",
+        "trigger_id": null,
+        "repo": "o/blue-crayon-1",
+        "created_at": 1615077308538,
+        "head_sha": "5acdeadbeef64d1a62388e901e5cdc9358644b37",
+        "conclusion": "success",
+        "actor": "testactor",
+        "completed_at": "2021-03-07T00:35:08.000Z",
+        "@timestamp": 1615077308538,
+        "name": "Code scanning - action",
+        "action": "workflows.completed_workflow_run",
+        "started_at": "2021-03-07T00:33:04.000Z",
+        "event": "schedule",
+        "workflow_run_id": 628312345,
+        "_document_id": "beeZYapIUe-wKg5-beadb33",
+        "config": {
+            "content_type": "json",
+            "insecure_ssl": "0",
+            "url": "https://example.com/deadbeef-new-hook"
+         },
+        "events": ["code_scanning_alert"]
+		}]`)
+	})
+	ctx := context.Background()
+	getOpts := GetAuditLogOptions{
+		Include: String("all"),
+		Phrase:  String("action:workflows"),
+		Order:   String("asc"),
+	}
+
+	auditEntries, _, err := client.Organizations.GetAuditLog(ctx, "o", &getOpts)
+	if err != nil {
+		t.Errorf("Organizations.GetAuditLog returned error: %v", err)
+	}
+	startedAt, _ := time.Parse(time.RFC3339, "2021-03-07T00:33:04.000Z")
+	completedAt, _ := time.Parse(time.RFC3339, "2021-03-07T00:35:08.000Z")
+	timestamp := time.Unix(1615077308538, 0)
+	want := []*AuditEntry{
+		{
+			Timestamp:     &Timestamp{timestamp},
+			DocumentID:    String("beeZYapIUe-wKg5-beadb33"),
+			Action:        String("workflows.completed_workflow_run"),
+			Actor:         String("testactor"),
+			Active:        Bool(true),
+			CompletedAt:   &Timestamp{completedAt},
+			Conclusion:    String("success"),
+			CreatedAt:     &Timestamp{timestamp},
+			Event:         String("schedule"),
+			HeadBranch:    String("master"),
+			HeadSHA:       String("5acdeadbeef64d1a62388e901e5cdc9358644b37"),
+			Name:          String("Code scanning - action"),
+			Org:           String("o"),
+			Repo:          String("o/blue-crayon-1"),
+			StartedAt:     &Timestamp{startedAt},
+			WorkflowID:    Int64(123456),
+			WorkflowRunID: Int64(628312345),
+			Events:        []string{"code_scanning_alert"},
+			Config: &HookConfig{
+				ContentType: String("json"),
+				InsecureSSL: String("0"),
+				URL:         String("https://example.com/deadbeef-new-hook"),
+			},
+		},
+	}
+
+	if !reflect.DeepEqual(auditEntries, want) {
+		t.Errorf("Organizations.GetAuditLog return \ngot: %+v,\nwant:%+v", auditEntries, want)
+	}
+
+	const methodName = "GetAuditLog"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Organizations.GetAuditLog(ctx, "\n", &getOpts)
+		return err
+	})
+
+	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
+		got, resp, err := client.Organizations.GetAuditLog(ctx, "o", &GetAuditLogOptions{})
+		if got != nil {
+			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
+		}
+		return resp, err
+	})
+
+}
diff --git a/test/integration/audit_log_test.go b/test/integration/audit_log_test.go
new file mode 100644
index 00000000..9ed96eda
--- /dev/null
+++ b/test/integration/audit_log_test.go
@@ -0,0 +1,32 @@
+// 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.
+
+// +build integration
+
+package integration
+
+import (
+	"context"
+	"testing"
+)
+
+// TestOrganizationAuditLog test that the client can read an org's audit log
+// Note: Org must be part of an enterprise
+// Test requires auth - set env var GITHUB_AUTH_TOKEN
+func TestOrganizationAuditLog(t *testing.T) {
+	org := "example_org"
+	entries, _, err := client.Organizations.GetAuditLog(context.Background(), org, nil)
+	if err != nil {
+		t.Fatalf("Organizations.GetAuditLog returned error: %v", err)
+	}
+
+	if len(entries) == 0 {
+		t.Errorf("No AuditLog events returned for org")
+	}
+
+	for _, e := range entries {
+		t.Log(e.GetAction(), e.GetActor(), e.GetTimestamp(), e.GetUser(), e.GetActive())
+	}
+}