github.com/massongit/reviewdog@v0.0.0-20240331071725-4a16675475a8/doghouse/server/github.go (about)

     1  package server
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net/http"
     7  
     8  	"github.com/bradleyfalzon/ghinstallation/v2"
     9  	"github.com/google/go-github/v60/github"
    10  )
    11  
    12  type NewGitHubClientOption struct {
    13  	// Required
    14  	PrivateKey []byte
    15  	// Required
    16  	IntegrationID int
    17  
    18  	// RepoOwner is required for installation API.
    19  	RepoOwner string
    20  
    21  	// Optional
    22  	Client *http.Client
    23  }
    24  
    25  func NewGitHubClient(ctx context.Context, opt *NewGitHubClientOption) (*github.Client, error) {
    26  	client := opt.Client
    27  	if client == nil {
    28  		client = http.DefaultClient
    29  	}
    30  
    31  	itr, err := githubAppTransport(ctx, client, opt)
    32  	if err != nil {
    33  		return nil, fmt.Errorf("failed to create gh transport: %w", err)
    34  	}
    35  
    36  	client.Transport = itr
    37  	return github.NewClient(client), nil
    38  }
    39  
    40  func githubAppTransport(ctx context.Context, client *http.Client, opt *NewGitHubClientOption) (http.RoundTripper, error) {
    41  	if opt.RepoOwner == "" {
    42  		return ghinstallation.NewAppsTransport(getTransport(client), int64(opt.IntegrationID), opt.PrivateKey)
    43  	}
    44  	installationID, err := findInstallationID(ctx, opt)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	return ghinstallation.New(getTransport(client), int64(opt.IntegrationID), installationID, opt.PrivateKey)
    49  }
    50  
    51  func getTransport(client *http.Client) http.RoundTripper {
    52  	if client.Transport != nil {
    53  		return client.Transport
    54  	}
    55  	return http.DefaultTransport
    56  }
    57  
    58  func findInstallationID(ctx context.Context, opt *NewGitHubClientOption) (int64, error) {
    59  	appCli, err := NewGitHubClient(ctx, &NewGitHubClientOption{
    60  		PrivateKey:    opt.PrivateKey,
    61  		IntegrationID: opt.IntegrationID,
    62  		Client:        &http.Client{}, // Use different client to get installation.
    63  		// Do no set RepoOwner.
    64  	})
    65  	if err != nil {
    66  		return 0, err
    67  	}
    68  	inst, _, err := appCli.Apps.FindUserInstallation(ctx, opt.RepoOwner)
    69  	if err != nil {
    70  		return 0, err
    71  	}
    72  	return inst.GetID(), nil
    73  }