|
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 | func TestRequestCopilotReview(t *testing.T) {
|
| 809 | + t.Parallel() |
| 810 | + |
809 | 811 | if getE2EHost() != "" && 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 | +func TestAssignCopilotToIssue(t *testing.T) { |
| 957 | + t.Parallel() |
| 958 | + |
| 959 | + if getE2EHost() != "" && 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 | + var trimmedGetMeText struct { |
| 982 | + Login string `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 | + if resp.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 | func TestPullRequestAtomicCreateAndSubmit(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
|
|
0 commit comments