|
7 | 7 | "encoding/base64"
|
8 | 8 | "encoding/json"
|
9 | 9 | "fmt"
|
| 10 | +"net/http" |
10 | 11 | "os"
|
11 | 12 | "os/exec"
|
12 | 13 | "slices"
|
@@ -221,7 +222,6 @@ func TestGetMe(t *testing.T) {
|
221 | 222 | t.Parallel()
|
222 | 223 |
|
223 | 224 | mcpClient:=setupMCPClient(t)
|
224 |
| - |
225 | 225 | ctx:=context.Background()
|
226 | 226 |
|
227 | 227 | // When we call the "get_me" tool
|
@@ -806,14 +806,13 @@ func TestDirectoryDeletion(t *testing.T) {
|
806 | 806 | }
|
807 | 807 |
|
808 | 808 | funcTestRequestCopilotReview(t*testing.T) {
|
| 809 | +t.Parallel() |
| 810 | + |
809 | 811 | ifgetE2EHost()!=""&&getE2EHost()!="https://github.com" {
|
810 | 812 | t.Skip("Skipping test because the host does not support copilot reviews")
|
811 | 813 | }
|
812 | 814 |
|
813 |
| -t.Parallel() |
814 |
| - |
815 | 815 | mcpClient:=setupMCPClient(t)
|
816 |
| - |
817 | 816 | ctx:=context.Background()
|
818 | 817 |
|
819 | 818 | // First, who am I
|
@@ -954,6 +953,112 @@ func TestRequestCopilotReview(t *testing.T) {
|
954 | 953 | require.Equal(t,"Bot",*reviewRequests.Users[0].Type,"expected review request to be for Bot")
|
955 | 954 | }
|
956 | 955 |
|
| 956 | +funcTestAssignCopilotToIssue(t*testing.T) { |
| 957 | +t.Parallel() |
| 958 | + |
| 959 | +ifgetE2EHost()!=""&&getE2EHost()!="https://github.com" { |
| 960 | +t.Skip("Skipping test because the host does not support copilot being assigned to issues") |
| 961 | +} |
| 962 | + |
| 963 | +mcpClient:=setupMCPClient(t) |
| 964 | +ctx:=context.Background() |
| 965 | + |
| 966 | +// First, who am I |
| 967 | +getMeRequest:= mcp.CallToolRequest{} |
| 968 | +getMeRequest.Params.Name="get_me" |
| 969 | + |
| 970 | +t.Log("Getting current user...") |
| 971 | +resp,err:=mcpClient.CallTool(ctx,getMeRequest) |
| 972 | +require.NoError(t,err,"expected to call 'get_me' tool successfully") |
| 973 | +require.False(t,resp.IsError,fmt.Sprintf("expected result not to be an error: %+v",resp)) |
| 974 | + |
| 975 | +require.False(t,resp.IsError,"expected result not to be an error") |
| 976 | +require.Len(t,resp.Content,1,"expected content to have one item") |
| 977 | + |
| 978 | +textContent,ok:=resp.Content[0].(mcp.TextContent) |
| 979 | +require.True(t,ok,"expected content to be of type TextContent") |
| 980 | + |
| 981 | +vartrimmedGetMeTextstruct { |
| 982 | +Loginstring`json:"login"` |
| 983 | +} |
| 984 | +err=json.Unmarshal([]byte(textContent.Text),&trimmedGetMeText) |
| 985 | +require.NoError(t,err,"expected to unmarshal text content successfully") |
| 986 | + |
| 987 | +currentOwner:=trimmedGetMeText.Login |
| 988 | + |
| 989 | +// Then create a repository with a README (via autoInit) |
| 990 | +repoName:=fmt.Sprintf("github-mcp-server-e2e-%s-%d",t.Name(),time.Now().UnixMilli()) |
| 991 | +createRepoRequest:= mcp.CallToolRequest{} |
| 992 | +createRepoRequest.Params.Name="create_repository" |
| 993 | +createRepoRequest.Params.Arguments=map[string]any{ |
| 994 | +"name":repoName, |
| 995 | +"private":true, |
| 996 | +"autoInit":true, |
| 997 | +} |
| 998 | + |
| 999 | +t.Logf("Creating repository %s/%s...",currentOwner,repoName) |
| 1000 | +_,err=mcpClient.CallTool(ctx,createRepoRequest) |
| 1001 | +require.NoError(t,err,"expected to call 'create_repository' tool successfully") |
| 1002 | +require.False(t,resp.IsError,fmt.Sprintf("expected result not to be an error: %+v",resp)) |
| 1003 | + |
| 1004 | +// Cleanup the repository after the test |
| 1005 | +t.Cleanup(func() { |
| 1006 | +// MCP Server doesn't support deletions, but we can use the GitHub Client |
| 1007 | +ghClient:=getRESTClient(t) |
| 1008 | +t.Logf("Deleting repository %s/%s...",currentOwner,repoName) |
| 1009 | +_,err:=ghClient.Repositories.Delete(context.Background(),currentOwner,repoName) |
| 1010 | +require.NoError(t,err,"expected to delete repository successfully") |
| 1011 | +}) |
| 1012 | + |
| 1013 | +// Create an issue |
| 1014 | +createIssueRequest:= mcp.CallToolRequest{} |
| 1015 | +createIssueRequest.Params.Name="create_issue" |
| 1016 | +createIssueRequest.Params.Arguments=map[string]any{ |
| 1017 | +"owner":currentOwner, |
| 1018 | +"repo":repoName, |
| 1019 | +"title":"Test issue to assign copilot to", |
| 1020 | +} |
| 1021 | + |
| 1022 | +t.Logf("Creating issue in %s/%s...",currentOwner,repoName) |
| 1023 | +resp,err=mcpClient.CallTool(ctx,createIssueRequest) |
| 1024 | +require.NoError(t,err,"expected to call 'create_issue' tool successfully") |
| 1025 | +require.False(t,resp.IsError,fmt.Sprintf("expected result not to be an error: %+v",resp)) |
| 1026 | + |
| 1027 | +// Assign copilot to the issue |
| 1028 | +assignCopilotRequest:= mcp.CallToolRequest{} |
| 1029 | +assignCopilotRequest.Params.Name="assign_copilot_to_issue" |
| 1030 | +assignCopilotRequest.Params.Arguments=map[string]any{ |
| 1031 | +"owner":currentOwner, |
| 1032 | +"repo":repoName, |
| 1033 | +"issueNumber":1, |
| 1034 | +} |
| 1035 | + |
| 1036 | +t.Logf("Assigning copilot to issue in %s/%s...",currentOwner,repoName) |
| 1037 | +resp,err=mcpClient.CallTool(ctx,assignCopilotRequest) |
| 1038 | +require.NoError(t,err,"expected to call 'assign_copilot_to_issue' tool successfully") |
| 1039 | + |
| 1040 | +textContent,ok=resp.Content[0].(mcp.TextContent) |
| 1041 | +require.True(t,ok,"expected content to be of type TextContent") |
| 1042 | + |
| 1043 | +possibleExpectedFailure:="copilot isn't available as an assignee for this issue. Please inform the user to visit https://docs.github.com/en/copilot/using-github-copilot/using-copilot-coding-agent-to-work-on-tasks/about-assigning-tasks-to-copilot for more information." |
| 1044 | +ifresp.IsError&&textContent.Text==possibleExpectedFailure { |
| 1045 | +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") |
| 1046 | +} |
| 1047 | + |
| 1048 | +require.False(t,resp.IsError,fmt.Sprintf("expected result not to be an error: %+v",resp)) |
| 1049 | + |
| 1050 | +require.Equal(t,"successfully assigned copilot to issue",textContent.Text) |
| 1051 | + |
| 1052 | +// Check that copilot is assigned to the issue |
| 1053 | +// MCP Server doesn't support getting assignees yet |
| 1054 | +ghClient:=getRESTClient(t) |
| 1055 | +assignees,response,err:=ghClient.Issues.Get(context.Background(),currentOwner,repoName,1) |
| 1056 | +require.NoError(t,err,"expected to get issue successfully") |
| 1057 | +require.Equal(t,http.StatusOK,response.StatusCode,"expected to get issue successfully") |
| 1058 | +require.Len(t,assignees.Assignees,1,"expected to find one assignee") |
| 1059 | +require.Equal(t,"Copilot",*assignees.Assignees[0].Login,"expected copilot to be assigned to the issue") |
| 1060 | +} |
| 1061 | + |
957 | 1062 | funcTestPullRequestAtomicCreateAndSubmit(t*testing.T) {
|
958 | 1063 | t.Parallel()
|
959 | 1064 |
|
@@ -1156,7 +1261,7 @@ func TestPullRequestReviewCommentSubmit(t *testing.T) {
|
1156 | 1261 |
|
1157 | 1262 | t.Logf("Creating repository %s/%s...",currentOwner,repoName)
|
1158 | 1263 | _,err=mcpClient.CallTool(ctx,createRepoRequest)
|
1159 |
| -require.NoError(t,err,"expected to call 'get_me' tool successfully") |
| 1264 | +require.NoError(t,err,"expected to call 'create_repository' tool successfully") |
1160 | 1265 | require.False(t,resp.IsError,fmt.Sprintf("expected result not to be an error: %+v",resp))
|
1161 | 1266 |
|
1162 | 1267 | // Cleanup the repository after the test
|
|