Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb4da208

Browse files
committed
Support assigning copilot to issues
1 parent4ccedee commitb4da208

File tree

6 files changed

+713
-9
lines changed

6 files changed

+713
-9
lines changed

‎e2e/e2e_test.go

Lines changed: 110 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"encoding/base64"
88
"encoding/json"
99
"fmt"
10+
"net/http"
1011
"os"
1112
"os/exec"
1213
"slices"
@@ -210,7 +211,6 @@ func TestGetMe(t *testing.T) {
210211
t.Parallel()
211212

212213
mcpClient:=setupMCPClient(t)
213-
214214
ctx:=context.Background()
215215

216216
// When we call the "get_me" tool
@@ -795,14 +795,13 @@ func TestDirectoryDeletion(t *testing.T) {
795795
}
796796

797797
funcTestRequestCopilotReview(t*testing.T) {
798+
t.Parallel()
799+
798800
ifgetE2EHost()!=""&&getE2EHost()!="https://github.com" {
799801
t.Skip("Skipping test because the host does not support copilot reviews")
800802
}
801803

802-
t.Parallel()
803-
804804
mcpClient:=setupMCPClient(t)
805-
806805
ctx:=context.Background()
807806

808807
// First, who am I
@@ -943,6 +942,112 @@ func TestRequestCopilotReview(t *testing.T) {
943942
require.Equal(t,"Bot",*reviewRequests.Users[0].Type,"expected review request to be for Bot")
944943
}
945944

945+
funcTestAssignCopilotToIssue(t*testing.T) {
946+
t.Parallel()
947+
948+
ifgetE2EHost()!=""&&getE2EHost()!="https://github.com" {
949+
t.Skip("Skipping test because the host does not support copilot being assigned to issues")
950+
}
951+
952+
mcpClient:=setupMCPClient(t)
953+
ctx:=context.Background()
954+
955+
// First, who am I
956+
getMeRequest:= mcp.CallToolRequest{}
957+
getMeRequest.Params.Name="get_me"
958+
959+
t.Log("Getting current user...")
960+
resp,err:=mcpClient.CallTool(ctx,getMeRequest)
961+
require.NoError(t,err,"expected to call 'get_me' tool successfully")
962+
require.False(t,resp.IsError,fmt.Sprintf("expected result not to be an error: %+v",resp))
963+
964+
require.False(t,resp.IsError,"expected result not to be an error")
965+
require.Len(t,resp.Content,1,"expected content to have one item")
966+
967+
textContent,ok:=resp.Content[0].(mcp.TextContent)
968+
require.True(t,ok,"expected content to be of type TextContent")
969+
970+
vartrimmedGetMeTextstruct {
971+
Loginstring`json:"login"`
972+
}
973+
err=json.Unmarshal([]byte(textContent.Text),&trimmedGetMeText)
974+
require.NoError(t,err,"expected to unmarshal text content successfully")
975+
976+
currentOwner:=trimmedGetMeText.Login
977+
978+
// Then create a repository with a README (via autoInit)
979+
repoName:=fmt.Sprintf("github-mcp-server-e2e-%s-%d",t.Name(),time.Now().UnixMilli())
980+
createRepoRequest:= mcp.CallToolRequest{}
981+
createRepoRequest.Params.Name="create_repository"
982+
createRepoRequest.Params.Arguments=map[string]any{
983+
"name":repoName,
984+
"private":true,
985+
"autoInit":true,
986+
}
987+
988+
t.Logf("Creating repository %s/%s...",currentOwner,repoName)
989+
_,err=mcpClient.CallTool(ctx,createRepoRequest)
990+
require.NoError(t,err,"expected to call 'get_me' tool successfully")
991+
require.False(t,resp.IsError,fmt.Sprintf("expected result not to be an error: %+v",resp))
992+
993+
// Cleanup the repository after the test
994+
t.Cleanup(func() {
995+
// MCP Server doesn't support deletions, but we can use the GitHub Client
996+
ghClient:=getRESTClient(t)
997+
t.Logf("Deleting repository %s/%s...",currentOwner,repoName)
998+
_,err:=ghClient.Repositories.Delete(context.Background(),currentOwner,repoName)
999+
require.NoError(t,err,"expected to delete repository successfully")
1000+
})
1001+
1002+
// Create an issue
1003+
createIssueRequest:= mcp.CallToolRequest{}
1004+
createIssueRequest.Params.Name="create_issue"
1005+
createIssueRequest.Params.Arguments=map[string]any{
1006+
"owner":currentOwner,
1007+
"repo":repoName,
1008+
"title":"Test issue to assign copilot to",
1009+
}
1010+
1011+
t.Logf("Creating issue in %s/%s...",currentOwner,repoName)
1012+
resp,err=mcpClient.CallTool(ctx,createIssueRequest)
1013+
require.NoError(t,err,"expected to call 'create_issue' tool successfully")
1014+
require.False(t,resp.IsError,fmt.Sprintf("expected result not to be an error: %+v",resp))
1015+
1016+
// Assign copilot to the issue
1017+
assignCopilotRequest:= mcp.CallToolRequest{}
1018+
assignCopilotRequest.Params.Name="assign_copilot_to_issue"
1019+
assignCopilotRequest.Params.Arguments=map[string]any{
1020+
"owner":currentOwner,
1021+
"repo":repoName,
1022+
"issueNumber":1,
1023+
}
1024+
1025+
t.Logf("Assigning copilot to issue in %s/%s...",currentOwner,repoName)
1026+
resp,err=mcpClient.CallTool(ctx,assignCopilotRequest)
1027+
require.NoError(t,err,"expected to call 'assign_copilot_to_issue' tool successfully")
1028+
1029+
textContent,ok=resp.Content[0].(mcp.TextContent)
1030+
require.True(t,ok,"expected content to be of type TextContent")
1031+
1032+
possibleExpectedFailure:="copilot isn't available as an assignee for this issue, perhaps you need to enable it in your settings?"
1033+
ifresp.IsError&&textContent.Text==possibleExpectedFailure {
1034+
t.Skip("skipping because copilot wasn't available as an assignee on this issue, it's likely that the owner doesn't have copilot enabled in their settings")
1035+
}
1036+
1037+
require.False(t,resp.IsError,fmt.Sprintf("expected result not to be an error: %+v",resp))
1038+
1039+
require.Equal(t,"successfully assigned copilot to issue",textContent.Text)
1040+
1041+
// Check that copilot is assigned to the issue
1042+
// MCP Server doesn't support getting assignees yet
1043+
ghClient:=getRESTClient(t)
1044+
assignees,response,err:=ghClient.Issues.Get(context.Background(),currentOwner,repoName,1)
1045+
require.NoError(t,err,"expected to get issue successfully")
1046+
require.Equal(t,http.StatusOK,response.StatusCode,"expected to get issue successfully")
1047+
require.Len(t,assignees.Assignees,1,"expected to find one assignee")
1048+
require.Equal(t,"Copilot",*assignees.Assignees[0].Login,"expected copilot to be assigned to the issue")
1049+
}
1050+
9461051
funcTestPullRequestAtomicCreateAndSubmit(t*testing.T) {
9471052
t.Parallel()
9481053

@@ -1145,7 +1250,7 @@ func TestPullRequestReviewCommentSubmit(t *testing.T) {
11451250

11461251
t.Logf("Creating repository %s/%s...",currentOwner,repoName)
11471252
_,err=mcpClient.CallTool(ctx,createRepoRequest)
1148-
require.NoError(t,err,"expected to call 'get_me' tool successfully")
1253+
require.NoError(t,err,"expected to call 'create_repository' tool successfully")
11491254
require.False(t,resp.IsError,fmt.Sprintf("expected result not to be an error: %+v",resp))
11501255

11511256
// Cleanup the repository after the test

‎internal/githubv4mock/objects_are_equal_values.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// The contents of this file are taken from https://github.com/stretchr/testify/blob/016e2e9c269209287f33ec203f340a9a723fe22c/assert/assertions.go#L166
22
// because I do not want to take a dependency on the entire testify module just to use this equality check.
33
//
4+
// There is a modification in objectsAreEqual to check that typed nils are equal, even if their types are different.
5+
//
46
// The original license, copied from https://github.com/stretchr/testify/blob/016e2e9c269209287f33ec203f340a9a723fe22c/LICENSE
57
//
68
// MIT License
@@ -69,8 +71,10 @@ func objectsAreEqualValues(expected, actual any) bool {
6971
//
7072
// This function does no assertion of any kind.
7173
funcobjectsAreEqual(expected,actualany)bool {
72-
ifexpected==nil||actual==nil {
73-
returnexpected==actual
74+
// There is a modification in objectsAreEqual to check that typed nils are equal, even if their types are different.
75+
// This is required because when a nil is provided as a variable, the type is not known.
76+
ifisNil(expected)&&isNil(actual) {
77+
returntrue
7478
}
7579

7680
exp,ok:=expected.([]byte)
@@ -94,3 +98,16 @@ func objectsAreEqual(expected, actual any) bool {
9498
funcisNumericType(t reflect.Type)bool {
9599
returnt.Kind()>=reflect.Int&&t.Kind()<=reflect.Complex128
96100
}
101+
102+
funcisNil(iany)bool {
103+
ifi==nil {
104+
returntrue
105+
}
106+
v:=reflect.ValueOf(i)
107+
switchv.Kind() {
108+
casereflect.Chan,reflect.Func,reflect.Interface,reflect.Map,reflect.Pointer,reflect.Slice:
109+
returnv.IsNil()
110+
default:
111+
returnfalse
112+
}
113+
}

‎internal/githubv4mock/objects_are_equal_values_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// The contents of this file are taken from https://github.com/stretchr/testify/blob/016e2e9c269209287f33ec203f340a9a723fe22c/assert/assertions_test.go#L140-L174
22
//
3+
// There is a modification to test objectsAreEqualValues to check that typed nils are equal, even if their types are different.
4+
35
// The original license, copied from https://github.com/stretchr/testify/blob/016e2e9c269209287f33ec203f340a9a723fe22c/LICENSE
46
//
57
// MIT License
@@ -55,6 +57,8 @@ func TestObjectsAreEqualValues(t *testing.T) {
5557
{3.14,complex128(1e+100+1e+100i),false},
5658
{complex128(1e+10+1e+10i),complex64(1e+10+1e+10i),true},
5759
{complex64(1e+10+1e+10i),complex128(1e+10+1e+10i),true},
60+
{(*string)(nil),nil,true},// typed nil vs untyped nil
61+
{(*string)(nil), (*int)(nil),true},// different typed nils
5862
}
5963

6064
for_,c:=rangecases {

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp