Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

A simple Go framework for building GitHub Apps

License

NotificationsYou must be signed in to change notification settings

palantir/go-githubapp

Repository files navigation

Autorelease

go-githubappGoDoc

A library for buildingGitHub Apps andother services that handle GitHub webhooks.

The library provides anhttp.Handler implementation that dispatches webhookevents to the correct place, removing boilerplate and letting you focus on thelogic of your application.

Usage

Most users will implementgithubapp.EventHandler for each webhookevent that needs to be handled. A single implementation can also respond tomultiple event types if they require the same actions:

typeCommentHandlerstruct {    githubapp.ClientCreator}func (h*CommentHandler)Handles() []string {return []string{"issue_comment"}}func (h*CommentHandler)Handle(ctx context.Context,eventType,deliveryIDstring,payload []byte)error {// from github.com/google/go-github/githubvarevent github.IssueCommentEventiferr:=json.Unmarshal(payload,&event);err!=nil {returnerr    }// do something with the content of the event}

We recommend embeddinggithubapp.ClientCreator in handler implementations asan easy way to access GitHub clients.

Once you define handlers, register them with an event dispatcher and associateit with a route in anynet/http-compatible HTTP router:

funcregisterRoutes(c githubapp.Config) {cc:=githubapp.NewDefaultCachingClientCreator(c)http.Handle("/api/github/hook",githubapp.NewDefaultEventDispatcher(c,&CommentHandler{cc},// ...    ))}

We recommend usinggo-baseapp as the minimal serverframework for writing github apps, though go-githubapp works well with the standard library andcan be easily integrated into most existing frameworks.

Examples

Theexample package contains a fully functional serverusinggo-githubapp. The example app responds to comments on pull requests bycommenting with a copy of the comment body.

To run the app, updateexample/config.yml with appropriate secrets and thenrun:

./godelw run example

Dependencies

go-githubapp has minimal dependencies, but does make some decisions:

Logging and metrics are only active when they are configured (see below). Thismeans you can add your own logging or metrics libraries without conflict, butwill miss out on the free built-in support.

Asynchronous Dispatch

GitHub imposes timeouts on webhook delivery responses. If an application doesnot respond in time, GitHub closes the connection and marks the delivery asfailed.go-githubapp optionally supports asynchronous dispatch to help solvethis problem. When enabled, the event dispatcher sends a response to GitHub aftervalidating the payload and then runs the event handler in a separate goroutine.

To enable, select an appropriatescheduler and configure the event dispatcherto use it:

dispatcher:=githubapp.NewEventDispatcher(handlers,secret,githubapp.WithScheduler(githubapp.AsyncScheduler(),))

The following schedulers are included in the library:

  • DefaultScheduler - a synchronous scheduler that runs event handlers inthe current goroutine. This is the default mode.

  • AsyncScheduler - an asynchronous scheduler that handles each event in anew goroutine. This is the simplest asynchronous option.

  • QueueAsyncScheduler - an asynchronous scheduler that queues events andhandles them with a fixed pool of worker goroutines. This is useful to limitthe amount of concurrent work.

AsyncScheduler andQueueAsyncScheduler support several additional optionsand customizations; see the documentation for details.

Structured Logging

go-githubapp usesrs/zerolog for structuredlogging. A logger must be stored in thecontext.Context associated with eachhttp.Request:

func (d *EventDispatcher) ServeHTTP(w http.ResponseWriter, r *http.Request) {    logger := zerolog.Ctx(r.Context())    ...}

If there is no logger in the context, log output is disabled. It's expectedthat HTTP middleware, like that provided by thehlog package, configuresthehttp.Request context automatically.

Below are the standard keys used when logging events. They are also exported asconstants.

exported constantkeydefinition
LogKeyEventTypegithub_event_typethegithub event type header
LogKeyDeliveryIDgithub_delivery_idthegithub event delivery id header
LogKeyInstallationIDgithub_installation_idtheinstallation id the app is authenticating with
LogKeyRepositoryNamegithub_repository_namethe repository name of the pull request being acted on
LogKeyRepositoryOwnergithub_repository_ownerthe repository owner of the pull request being acted on
LogKeyPRNumgithub_pr_numthe number of the pull request being acted on

Where appropriate, the library creates derived loggers with the above keys setto the correct values.

GitHub Clients

Authenticated and configured GitHub clients can be retrieved fromgithubapp.ClientCreator implementations. The library provides a basicimplementation and a caching version.

There are three types of clients and two API versions for a total of sixdistinct clients:

  • Anapplication client authenticatesas the application and can onlycall limited APIs that mostly return application metadata.
  • Aninstallation client authenticatesas an installation and can callany APIs where the has been installed and granted permissions.
  • Atoken client authenticates with a static OAuth2 token associated with auser account.

go-githubapp also exposes various configuration options for GitHub clients.These are provided when callinggithubapp.NewClientCreator:

  • githubapp.WithClientUserAgent sets aUser-Agent string for all clients
  • githubapp.WithClientTimeout sets a timeout for requests made by all clients
  • githubapp.WithClientCaching enables response caching for all v3 (REST) clients.The cache can be configured to always validate responses or to respectthe cache headers returned by GitHub. Re-validation is useful if dataoften changes faster than the requested cache duration.
  • githubapp.WithClientMiddleware allows customization of thehttp.RoundTripper used by all clients and is useful if you want to logrequests or emit metrics about GitHub requests and responses.

The library provides the following middleware:

  • githubapp.ClientMetrics emits the standard metrics described below
  • githubapp.ClientLogging logs metadata about all requests and responses
baseHandler,err:=githubapp.NewDefaultCachingClientCreator(config.Github,githubapp.WithClientUserAgent("example-app/1.0.0"),githubapp.WithClientCaching(false,func() httpcache.Cache {returnhttpcache.NewMemoryCache() }),githubapp.WithClientMiddleware(githubapp.ClientMetrics(registry),githubapp.ClientLogging(zerolog.DebugLevel),    ),...)

Metrics

go-githubapp usesrcrowley/go-metrics to provide metrics. Metrics areoptional and disabled by default.

GitHub clients emit the following metrics when configured with thegithubapp.ClientMetrics middleware:

metric nametypedefinition
github.requestscounterthe count of successfully completed requests made to GitHub
github.requests.2xxcounterlikegithub.requests, but only counting 2XX status codes
github.requests.3xxcounterlikegithub.requests, but only counting 3XX status codes
github.requests.4xxcounterlikegithub.requests, but only counting 4XX status codes
github.requests.5xxcounterlikegithub.requests, but only counting 5XX status codes
github.requests.cachedcounterthe count of successfully cached requests
github.rate.limit[installation:<id>]gaugethe maximum number of requests permitted to make per hour, tagged with the installation id
github.rate.remaining[installation:<id>]gaugethe number of requests remaining in the current rate limit window, tagged with the installation id

When usingasynchronous dispatch, thegithubapp.WithSchedulingMetrics option emits the following metrics:

metric nametypedefinition
github.event.queuegaugethe number of queued unprocessed event
github.event.workersgaugethe number of workers actively processing events
github.event.droppedcounterthe number events dropped due to limited queue capacity
github.event.agehistogramthe age (queue time) in milliseconds of events at processing time

TheMetricsErrorCallback andMetricsAsyncErrorCallback error callbacks forthe event dispatcher and asynchronous schedulers emit the following metrics:

metric nametypedefinition
github.handler.error[event:<type>]counterthe number of processing errors, tagged with the GitHub event type

Note that metrics need to be published in order to be useful. Severalpublishing options are available or you can implement your own.

Background Jobs and Multi-Organization Operations

While applications will mostly operate on the installation IDs provided inwebhook payloads, sometimes there is a need to run background jobs or make APIcalls against multiple organizations. In these cases, use anapplicationclient to look up specific installations of the application and then constructaninstallation client to make API calls:

funcgetOrganizationClient(cc githubapp.ClientCreator,orgstring) (*github.Client,error) {// create a client to perform actions as the applicationappClient,err:=cc.NewAppClient()iferr!=nil {returnnil,err    }// look up the installation ID for a particular organizationinstallations:=githubapp.NewInstallationsService(appClient)install,err:=installations.GetByOwner(context.Background(),org)iferr!=nil {returnnil,err    }// create a client to perform actions on that specific organizationreturncc.NewInstallationClient(install.ID)}

Config Loading

Theappconfig package provides a flexible configuration loader for findingrepository configuration. It supports repository-local files, files containingremote references, and organization-level defaults.

By default, the loader will:

  1. Try a list of paths in the repository
  2. If a file exists at a path, load its contents
  3. If the contents define a remote reference, load the remote file. Otherwise,return the contents.
  4. If no files exist in the repository, try a list of paths in a.githubrepository owned by the same owner.

Users can customize the paths, the remote reference encoding, whether remotereferences are enabled, the name of the owner-level default repository, andwhether the owner-level default is enabled.

The standard remote reference encoding is YAML:

remote:owner/repopath:config/app.ymlref:develop

Usage is straightforward:

funcloadConfig(ctx context.Context,client*github.Client,owner,repo,refstring) (*AppConfig,error) {loader:=appconfig.NewLoader([]string{".github/app.yml"})c,err:=loader.LoadConfig(ctx,client,onwer,repo,ref)iferr!=nil {returnnil,err    }ifc.IsUndefined() {returnnil,nil    }varappConfigAppConfigiferr:=yaml.Unmarshal(c.Content,&appConfig);err!=nil {returnnil,err    }return&appConfig,nil}

OAuth2

Theoauth2 package provides anhttp.Handler implementation that simplifiesOAuth2 authentication with GitHub. When a user visits the endpoint, they areredirected to GitHub to authorize the application. GitHub redirects back to thesame endpoint, which performs the code exchange and obtains a token for theuser. The token is passed to a callback for further processing.

funcregisterOAuth2Handler(c githubapp.Config) {http.Handle("/api/auth/github",oauth2.NewHandler(oauth2.GetConfig(c, []string{"user:email"}),// force generated URLs to use HTTPS; useful if the app is behind a reverse proxyoauth2.ForceTLS(true),// set the callback for successful loginsoauth2.OnLogin(func(w http.ResponseWriter,r*http.Request,login*oauth2.Login) {// look up the current user with the authenticated clientclient:=github.NewClient(login.Client)user,_,err:=client.Users.Get(r.Context(),"")// handle error, save the user, ...// redirect the user back to another pagehttp.Redirect(w,r,"/dashboard",http.StatusFound)        }),    ))}

Production applications should also use theoauth2.WithStore option to set asecureStateStore implementation.oauth2.SessionStateStore is a good choicethat usesalexedwards/scs to store thestate in a session.

Customizing Webhook Responses

For most applications, the default responses should be sufficient: they usecorrect status codes and include enough information to match up GitHub deliveryrecords with request logs. If your application has additional requirements forresponses, two methods are provided for customization:

  • Error responses can be modified with a custom error callback. Use theWithErrorCallback option when creating an event dispatcher.

  • Non-error responses can be modified with a custom response callback. Use theWithResponseCallback option when creating an event dispatcher.

  • Individual hook responses can be modified by calling theSetResponderfunction before the handler returns. Note that if you register a customresponse handler as described above, you must make it aware of handler-levelresponders if you want to keep usingSetResponder. See the default responsecallback for an example of how to implement this.

Stability and Versioning Guarantees

While we've used this library to build multiple applications internally,there's still room for API tweaks and improvements as we find better ways tosolve problems. These will be backwards compatible when possible and shouldrequire only minor changes when not.

Releases will be tagged periodically and will follow semantic versioning, withnew major versions tagged after any backwards-incompatible changes. Still, werecommend vendoring this library to avoid surprises.

In general, fixes will only be applied to trunk and future releases, notbackported to older versions.

Contributing

Contributions and issues are welcome. For new features or large contributions,we prefer discussing the proposed change on a GitHub issue prior to a PR.

New functionality should avoid adding new dependencies if possible and shouldbe broadly useful. Feature requests that are specific to certain uses willlikely be declined unless they can be redesigned to be generic or optional.

Before submitting a pull request, please run tests and style checks:

./godelw verify

License

This library is made available under theApache 2.0 License.


[8]ページ先頭

©2009-2025 Movatter.jp