Add auto-merge setting and merge now functionality
This commit is contained in:
163
github.go
163
github.go
@@ -30,6 +30,11 @@ type GitHubPullRequestWriteService interface {
|
||||
UpdatePullRequest(context.Context, string, PullRequestMetadata) (PullRequestMetadata, error)
|
||||
}
|
||||
|
||||
type GitHubMergeService interface {
|
||||
SetPullRequestAutoMerge(context.Context, string, string, string, bool) (*AutoMergeRequest, error)
|
||||
MergePullRequest(context.Context, string, string, string) (PullRequestMergeResult, error)
|
||||
}
|
||||
|
||||
type GitHubBranchService interface {
|
||||
ListBranches(context.Context, string, string) ([]RepositoryBranch, error)
|
||||
}
|
||||
@@ -429,7 +434,7 @@ func nullableCursor(cursor string) any {
|
||||
const detailsQuery = `
|
||||
query PullRequestDetails($owner: String!, $name: String!, $number: Int!) {
|
||||
repository(owner: $owner, name: $name) {
|
||||
url
|
||||
url mergeCommitAllowed squashMergeAllowed rebaseMergeAllowed
|
||||
viewerPermission
|
||||
defaultBranchRef { name }
|
||||
rulesets(first: 100, includeParents: true, targets: [BRANCH]) {
|
||||
@@ -440,11 +445,13 @@ query PullRequestDetails($owner: String!, $name: String!, $number: Int!) {
|
||||
}
|
||||
}
|
||||
pullRequest(number: $number) {
|
||||
id number title url body isDraft createdAt updatedAt
|
||||
id number title url body isDraft createdAt updatedAt state merged mergedAt
|
||||
mergeable mergeStateStatus reviewDecision
|
||||
autoMergeRequest { mergeMethod enabledAt enabledBy { login } }
|
||||
mergeQueueEntry { state position enqueuedAt estimatedTimeToMerge }
|
||||
baseRefName headRefName headRefOid
|
||||
viewerCanUpdate viewerCanReact viewerCanSubscribe viewerCanEnableAutoMerge
|
||||
viewerCanUpdate viewerCanReact viewerCanSubscribe
|
||||
viewerCanEnableAutoMerge viewerCanDisableAutoMerge
|
||||
baseRef {
|
||||
target { ... on Commit { oid } }
|
||||
branchProtectionRule {
|
||||
@@ -631,6 +638,29 @@ mutation UpdatePullRequest($input: UpdatePullRequestInput!) {
|
||||
}
|
||||
}`
|
||||
|
||||
const enableAutoMergeMutation = `
|
||||
mutation EnablePullRequestAutoMerge($input: EnablePullRequestAutoMergeInput!) {
|
||||
enablePullRequestAutoMerge(input: $input) {
|
||||
pullRequest {
|
||||
autoMergeRequest { mergeMethod enabledAt enabledBy { login } }
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
const disableAutoMergeMutation = `
|
||||
mutation DisablePullRequestAutoMerge($input: DisablePullRequestAutoMergeInput!) {
|
||||
disablePullRequestAutoMerge(input: $input) {
|
||||
pullRequest { id autoMergeRequest { mergeMethod } }
|
||||
}
|
||||
}`
|
||||
|
||||
const mergePullRequestMutation = `
|
||||
mutation MergePullRequest($input: MergePullRequestInput!) {
|
||||
mergePullRequest(input: $input) {
|
||||
pullRequest { merged mergedAt }
|
||||
}
|
||||
}`
|
||||
|
||||
type githubActor struct {
|
||||
Login string `json:"login"`
|
||||
Name string `json:"name"`
|
||||
@@ -759,14 +789,20 @@ type githubRuleset struct {
|
||||
}
|
||||
|
||||
type githubPullRequestDetails struct {
|
||||
ID, Title, URL, Body, Mergeable, MergeStateStatus string
|
||||
ReviewDecision, BaseRefName, HeadRefName, HeadRefOID string
|
||||
Number, Additions, Deletions, ChangedFiles int
|
||||
IsDraft bool
|
||||
CreatedAt, UpdatedAt time.Time
|
||||
Author *githubActor
|
||||
ViewerCanUpdate, ViewerCanReact, ViewerCanSubscribe, ViewerCanEnableAutoMerge bool
|
||||
BaseRef *struct {
|
||||
ID, Title, URL, Body, State, Mergeable, MergeStateStatus string
|
||||
ReviewDecision, BaseRefName, HeadRefName, HeadRefOID string
|
||||
Number, Additions, Deletions, ChangedFiles int
|
||||
IsDraft, Merged bool
|
||||
CreatedAt, UpdatedAt, MergedAt time.Time
|
||||
Author *githubActor
|
||||
ViewerCanUpdate, ViewerCanReact, ViewerCanSubscribe bool
|
||||
ViewerCanEnableAutoMerge, ViewerCanDisableAutoMerge bool
|
||||
AutoMergeRequest *struct {
|
||||
MergeMethod string
|
||||
EnabledAt time.Time
|
||||
EnabledBy *githubActor
|
||||
}
|
||||
BaseRef *struct {
|
||||
Target *struct{ OID string }
|
||||
BranchProtectionRule *struct {
|
||||
RequiresApprovingReviews, RequiresStatusChecks bool
|
||||
@@ -1057,11 +1093,12 @@ func (c *GitHubClient) allCheckAnnotations(
|
||||
func (c *GitHubClient) GetPullRequest(ctx context.Context, owner, name string, number int) (PRDetails, error) {
|
||||
var data struct {
|
||||
Repository *struct {
|
||||
URL string
|
||||
ViewerPermission string `json:"viewerPermission"`
|
||||
DefaultBranchRef *struct{ Name string }
|
||||
Rulesets struct{ Nodes []githubRuleset }
|
||||
PullRequest *githubPullRequestDetails `json:"pullRequest"`
|
||||
URL string
|
||||
ViewerPermission string `json:"viewerPermission"`
|
||||
MergeCommitAllowed, SquashMergeAllowed, RebaseMergeAllowed bool
|
||||
DefaultBranchRef *struct{ Name string }
|
||||
Rulesets struct{ Nodes []githubRuleset }
|
||||
PullRequest *githubPullRequestDetails `json:"pullRequest"`
|
||||
} `json:"repository"`
|
||||
}
|
||||
if err := c.query(ctx, detailsQuery, map[string]any{"owner": owner, "name": name, "number": number}, &data); err != nil {
|
||||
@@ -1138,6 +1175,7 @@ func (c *GitHubClient) GetPullRequest(ctx context.Context, owner, name string, n
|
||||
},
|
||||
Body: node.Body, CreatedAt: node.CreatedAt, BaseRef: node.BaseRefName, HeadRef: node.HeadRefName,
|
||||
HeadOID: node.HeadRefOID, Mergeable: node.Mergeable, MergeState: node.MergeStateStatus,
|
||||
State: node.State, Merged: node.Merged, MergedAt: node.MergedAt,
|
||||
RepositoryURL: data.Repository.URL,
|
||||
Additions: node.Additions, Deletions: node.Deletions, ChangedFiles: node.ChangedFiles,
|
||||
CommitCount: node.Commits.TotalCount, CommentCount: node.Comments.TotalCount,
|
||||
@@ -1146,8 +1184,25 @@ func (c *GitHubClient) GetPullRequest(ctx context.Context, owner, name string, n
|
||||
Repository: data.Repository.ViewerPermission,
|
||||
CanUpdatePR: node.ViewerCanUpdate, CanReact: node.ViewerCanReact,
|
||||
CanSubscribe: node.ViewerCanSubscribe, CanEnableMerge: node.ViewerCanEnableAutoMerge,
|
||||
CanDisableMerge: node.ViewerCanDisableAutoMerge,
|
||||
},
|
||||
}
|
||||
if data.Repository.SquashMergeAllowed {
|
||||
details.AllowedMergeMethods = append(details.AllowedMergeMethods, "SQUASH")
|
||||
}
|
||||
if data.Repository.MergeCommitAllowed {
|
||||
details.AllowedMergeMethods = append(details.AllowedMergeMethods, "MERGE")
|
||||
}
|
||||
if data.Repository.RebaseMergeAllowed {
|
||||
details.AllowedMergeMethods = append(details.AllowedMergeMethods, "REBASE")
|
||||
}
|
||||
if node.AutoMergeRequest != nil {
|
||||
details.AutoMerge = &AutoMergeRequest{
|
||||
MergeMethod: node.AutoMergeRequest.MergeMethod,
|
||||
EnabledAt: node.AutoMergeRequest.EnabledAt,
|
||||
EnabledBy: actorLogin(node.AutoMergeRequest.EnabledBy),
|
||||
}
|
||||
}
|
||||
if node.BaseRef != nil && node.BaseRef.Target != nil {
|
||||
details.BaseOID = node.BaseRef.Target.OID
|
||||
}
|
||||
@@ -1460,6 +1515,82 @@ func (c *GitHubClient) UpdatePullRequest(
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *GitHubClient) SetPullRequestAutoMerge(
|
||||
ctx context.Context, pullRequestID, expectedHeadOID, mergeMethod string, enabled bool,
|
||||
) (*AutoMergeRequest, error) {
|
||||
if !enabled {
|
||||
var data struct {
|
||||
DisablePullRequestAutoMerge *struct{ PullRequest *struct{ ID string } }
|
||||
}
|
||||
if err := c.query(ctx, disableAutoMergeMutation, map[string]any{
|
||||
"input": map[string]any{"pullRequestId": pullRequestID},
|
||||
}, &data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if data.DisablePullRequestAutoMerge == nil ||
|
||||
data.DisablePullRequestAutoMerge.PullRequest == nil {
|
||||
return nil, errors.New("GitHub returned no pull request after disabling auto-merge")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
var data struct {
|
||||
EnablePullRequestAutoMerge *struct {
|
||||
PullRequest *struct {
|
||||
AutoMergeRequest *struct {
|
||||
MergeMethod string
|
||||
EnabledAt time.Time
|
||||
EnabledBy *githubActor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
input := map[string]any{
|
||||
"pullRequestId": pullRequestID, "expectedHeadOid": expectedHeadOID,
|
||||
"mergeMethod": mergeMethod,
|
||||
}
|
||||
if err := c.query(ctx, enableAutoMergeMutation, map[string]any{"input": input}, &data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if data.EnablePullRequestAutoMerge == nil ||
|
||||
data.EnablePullRequestAutoMerge.PullRequest == nil ||
|
||||
data.EnablePullRequestAutoMerge.PullRequest.AutoMergeRequest == nil {
|
||||
return nil, errors.New("GitHub returned no auto-merge request")
|
||||
}
|
||||
node := data.EnablePullRequestAutoMerge.PullRequest.AutoMergeRequest
|
||||
return &AutoMergeRequest{
|
||||
MergeMethod: node.MergeMethod, EnabledAt: node.EnabledAt,
|
||||
EnabledBy: actorLogin(node.EnabledBy),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *GitHubClient) MergePullRequest(
|
||||
ctx context.Context, pullRequestID, expectedHeadOID, mergeMethod string,
|
||||
) (PullRequestMergeResult, error) {
|
||||
var data struct {
|
||||
MergePullRequest *struct {
|
||||
PullRequest *struct {
|
||||
Merged bool
|
||||
MergedAt time.Time
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := c.query(ctx, mergePullRequestMutation, map[string]any{
|
||||
"input": map[string]any{
|
||||
"pullRequestId": pullRequestID, "expectedHeadOid": expectedHeadOID,
|
||||
"mergeMethod": mergeMethod,
|
||||
},
|
||||
}, &data); err != nil {
|
||||
return PullRequestMergeResult{}, err
|
||||
}
|
||||
if data.MergePullRequest == nil || data.MergePullRequest.PullRequest == nil ||
|
||||
!data.MergePullRequest.PullRequest.Merged {
|
||||
return PullRequestMergeResult{}, errors.New("GitHub did not merge the pull request")
|
||||
}
|
||||
return PullRequestMergeResult{
|
||||
Merged: true, MergedAt: data.MergePullRequest.PullRequest.MergedAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func convertReviewThread(thread githubReviewThread) ReviewThread {
|
||||
item := ReviewThread{
|
||||
ID: thread.ID, Path: thread.Path, DiffSide: thread.DiffSide,
|
||||
|
||||
Reference in New Issue
Block a user