|
7 | 7 | "encoding/base64"
|
8 | 8 | "encoding/json"
|
9 | 9 | "fmt"
|
| 10 | + "net/http" |
10 | 11 | "os"
|
11 | 12 | "os/exec"
|
12 | 13 | "slices"
|
@@ -210,7 +211,6 @@ func TestGetMe(t *testing.T) {
|
210 | 211 | t.Parallel()
|
211 | 212 |
|
212 | 213 | mcpClient := setupMCPClient(t)
|
213 |
| - |
214 | 214 | ctx := context.Background()
|
215 | 215 |
|
216 | 216 | // When we call the "get_me" tool
|
@@ -795,14 +795,13 @@ func TestDirectoryDeletion(t *testing.T) {
|
795 | 795 | }
|
796 | 796 |
|
797 | 797 | func TestRequestCopilotReview(t *testing.T) {
|
| 798 | + t.Parallel() |
| 799 | + |
798 | 800 | if getE2EHost() != "" && getE2EHost() != "https://github.com" {
|
799 | 801 | t.Skip("Skipping test because the host does not support copilot reviews")
|
800 | 802 | }
|
801 | 803 |
|
802 |
| - t.Parallel() |
803 |
| - |
804 | 804 | mcpClient := setupMCPClient(t)
|
805 |
| - |
806 | 805 | ctx := context.Background()
|
807 | 806 |
|
808 | 807 | // First, who am I
|
@@ -943,6 +942,112 @@ func TestRequestCopilotReview(t *testing.T) {
|
943 | 942 | require.Equal(t, "Bot", *reviewRequests.Users[0].Type, "expected review request to be for Bot")
|
944 | 943 | }
|
945 | 944 |
|
| 945 | +func TestAssignCopilotToIssue(t *testing.T) { |
| 946 | + t.Parallel() |
| 947 | + |
| 948 | + if getE2EHost() != "" && 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 | + var trimmedGetMeText struct { |
| 971 | + Login string `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 'create_repository' 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. 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." |
| 1033 | + if resp.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 | + |
946 | 1051 | func TestPullRequestAtomicCreateAndSubmit(t *testing.T) {
|
947 | 1052 | t.Parallel()
|
948 | 1053 |
|
@@ -1145,7 +1250,7 @@ func TestPullRequestReviewCommentSubmit(t *testing.T) {
|
1145 | 1250 |
|
1146 | 1251 | t.Logf("Creating repository %s/%s...", currentOwner, repoName)
|
1147 | 1252 | _, 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") |
1149 | 1254 | require.False(t, resp.IsError, fmt.Sprintf("expected result not to be an error: %+v", resp))
|
1150 | 1255 |
|
1151 | 1256 | // Cleanup the repository after the test
|
|
0 commit comments