cli/pkg/cmd/pr/merge/http.go
Kynan Ware 5de7a10080 Add godoc comments to exported symbols in pkg/cmd/pr
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-04 15:53:47 -07:00

170 lines
5.3 KiB
Go

package merge
import (
"net/http"
"strings"
"github.com/cli/cli/v2/api"
"github.com/cli/cli/v2/internal/ghrepo"
"github.com/shurcooL/githubv4"
)
// PullRequestMergeMethod represents the strategy used to merge a pull request.
type PullRequestMergeMethod int
const (
// PullRequestMergeMethodMerge creates a merge commit.
PullRequestMergeMethodMerge PullRequestMergeMethod = iota
// PullRequestMergeMethodRebase rebases the commits onto the base branch.
PullRequestMergeMethodRebase
// PullRequestMergeMethodSquash squashes all commits into a single commit.
PullRequestMergeMethodSquash
)
// Merge state status constants represent the GitHub GraphQL MergeStateStatus values.
const (
// MergeStateStatusBehind indicates the head branch is behind the base branch.
MergeStateStatusBehind = "BEHIND"
// MergeStateStatusBlocked indicates the merge is blocked by branch protection or other rules.
MergeStateStatusBlocked = "BLOCKED"
// MergeStateStatusClean indicates the branch is clean and ready to merge.
MergeStateStatusClean = "CLEAN"
// MergeStateStatusDirty indicates the branch has merge conflicts.
MergeStateStatusDirty = "DIRTY"
// MergeStateStatusHasHooks indicates the branch has pre-receive hooks that must pass.
MergeStateStatusHasHooks = "HAS_HOOKS"
// MergeStateStatusMerged indicates the pull request has already been merged.
MergeStateStatusMerged = "MERGED"
// MergeStateStatusUnstable indicates the branch has failing required status checks.
MergeStateStatusUnstable = "UNSTABLE"
)
type mergePayload struct {
repo ghrepo.Interface
pullRequestID string
method PullRequestMergeMethod
auto bool
commitSubject string
commitBody string
setCommitBody bool
expectedHeadOid string
authorEmail string
}
// TODO: drop after githubv4 gets updated
type EnablePullRequestAutoMergeInput struct {
githubv4.MergePullRequestInput
}
func mergePullRequest(client *http.Client, payload mergePayload) error {
input := githubv4.MergePullRequestInput{
PullRequestID: githubv4.ID(payload.pullRequestID),
}
switch payload.method {
case PullRequestMergeMethodMerge:
m := githubv4.PullRequestMergeMethodMerge
input.MergeMethod = &m
case PullRequestMergeMethodRebase:
m := githubv4.PullRequestMergeMethodRebase
input.MergeMethod = &m
case PullRequestMergeMethodSquash:
m := githubv4.PullRequestMergeMethodSquash
input.MergeMethod = &m
}
if payload.authorEmail != "" {
authorEmail := githubv4.String(payload.authorEmail)
input.AuthorEmail = &authorEmail
}
if payload.commitSubject != "" {
commitHeadline := githubv4.String(payload.commitSubject)
input.CommitHeadline = &commitHeadline
}
if payload.setCommitBody {
commitBody := githubv4.String(payload.commitBody)
input.CommitBody = &commitBody
}
if payload.expectedHeadOid != "" {
expectedHeadOid := githubv4.GitObjectID(payload.expectedHeadOid)
input.ExpectedHeadOid = &expectedHeadOid
}
variables := map[string]interface{}{
"input": input,
}
gql := api.NewClientFromHTTP(client)
if payload.auto {
var mutation struct {
EnablePullRequestAutoMerge struct {
ClientMutationId string
} `graphql:"enablePullRequestAutoMerge(input: $input)"`
}
variables["input"] = EnablePullRequestAutoMergeInput{input}
return gql.Mutate(payload.repo.RepoHost(), "PullRequestAutoMerge", &mutation, variables)
}
var mutation struct {
MergePullRequest struct {
ClientMutationId string
} `graphql:"mergePullRequest(input: $input)"`
}
return gql.Mutate(payload.repo.RepoHost(), "PullRequestMerge", &mutation, variables)
}
func disableAutoMerge(client *http.Client, repo ghrepo.Interface, prID string) error {
var mutation struct {
DisablePullRequestAutoMerge struct {
ClientMutationId string
} `graphql:"disablePullRequestAutoMerge(input: {pullRequestId: $prID})"`
}
variables := map[string]interface{}{
"prID": githubv4.ID(prID),
}
gql := api.NewClientFromHTTP(client)
return gql.Mutate(repo.RepoHost(), "PullRequestAutoMergeDisable", &mutation, variables)
}
func getMergeText(client *http.Client, repo ghrepo.Interface, prID string, mergeMethod PullRequestMergeMethod) (string, string, error) {
var method githubv4.PullRequestMergeMethod
switch mergeMethod {
case PullRequestMergeMethodMerge:
method = githubv4.PullRequestMergeMethodMerge
case PullRequestMergeMethodRebase:
method = githubv4.PullRequestMergeMethodRebase
case PullRequestMergeMethodSquash:
method = githubv4.PullRequestMergeMethodSquash
}
var query struct {
Node struct {
PullRequest struct {
ViewerMergeHeadlineText string `graphql:"viewerMergeHeadlineText(mergeType: $method)"`
ViewerMergeBodyText string `graphql:"viewerMergeBodyText(mergeType: $method)"`
} `graphql:"...on PullRequest"`
} `graphql:"node(id: $prID)"`
}
variables := map[string]interface{}{
"prID": githubv4.ID(prID),
"method": method,
}
gql := api.NewClientFromHTTP(client)
err := gql.Query(repo.RepoHost(), "PullRequestMergeText", &query, variables)
if err != nil {
// Tolerate this API missing in older GitHub Enterprise
if strings.Contains(err.Error(), "Field 'viewerMergeHeadlineText' doesn't exist") ||
strings.Contains(err.Error(), "Field 'viewerMergeBodyText' doesn't exist") {
return "", "", nil
}
return "", "", err
}
return query.Node.PullRequest.ViewerMergeHeadlineText, query.Node.PullRequest.ViewerMergeBodyText, nil
}