package githubclient import ( "context" "fmt" "net/http" "regexp" "time" "go.uber.org/multierr" "golang.org/x/oauth2" "github.com/bradleyfalzon/ghinstallation/v2" ) type Config struct { // HTTPS Github Repository URL Repository string // For Github App authentication PrivateKey []byte // PEM encoded private key. If empty, use oauth. AppID int64 InstallationID int64 // Optional. See documentation AccessToken string // optional personal access token } var ( errEmptyRepositoryError = fmt.Errorf("Repository must be provided") errInvalidRepositoryError = fmt.Errorf("Invalid repository URL") errEmptyKeyError = fmt.Errorf("PrivateKey or AccessToken must be set") errEmptyAppIDError = fmt.Errorf("AppID must be greater than zero") ) // Ensure the repository will work with the GithubOwner and GithubRepo methods var reValidRepository = regexp.MustCompile("^https://github.com/[^/]+/[^/]+([.]git)?$") var ( // used to remove everything from the Repository url, except the owner. reGithubOwner = regexp.MustCompile(`^https://github.com/|/[^/]*$`) // used to remove everything from the Repository url, except the repo name. reGithubRepo = regexp.MustCompile(`^.*/|[.]git$`) ) // Owner uses the Repository url to find the owner. func (c *Config) Owner() string { return reGithubOwner.ReplaceAllString(c.Repository, "") } // Repo uses the Repository url to find the repository name. func (c *Config) Repo() string { return reGithubRepo.ReplaceAllString(c.Repository, "") } // Validate returns an error if the configuration is missing required fields. func (c *Config) Validate() error { var errs []error if c.AccessToken != "" { // if the access token is set dont worry about the rest return nil } if c.PrivateKey == nil && c.AccessToken == "" { errs = append(errs, errEmptyKeyError) } if c.AppID <= 0 { errs = append(errs, errEmptyAppIDError) } if c.Repository == "" { errs = append(errs, errEmptyRepositoryError) } if !reValidRepository.MatchString(c.Repository) { errs = append(errs, errInvalidRepositoryError) } return multierr.Combine(errs...) } func (c *Config) HTTPClient() (*http.Client, error) { if err := c.Validate(); err != nil { return nil, err } if c.AccessToken != "" { return oauth2.NewClient(context.Background(), oauth2.StaticTokenSource( &oauth2.Token{AccessToken: c.AccessToken}, )), nil } transport := http.DefaultTransport const timeout = 5 * time.Minute if c.InstallationID == 0 { // Create an AppsService API compatible http client. tr, err := ghinstallation.NewAppsTransport(transport, c.AppID, c.PrivateKey) if err != nil { return nil, err } return &http.Client{ Transport: tr, Timeout: timeout, }, nil } tr, err := ghinstallation.New(transport, c.AppID, c.InstallationID, c.PrivateKey) if err != nil { return nil, err } return &http.Client{ Transport: tr, Timeout: timeout, }, nil }