diff --git a/internal/github/pr.go b/internal/github/pr.go new file mode 100644 index 0000000..3a40789 --- /dev/null +++ b/internal/github/pr.go @@ -0,0 +1,63 @@ +package github + +import ( + "context" + "regexp" + + "github.com/google/go-github/v47/github" + "github.com/pkg/errors" + "golang.org/x/oauth2" + + "github.com/akuityio/bookkeeper/internal/git" +) + +func OpenPR( + ctx context.Context, + repoURL string, + title string, + body string, + targetBranch string, + commitBranch string, + repoCreds git.RepoCredentials, +) (string, error) { + owner, repo, err := parseGitHubURL(repoURL) + if err != nil { + return "", err + } + githubClient := github.NewClient( + oauth2.NewClient( + ctx, + oauth2.StaticTokenSource( + &oauth2.Token{AccessToken: repoCreds.Password}, + ), + ), + ) + pr, _, err := githubClient.PullRequests.Create( + ctx, + owner, + repo, + &github.NewPullRequest{ + Title: github.String(title), + Base: github.String(targetBranch), + Head: github.String(commitBranch), + Body: github.String(body), + MaintainerCanModify: github.Bool(false), + }, + ) + // We don't unconditionally return *pr.HTMLURL and err because if err != nil, + // pr might be == nil + if err != nil { + return "", + errors.Wrap(err, "error opening pull request to the target branch") + } + return *pr.HTMLURL, nil +} + +func parseGitHubURL(url string) (string, string, error) { + regex := regexp.MustCompile(`^https\://github\.com/([\w-]+)/([\w-]+).*`) + parts := regex.FindStringSubmatch(url) + if len(parts) != 3 { + return "", "", errors.Errorf("error parsing github repository URL %q", url) + } + return parts[1], parts[2], nil +} diff --git a/service.go b/service.go index 68d331d..f29bd7c 100644 --- a/service.go +++ b/service.go @@ -6,18 +6,16 @@ import ( "fmt" "os" "path/filepath" - "regexp" "strings" "github.com/ghodss/yaml" - "github.com/google/go-github/v47/github" "github.com/pkg/errors" uuid "github.com/satori/go.uuid" log "github.com/sirupsen/logrus" - "golang.org/x/oauth2" "github.com/akuityio/bookkeeper/internal/config" "github.com/akuityio/bookkeeper/internal/git" + "github.com/akuityio/bookkeeper/internal/github" "github.com/akuityio/bookkeeper/internal/metadata" ) @@ -205,23 +203,7 @@ func (s *service) RenderConfig( Debug("pushed fully-rendered configuration") // Open a PR if requested - // - // TODO: Support git providers other than GitHub - // - // TODO: Move this into its own github package - if commitBranch != req.TargetBranch { - var owner, repo string - if owner, repo, err = parseGitHubURL(req.RepoURL); err != nil { - return res, err - } - githubClient := github.NewClient( - oauth2.NewClient( - ctx, - oauth2.StaticTokenSource( - &oauth2.Token{AccessToken: req.RepoCreds.Password}, - ), - ), - ) + if branchConfig.OpenPR { commitMsgParts := strings.SplitN(commitMsg, "\n", 2) // PR title is just the first line of the commit message prTitle := fmt.Sprintf("%s --> %s", commitMsgParts[0], req.TargetBranch) @@ -230,25 +212,24 @@ func (s *service) RenderConfig( if len(commitMsgParts) == 2 { prBody = strings.TrimSpace(commitMsgParts[1]) } - var pr *github.PullRequest - if pr, _, err = githubClient.PullRequests.Create( + // TODO: Support git providers other than GitHub + if res.PullRequestURL, err = github.OpenPR( ctx, - owner, - repo, - &github.NewPullRequest{ - Title: github.String(prTitle), - Base: github.String(req.TargetBranch), - Head: github.String(commitBranch), - Body: github.String(prBody), - MaintainerCanModify: github.Bool(false), + req.RepoURL, + prTitle, + prBody, + req.TargetBranch, + commitBranch, + git.RepoCredentials{ + Username: req.RepoCreds.Username, + Password: req.RepoCreds.Password, }, ); err != nil { return res, errors.Wrap(err, "error opening pull request to the target branch") } - logger.WithField("prURL", *pr.HTMLURL).Debug("opened PR") + logger.WithField("prURL", res.PullRequestURL).Debug("opened PR") res.ActionTaken = ActionTakenOpenedPR - res.PullRequestURL = *pr.HTMLURL } else { res.ActionTaken = ActionTakenPushedDirectly res.CommitID = commitID @@ -325,15 +306,6 @@ func (s *service) switchToCommitBranch( return commitBranch, nil } -func parseGitHubURL(url string) (string, string, error) { - regex := regexp.MustCompile(`^https\://github\.com/([\w-]+)/([\w-]+).*`) - parts := regex.FindStringSubmatch(url) - if len(parts) != 3 { - return "", "", errors.Errorf("error parsing github repository URL %q", url) - } - return parts[1], parts[2], nil -} - // checkoutSourceCommit examines a RenderRequest and determines if it is // requesting to render configuration from a specific commit. If not, it returns // the ID of the most recent commit.