From 35cc9bacb3581995b0a0b370f0c9b64749d513c0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 09:08:39 +0000 Subject: [PATCH 01/13] Initial plan From 637de7a7cae0e3f5db986180361a87ba55140cea Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 09:16:07 +0000 Subject: [PATCH 02/13] Add endpoint constants and migrate raw package tests Co-authored-by: JoannaaKL <67866556+JoannaaKL@users.noreply.github.com> --- pkg/github/helper_test.go | 130 +++++++++++++++++++++++++++++++++++++- pkg/raw/raw_mock.go | 20 ------ pkg/raw/raw_test.go | 97 ++++++++++++++++++---------- 3 files changed, 192 insertions(+), 55 deletions(-) delete mode 100644 pkg/raw/raw_mock.go diff --git a/pkg/github/helper_test.go b/pkg/github/helper_test.go index 3eea4fba7..b62a67708 100644 --- a/pkg/github/helper_test.go +++ b/pkg/github/helper_test.go @@ -18,15 +18,120 @@ import ( // GitHub API endpoint patterns for testing // These constants define the URL patterns used in HTTP mocking for tests const ( + // User endpoints + GetUser = "GET /user" + GetUserStarred = "GET /user/starred" + GetUsersGistsByUsername = "GET /users/{username}/gists" + GetUsersStarredByUsername = "GET /users/{username}/starred" + PutUserStarredByOwnerByRepo = "PUT /user/starred/{owner}/{repo}" + DeleteUserStarredByOwnerByRepo = "DELETE /user/starred/{owner}/{repo}" + // Repository endpoints - GetReposByOwnerByRepo = "GET /repos/{owner}/{repo}" + GetReposByOwnerByRepo = "GET /repos/{owner}/{repo}" + GetReposBranchesByOwnerByRepo = "GET /repos/{owner}/{repo}/branches" + GetReposTagsByOwnerByRepo = "GET /repos/{owner}/{repo}/tags" + GetReposCommitsByOwnerByRepo = "GET /repos/{owner}/{repo}/commits" + GetReposCommitsByOwnerByRepoByRef = "GET /repos/{owner}/{repo}/commits/{ref}" + GetReposContentsByOwnerByRepoByPath = "GET /repos/{owner}/{repo}/contents/{path}" + PutReposContentsByOwnerByRepoByPath = "PUT /repos/{owner}/{repo}/contents/{path}" + PostReposForksByOwnerByRepo = "POST /repos/{owner}/{repo}/forks" + GetReposSubscriptionByOwnerByRepo = "GET /repos/{owner}/{repo}/subscription" + PutReposSubscriptionByOwnerByRepo = "PUT /repos/{owner}/{repo}/subscription" + DeleteReposSubscriptionByOwnerByRepo = "DELETE /repos/{owner}/{repo}/subscription" // Git endpoints - GetReposGitTreesByOwnerByRepoByTree = "GET /repos/{owner}/{repo}/git/trees/{tree}" + GetReposGitTreesByOwnerByRepoByTree = "GET /repos/{owner}/{repo}/git/trees/{tree}" + GetReposGitRefByOwnerByRepoByRef = "GET /repos/{owner}/{repo}/git/ref/{ref}" + PostReposGitRefsByOwnerByRepo = "POST /repos/{owner}/{repo}/git/refs" + PatchReposGitRefsByOwnerByRepoByRef = "PATCH /repos/{owner}/{repo}/git/refs/{ref}" + GetReposGitCommitsByOwnerByRepoByCommitSha = "GET /repos/{owner}/{repo}/git/commits/{commit_sha}" + PostReposGitCommitsByOwnerByRepo = "POST /repos/{owner}/{repo}/git/commits" + GetReposGitTagsByOwnerByRepoByTagSha = "GET /repos/{owner}/{repo}/git/tags/{tag_sha}" + PostReposGitTreesByOwnerByRepo = "POST /repos/{owner}/{repo}/git/trees" + GetReposCommitsStatusByOwnerByRepoByRef = "GET /repos/{owner}/{repo}/commits/{ref}/status" + GetReposCommitsStatusesByOwnerByRepoByRef = "GET /repos/{owner}/{repo}/commits/{ref}/statuses" + + // Issues endpoints + GetReposIssuesByOwnerByRepoByIssueNumber = "GET /repos/{owner}/{repo}/issues/{issue_number}" + GetReposIssuesCommentsByOwnerByRepoByIssueNumber = "GET /repos/{owner}/{repo}/issues/{issue_number}/comments" + PostReposIssuesByOwnerByRepo = "POST /repos/{owner}/{repo}/issues" + PostReposIssuesCommentsByOwnerByRepoByIssueNumber = "POST /repos/{owner}/{repo}/issues/{issue_number}/comments" + PatchReposIssuesByOwnerByRepoByIssueNumber = "PATCH /repos/{owner}/{repo}/issues/{issue_number}" + GetReposIssuesSubIssuesByOwnerByRepoByIssueNumber = "GET /repos/{owner}/{repo}/issues/{issue_number}/sub_issues" + PostReposIssuesSubIssuesByOwnerByRepoByIssueNumber = "POST /repos/{owner}/{repo}/issues/{issue_number}/sub_issues" + DeleteReposIssuesSubIssueByOwnerByRepoByIssueNumber = "DELETE /repos/{owner}/{repo}/issues/{issue_number}/sub_issues" + PatchReposIssuesSubIssuesPriorityByOwnerByRepoByIssueNumber = "PATCH /repos/{owner}/{repo}/issues/{issue_number}/sub_issues/priority" + + // Pull request endpoints + GetReposPullsByOwnerByRepo = "GET /repos/{owner}/{repo}/pulls" + GetReposPullsByOwnerByRepoByPullNumber = "GET /repos/{owner}/{repo}/pulls/{pull_number}" + GetReposPullsFilesByOwnerByRepoByPullNumber = "GET /repos/{owner}/{repo}/pulls/{pull_number}/files" + GetReposPullsReviewsByOwnerByRepoByPullNumber = "GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews" + PostReposPullsByOwnerByRepo = "POST /repos/{owner}/{repo}/pulls" + PatchReposPullsByOwnerByRepoByPullNumber = "PATCH /repos/{owner}/{repo}/pulls/{pull_number}" + PutReposPullsMergeByOwnerByRepoByPullNumber = "PUT /repos/{owner}/{repo}/pulls/{pull_number}/merge" + PutReposPullsUpdateBranchByOwnerByRepoByPullNumber = "PUT /repos/{owner}/{repo}/pulls/{pull_number}/update-branch" + PostReposPullsRequestedReviewersByOwnerByRepoByPullNumber = "POST /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers" + + // Notifications endpoints + GetNotifications = "GET /notifications" + PutNotifications = "PUT /notifications" + GetReposNotificationsByOwnerByRepo = "GET /repos/{owner}/{repo}/notifications" + PutReposNotificationsByOwnerByRepo = "PUT /repos/{owner}/{repo}/notifications" + GetNotificationsThreadsByThreadId = "GET /notifications/threads/{thread_id}" + PatchNotificationsThreadsByThreadId = "PATCH /notifications/threads/{thread_id}" + DeleteNotificationsThreadsByThreadId = "DELETE /notifications/threads/{thread_id}" + PutNotificationsThreadsSubscriptionByThreadId = "PUT /notifications/threads/{thread_id}/subscription" + DeleteNotificationsThreadsSubscriptionByThreadId = "DELETE /notifications/threads/{thread_id}/subscription" + + // Gists endpoints + GetGists = "GET /gists" + GetGistsByGistId = "GET /gists/{gist_id}" + PostGists = "POST /gists" + PatchGistsByGistId = "PATCH /gists/{gist_id}" + + // Releases endpoints + GetReposReleasesByOwnerByRepo = "GET /repos/{owner}/{repo}/releases" + GetReposReleasesLatestByOwnerByRepo = "GET /repos/{owner}/{repo}/releases/latest" + GetReposReleasesTagsByOwnerByRepoByTag = "GET /repos/{owner}/{repo}/releases/tags/{tag}" // Code scanning endpoints GetReposCodeScanningAlertsByOwnerByRepo = "GET /repos/{owner}/{repo}/code-scanning/alerts" GetReposCodeScanningAlertsByOwnerByRepoByAlertNumber = "GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}" + + // Secret scanning endpoints + GetReposSecretScanningAlertsByOwnerByRepo = "GET /repos/{owner}/{repo}/secret-scanning/alerts" + GetReposSecretScanningAlertsByOwnerByRepoByAlertNumber = "GET /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}" + + // Dependabot endpoints + GetReposDependabotAlertsByOwnerByRepo = "GET /repos/{owner}/{repo}/dependabot/alerts" + GetReposDependabotAlertsByOwnerByRepoByAlertNumber = "GET /repos/{owner}/{repo}/dependabot/alerts/{alert_number}" + + // Security advisories endpoints + GetAdvisories = "GET /advisories" + GetAdvisoriesByGhsaId = "GET /advisories/{ghsa_id}" + + // Actions endpoints + GetReposActionsWorkflowsByOwnerByRepo = "GET /repos/{owner}/{repo}/actions/workflows" + PostReposActionsWorkflowsDispatchesByOwnerByRepoByWorkflowId = "POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches" + GetReposActionsRunsJobsByOwnerByRepoByRunId = "GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs" + GetReposActionsRunsArtifactsByOwnerByRepoByRunId = "GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts" + GetReposActionsRunsTimingByOwnerByRepoByRunId = "GET /repos/{owner}/{repo}/actions/runs/{run_id}/timing" + GetReposActionsJobsLogsByOwnerByRepoByJobId = "GET /repos/{owner}/{repo}/actions/jobs/{job_id}/logs" + DeleteReposActionsRunsLogsByOwnerByRepoByRunId = "DELETE /repos/{owner}/{repo}/actions/runs/{run_id}/logs" + + // Search endpoints + GetSearchCode = "GET /search/code" + GetSearchIssues = "GET /search/issues" + GetSearchRepositories = "GET /search/repositories" + GetSearchUsers = "GET /search/users" + + // Raw content endpoints (used for GitHub raw content API, not standard API) + // These are used with the raw content client that interacts with raw.githubusercontent.com + GetRawReposContentsByOwnerByRepoByPath = "GET /{owner}/{repo}/HEAD/{path}" + GetRawReposContentsByOwnerByRepoByBranchByPath = "GET /{owner}/{repo}/refs/heads/{branch}/{path}" + GetRawReposContentsByOwnerByRepoByTagByPath = "GET /{owner}/{repo}/refs/tags/{tag}/{path}" + GetRawReposContentsByOwnerByRepoBySHAByPath = "GET /{owner}/{repo}/{sha}/{path}" ) type expectations struct { @@ -382,6 +487,27 @@ func matchPath(pattern, path string) bool { patternParts := strings.Split(strings.Trim(pattern, "/"), "/") pathParts := strings.Split(strings.Trim(path, "/"), "/") + // Handle patterns with wildcard path like {path:.*} + if len(patternParts) > 0 { + lastPart := patternParts[len(patternParts)-1] + if strings.HasPrefix(lastPart, "{") && strings.Contains(lastPart, ":") && strings.HasSuffix(lastPart, "}") { + // This is a wildcard pattern like {path:.*} + // Check if all parts before the wildcard match + if len(pathParts) < len(patternParts)-1 { + return false + } + for i := 0; i < len(patternParts)-1; i++ { + if strings.HasPrefix(patternParts[i], "{") && strings.HasSuffix(patternParts[i], "}") { + continue // Path parameter matches anything + } + if patternParts[i] != pathParts[i] { + return false + } + } + return true + } + } + if len(patternParts) != len(pathParts) { return false } diff --git a/pkg/raw/raw_mock.go b/pkg/raw/raw_mock.go deleted file mode 100644 index 30c7759d3..000000000 --- a/pkg/raw/raw_mock.go +++ /dev/null @@ -1,20 +0,0 @@ -package raw - -import "github.com/migueleliasweb/go-github-mock/src/mock" - -var GetRawReposContentsByOwnerByRepoByPath mock.EndpointPattern = mock.EndpointPattern{ - Pattern: "/{owner}/{repo}/HEAD/{path:.*}", - Method: "GET", -} -var GetRawReposContentsByOwnerByRepoByBranchByPath mock.EndpointPattern = mock.EndpointPattern{ - Pattern: "/{owner}/{repo}/refs/heads/{branch}/{path:.*}", - Method: "GET", -} -var GetRawReposContentsByOwnerByRepoByTagByPath mock.EndpointPattern = mock.EndpointPattern{ - Pattern: "/{owner}/{repo}/refs/tags/{tag}/{path:.*}", - Method: "GET", -} -var GetRawReposContentsByOwnerByRepoBySHAByPath mock.EndpointPattern = mock.EndpointPattern{ - Pattern: "/{owner}/{repo}/{sha}/{path:.*}", - Method: "GET", -} diff --git a/pkg/raw/raw_test.go b/pkg/raw/raw_test.go index 242029c8b..41c65d13b 100644 --- a/pkg/raw/raw_test.go +++ b/pkg/raw/raw_test.go @@ -1,22 +1,44 @@ package raw import ( + "bytes" "context" + "io" "net/http" "net/url" + "strings" "testing" "github.com/google/go-github/v79/github" - "github.com/migueleliasweb/go-github-mock/src/mock" "github.com/stretchr/testify/require" ) +// mockRawTransport is a custom HTTP transport for testing raw content API +type mockRawTransport struct { + statusCode int + contentType string + body string +} + +func (m *mockRawTransport) RoundTrip(req *http.Request) (*http.Response, error) { + // Create a response with the configured status and body + resp := &http.Response{ + StatusCode: m.statusCode, + Header: make(http.Header), + Body: io.NopCloser(bytes.NewBufferString(m.body)), + Request: req, + } + if m.contentType != "" { + resp.Header.Set("Content-Type", m.contentType) + } + return resp, nil +} + func TestGetRawContent(t *testing.T) { base, _ := url.Parse("https://raw.example.com/") tests := []struct { name string - pattern mock.EndpointPattern opts *ContentOpts owner, repo, path string statusCode int @@ -25,46 +47,51 @@ func TestGetRawContent(t *testing.T) { expectError string }{ { - name: "HEAD fetch success", - pattern: GetRawReposContentsByOwnerByRepoByPath, - opts: nil, - owner: "octocat", repo: "hello", path: "README.md", + name: "HEAD fetch success", + opts: nil, + owner: "octocat", + repo: "hello", + path: "README.md", statusCode: 200, contentType: "text/plain", body: "# Test file", }, { - name: "branch fetch success", - pattern: GetRawReposContentsByOwnerByRepoByBranchByPath, - opts: &ContentOpts{Ref: "refs/heads/main"}, - owner: "octocat", repo: "hello", path: "README.md", + name: "branch fetch success", + opts: &ContentOpts{Ref: "refs/heads/main"}, + owner: "octocat", + repo: "hello", + path: "README.md", statusCode: 200, contentType: "text/plain", body: "# Test file", }, { - name: "tag fetch success", - pattern: GetRawReposContentsByOwnerByRepoByTagByPath, - opts: &ContentOpts{Ref: "refs/tags/v1.0.0"}, - owner: "octocat", repo: "hello", path: "README.md", + name: "tag fetch success", + opts: &ContentOpts{Ref: "refs/tags/v1.0.0"}, + owner: "octocat", + repo: "hello", + path: "README.md", statusCode: 200, contentType: "text/plain", body: "# Test file", }, { - name: "sha fetch success", - pattern: GetRawReposContentsByOwnerByRepoBySHAByPath, - opts: &ContentOpts{SHA: "abc123"}, - owner: "octocat", repo: "hello", path: "README.md", + name: "sha fetch success", + opts: &ContentOpts{SHA: "abc123"}, + owner: "octocat", + repo: "hello", + path: "README.md", statusCode: 200, contentType: "text/plain", body: "# Test file", }, { - name: "not found", - pattern: GetRawReposContentsByOwnerByRepoByPath, - opts: nil, - owner: "octocat", repo: "hello", path: "notfound.txt", + name: "not found", + opts: nil, + owner: "octocat", + repo: "hello", + path: "notfound.txt", statusCode: 404, contentType: "application/json", body: `{"message": "Not Found"}`, @@ -73,29 +100,33 @@ func TestGetRawContent(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - mockedClient := mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - tc.pattern, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", tc.contentType) - w.WriteHeader(tc.statusCode) - _, err := w.Write([]byte(tc.body)) - require.NoError(t, err) - }), - ), - ) + // Create mock HTTP client with custom transport + mockedClient := &http.Client{ + Transport: &mockRawTransport{ + statusCode: tc.statusCode, + contentType: tc.contentType, + body: tc.body, + }, + } ghClient := github.NewClient(mockedClient) client := NewClient(ghClient, base) resp, err := client.GetRawContent(context.Background(), tc.owner, tc.repo, tc.path, tc.opts) defer func() { _ = resp.Body.Close() }() + if tc.expectError != "" { require.Error(t, err) return } require.NoError(t, err) require.Equal(t, tc.statusCode, resp.StatusCode) + + // Verify the URL was constructed correctly + actualURL := client.URLFromOpts(tc.opts, tc.owner, tc.repo, tc.path) + require.True(t, strings.Contains(actualURL, tc.owner)) + require.True(t, strings.Contains(actualURL, tc.repo)) + require.True(t, strings.Contains(actualURL, tc.path)) }) } } From f4a8dbaab7e5cad118ea8cb38d84fba205f0becc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 09:18:44 +0000 Subject: [PATCH 03/13] Migrate security_advisories_test.go to testify mocks Co-authored-by: JoannaaKL <67866556+JoannaaKL@users.noreply.github.com> --- pkg/github/helper_test.go | 6 +- pkg/github/repositories_test.go | 10 +- pkg/github/repository_resource_test.go | 18 +-- pkg/github/security_advisories_test.go | 209 ++++++++++--------------- 4 files changed, 98 insertions(+), 145 deletions(-) diff --git a/pkg/github/helper_test.go b/pkg/github/helper_test.go index b62a67708..cfbbc91f0 100644 --- a/pkg/github/helper_test.go +++ b/pkg/github/helper_test.go @@ -108,8 +108,10 @@ const ( GetReposDependabotAlertsByOwnerByRepoByAlertNumber = "GET /repos/{owner}/{repo}/dependabot/alerts/{alert_number}" // Security advisories endpoints - GetAdvisories = "GET /advisories" - GetAdvisoriesByGhsaId = "GET /advisories/{ghsa_id}" + GetAdvisories = "GET /advisories" + GetAdvisoriesByGhsaId = "GET /advisories/{ghsa_id}" + GetReposSecurityAdvisoriesByOwnerByRepo = "GET /repos/{owner}/{repo}/security-advisories" + GetOrgsSecurityAdvisoriesByOrg = "GET /orgs/{org}/security-advisories" // Actions endpoints GetReposActionsWorkflowsByOwnerByRepo = "GET /repos/{owner}/{repo}/actions/workflows" diff --git a/pkg/github/repositories_test.go b/pkg/github/repositories_test.go index 4e978a81a..c073cf22d 100644 --- a/pkg/github/repositories_test.go +++ b/pkg/github/repositories_test.go @@ -95,7 +95,7 @@ func Test_GetFileContents(t *testing.T) { }), ), mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoByBranchByPath, + GetRawReposContentsByOwnerByRepoByBranchByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, _ = w.Write(mockRawContent) @@ -140,7 +140,7 @@ func Test_GetFileContents(t *testing.T) { }), ), mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoByBranchByPath, + GetRawReposContentsByOwnerByRepoByBranchByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "image/png") _, _ = w.Write(mockRawContent) @@ -185,7 +185,7 @@ func Test_GetFileContents(t *testing.T) { }), ), mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoByBranchByPath, + GetRawReposContentsByOwnerByRepoByBranchByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "application/pdf") _, _ = w.Write(mockRawContent) @@ -229,7 +229,7 @@ func Test_GetFileContents(t *testing.T) { ), ), mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoByPath, + GetRawReposContentsByOwnerByRepoByPath, expectQueryParams(t, map[string]string{ "branch": "main", }).andThen( @@ -263,7 +263,7 @@ func Test_GetFileContents(t *testing.T) { }), ), mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoByPath, + GetRawReposContentsByOwnerByRepoByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNotFound) _, _ = w.Write([]byte(`{"message": "Not Found"}`)) diff --git a/pkg/github/repository_resource_test.go b/pkg/github/repository_resource_test.go index 99c06cdd6..87d7ff2a1 100644 --- a/pkg/github/repository_resource_test.go +++ b/pkg/github/repository_resource_test.go @@ -36,7 +36,7 @@ func Test_repositoryResourceContents(t *testing.T) { name: "missing owner", mockedClient: mock.NewMockedHTTPClient( mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoByPath, + GetRawReposContentsByOwnerByRepoByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) @@ -55,7 +55,7 @@ func Test_repositoryResourceContents(t *testing.T) { name: "missing repo", mockedClient: mock.NewMockedHTTPClient( mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoByBranchByPath, + GetRawReposContentsByOwnerByRepoByBranchByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) @@ -74,7 +74,7 @@ func Test_repositoryResourceContents(t *testing.T) { name: "successful blob content fetch", mockedClient: mock.NewMockedHTTPClient( mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoByPath, + GetRawReposContentsByOwnerByRepoByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "image/png") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) @@ -98,7 +98,7 @@ func Test_repositoryResourceContents(t *testing.T) { name: "successful text content fetch (HEAD)", mockedClient: mock.NewMockedHTTPClient( mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoByPath, + GetRawReposContentsByOwnerByRepoByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) @@ -122,7 +122,7 @@ func Test_repositoryResourceContents(t *testing.T) { name: "successful text content fetch (HEAD)", mockedClient: mock.NewMockedHTTPClient( mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoByPath, + GetRawReposContentsByOwnerByRepoByPath, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain") @@ -148,7 +148,7 @@ func Test_repositoryResourceContents(t *testing.T) { name: "successful text content fetch (branch)", mockedClient: mock.NewMockedHTTPClient( mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoByBranchByPath, + GetRawReposContentsByOwnerByRepoByBranchByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) @@ -172,7 +172,7 @@ func Test_repositoryResourceContents(t *testing.T) { name: "successful text content fetch (tag)", mockedClient: mock.NewMockedHTTPClient( mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoByTagByPath, + GetRawReposContentsByOwnerByRepoByTagByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) @@ -196,7 +196,7 @@ func Test_repositoryResourceContents(t *testing.T) { name: "successful text content fetch (sha)", mockedClient: mock.NewMockedHTTPClient( mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoBySHAByPath, + GetRawReposContentsByOwnerByRepoBySHAByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) @@ -228,7 +228,7 @@ func Test_repositoryResourceContents(t *testing.T) { }), ), mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoBySHAByPath, + GetRawReposContentsByOwnerByRepoBySHAByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) diff --git a/pkg/github/security_advisories_test.go b/pkg/github/security_advisories_test.go index 3970949ec..1bd8c12f8 100644 --- a/pkg/github/security_advisories_test.go +++ b/pkg/github/security_advisories_test.go @@ -10,7 +10,6 @@ import ( "github.com/github/github-mcp-server/pkg/translations" "github.com/google/go-github/v79/github" "github.com/google/jsonschema-go/jsonschema" - "github.com/migueleliasweb/go-github-mock/src/mock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -50,12 +49,9 @@ func Test_ListGlobalSecurityAdvisories(t *testing.T) { }{ { name: "successful advisory fetch", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.GetAdvisories, - []*github.GlobalSecurityAdvisory{mockAdvisory}, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetAdvisories: mockResponse(t, http.StatusOK, []*github.GlobalSecurityAdvisory{mockAdvisory}), + }), requestArgs: map[string]interface{}{ "type": "reviewed", "ecosystem": "npm", @@ -66,15 +62,12 @@ func Test_ListGlobalSecurityAdvisories(t *testing.T) { }, { name: "invalid severity value", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetAdvisories, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write([]byte(`{"message": "Bad Request"}`)) - }), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetAdvisories: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusBadRequest) + _, _ = w.Write([]byte(`{"message": "Bad Request"}`)) + }), + }), requestArgs: map[string]interface{}{ "type": "reviewed", "severity": "extreme", @@ -84,15 +77,12 @@ func Test_ListGlobalSecurityAdvisories(t *testing.T) { }, { name: "API error handling", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetAdvisories, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write([]byte(`{"message": "Internal Server Error"}`)) - }), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetAdvisories: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write([]byte(`{"message": "Internal Server Error"}`)) + }), + }), requestArgs: map[string]interface{}{}, expectError: true, expectedErrMsg: "failed to list global security advisories", @@ -172,12 +162,9 @@ func Test_GetGlobalSecurityAdvisory(t *testing.T) { }{ { name: "successful advisory fetch", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.GetAdvisoriesByGhsaId, - mockAdvisory, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetAdvisoriesByGhsaId: mockResponse(t, http.StatusOK, mockAdvisory), + }), requestArgs: map[string]interface{}{ "ghsaId": "GHSA-xxxx-xxxx-xxxx", }, @@ -186,15 +173,12 @@ func Test_GetGlobalSecurityAdvisory(t *testing.T) { }, { name: "invalid ghsaId format", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetAdvisoriesByGhsaId, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write([]byte(`{"message": "Bad Request"}`)) - }), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetAdvisoriesByGhsaId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusBadRequest) + _, _ = w.Write([]byte(`{"message": "Bad Request"}`)) + }), + }), requestArgs: map[string]interface{}{ "ghsaId": "invalid-ghsa-id", }, @@ -203,15 +187,12 @@ func Test_GetGlobalSecurityAdvisory(t *testing.T) { }, { name: "advisory not found", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetAdvisoriesByGhsaId, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusNotFound) - _, _ = w.Write([]byte(`{"message": "Not Found"}`)) - }), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetAdvisoriesByGhsaId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusNotFound) + _, _ = w.Write([]byte(`{"message": "Not Found"}`)) + }), + }), requestArgs: map[string]interface{}{ "ghsaId": "GHSA-xxxx-xxxx-xxxx", }, @@ -272,12 +253,6 @@ func Test_ListRepositorySecurityAdvisories(t *testing.T) { assert.Contains(t, schema.Properties, "state") assert.ElementsMatch(t, schema.Required, []string{"owner", "repo"}) - // Local endpoint pattern for repository security advisories - var GetReposSecurityAdvisoriesByOwnerByRepo = mock.EndpointPattern{ - Pattern: "/repos/{owner}/{repo}/security-advisories", - Method: "GET", - } - // Setup mock advisories for success cases adv1 := &github.SecurityAdvisory{ GHSAID: github.Ptr("GHSA-1111-1111-1111"), @@ -302,17 +277,14 @@ func Test_ListRepositorySecurityAdvisories(t *testing.T) { }{ { name: "successful advisories listing (no filters)", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - GetReposSecurityAdvisoriesByOwnerByRepo, - expect(t, expectations{ - path: "/repos/owner/repo/security-advisories", - queryParams: map[string]string{}, - }).andThen( - mockResponse(t, http.StatusOK, []*github.SecurityAdvisory{adv1, adv2}), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposSecurityAdvisoriesByOwnerByRepo: expect(t, expectations{ + path: "/repos/owner/repo/security-advisories", + queryParams: map[string]string{}, + }).andThen( + mockResponse(t, http.StatusOK, []*github.SecurityAdvisory{adv1, adv2}), ), - ), + }), requestArgs: map[string]interface{}{ "owner": "owner", "repo": "repo", @@ -322,21 +294,18 @@ func Test_ListRepositorySecurityAdvisories(t *testing.T) { }, { name: "successful advisories listing with filters", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - GetReposSecurityAdvisoriesByOwnerByRepo, - expect(t, expectations{ - path: "/repos/octo/hello-world/security-advisories", - queryParams: map[string]string{ - "direction": "desc", - "sort": "updated", - "state": "published", - }, - }).andThen( - mockResponse(t, http.StatusOK, []*github.SecurityAdvisory{adv1}), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposSecurityAdvisoriesByOwnerByRepo: expect(t, expectations{ + path: "/repos/octo/hello-world/security-advisories", + queryParams: map[string]string{ + "direction": "desc", + "sort": "updated", + "state": "published", + }, + }).andThen( + mockResponse(t, http.StatusOK, []*github.SecurityAdvisory{adv1}), ), - ), + }), requestArgs: map[string]interface{}{ "owner": "octo", "repo": "hello-world", @@ -349,17 +318,14 @@ func Test_ListRepositorySecurityAdvisories(t *testing.T) { }, { name: "advisories listing fails", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - GetReposSecurityAdvisoriesByOwnerByRepo, - expect(t, expectations{ - path: "/repos/owner/repo/security-advisories", - queryParams: map[string]string{}, - }).andThen( - mockResponse(t, http.StatusInternalServerError, map[string]string{"message": "Internal Server Error"}), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposSecurityAdvisoriesByOwnerByRepo: expect(t, expectations{ + path: "/repos/owner/repo/security-advisories", + queryParams: map[string]string{}, + }).andThen( + mockResponse(t, http.StatusInternalServerError, map[string]string{"message": "Internal Server Error"}), ), - ), + }), requestArgs: map[string]interface{}{ "owner": "owner", "repo": "repo", @@ -421,12 +387,6 @@ func Test_ListOrgRepositorySecurityAdvisories(t *testing.T) { assert.Contains(t, schema.Properties, "state") assert.ElementsMatch(t, schema.Required, []string{"org"}) - // Endpoint pattern for org repository security advisories - var GetOrgsSecurityAdvisoriesByOrg = mock.EndpointPattern{ - Pattern: "/orgs/{org}/security-advisories", - Method: "GET", - } - adv1 := &github.SecurityAdvisory{ GHSAID: github.Ptr("GHSA-aaaa-bbbb-cccc"), Summary: github.Ptr("Org repo advisory 1"), @@ -450,17 +410,14 @@ func Test_ListOrgRepositorySecurityAdvisories(t *testing.T) { }{ { name: "successful listing (no filters)", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - GetOrgsSecurityAdvisoriesByOrg, - expect(t, expectations{ - path: "/orgs/octo/security-advisories", - queryParams: map[string]string{}, - }).andThen( - mockResponse(t, http.StatusOK, []*github.SecurityAdvisory{adv1, adv2}), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetOrgsSecurityAdvisoriesByOrg: expect(t, expectations{ + path: "/orgs/octo/security-advisories", + queryParams: map[string]string{}, + }).andThen( + mockResponse(t, http.StatusOK, []*github.SecurityAdvisory{adv1, adv2}), ), - ), + }), requestArgs: map[string]interface{}{ "org": "octo", }, @@ -469,21 +426,18 @@ func Test_ListOrgRepositorySecurityAdvisories(t *testing.T) { }, { name: "successful listing with filters", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - GetOrgsSecurityAdvisoriesByOrg, - expect(t, expectations{ - path: "/orgs/octo/security-advisories", - queryParams: map[string]string{ - "direction": "asc", - "sort": "created", - "state": "triage", - }, - }).andThen( - mockResponse(t, http.StatusOK, []*github.SecurityAdvisory{adv1}), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetOrgsSecurityAdvisoriesByOrg: expect(t, expectations{ + path: "/orgs/octo/security-advisories", + queryParams: map[string]string{ + "direction": "asc", + "sort": "created", + "state": "triage", + }, + }).andThen( + mockResponse(t, http.StatusOK, []*github.SecurityAdvisory{adv1}), ), - ), + }), requestArgs: map[string]interface{}{ "org": "octo", "direction": "asc", @@ -495,17 +449,14 @@ func Test_ListOrgRepositorySecurityAdvisories(t *testing.T) { }, { name: "listing fails", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - GetOrgsSecurityAdvisoriesByOrg, - expect(t, expectations{ - path: "/orgs/octo/security-advisories", - queryParams: map[string]string{}, - }).andThen( - mockResponse(t, http.StatusForbidden, map[string]string{"message": "Forbidden"}), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetOrgsSecurityAdvisoriesByOrg: expect(t, expectations{ + path: "/orgs/octo/security-advisories", + queryParams: map[string]string{}, + }).andThen( + mockResponse(t, http.StatusForbidden, map[string]string{"message": "Forbidden"}), ), - ), + }), requestArgs: map[string]interface{}{ "org": "octo", }, From 070e14ed2bc1900311c22fab043e70a65308e78a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 09:32:33 +0000 Subject: [PATCH 04/13] Migrate actions, dependabot, and secret_scanning tests to testify Co-authored-by: JoannaaKL <67866556+JoannaaKL@users.noreply.github.com> --- pkg/github/actions_test.go | 547 +++++++++++-------------- pkg/github/dependabot_test.go | 81 ++-- pkg/github/repositories_test.go | 10 +- pkg/github/repository_resource_test.go | 18 +- pkg/github/secret_scanning_test.go | 66 ++- pkg/raw/raw_mock.go | 20 + 6 files changed, 330 insertions(+), 412 deletions(-) create mode 100644 pkg/raw/raw_mock.go diff --git a/pkg/github/actions_test.go b/pkg/github/actions_test.go index 4d56f01aa..8c00c9af5 100644 --- a/pkg/github/actions_test.go +++ b/pkg/github/actions_test.go @@ -18,7 +18,6 @@ import ( "github.com/github/github-mcp-server/pkg/translations" "github.com/google/go-github/v79/github" "github.com/google/jsonschema-go/jsonschema" - "github.com/migueleliasweb/go-github-mock/src/mock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -46,44 +45,41 @@ func Test_ListWorkflows(t *testing.T) { }{ { name: "successful workflow listing", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposActionsWorkflowsByOwnerByRepo, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - workflows := &github.Workflows{ - TotalCount: github.Ptr(2), - Workflows: []*github.Workflow{ - { - ID: github.Ptr(int64(123)), - Name: github.Ptr("CI"), - Path: github.Ptr(".github/workflows/ci.yml"), - State: github.Ptr("active"), - CreatedAt: &github.Timestamp{}, - UpdatedAt: &github.Timestamp{}, - URL: github.Ptr("https://api.github.com/repos/owner/repo/actions/workflows/123"), - HTMLURL: github.Ptr("https://github.com/owner/repo/actions/workflows/ci.yml"), - BadgeURL: github.Ptr("https://github.com/owner/repo/workflows/CI/badge.svg"), - NodeID: github.Ptr("W_123"), - }, - { - ID: github.Ptr(int64(456)), - Name: github.Ptr("Deploy"), - Path: github.Ptr(".github/workflows/deploy.yml"), - State: github.Ptr("active"), - CreatedAt: &github.Timestamp{}, - UpdatedAt: &github.Timestamp{}, - URL: github.Ptr("https://api.github.com/repos/owner/repo/actions/workflows/456"), - HTMLURL: github.Ptr("https://github.com/owner/repo/actions/workflows/deploy.yml"), - BadgeURL: github.Ptr("https://github.com/owner/repo/workflows/Deploy/badge.svg"), - NodeID: github.Ptr("W_456"), - }, + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposActionsWorkflowsByOwnerByRepo: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + workflows := &github.Workflows{ + TotalCount: github.Ptr(2), + Workflows: []*github.Workflow{ + { + ID: github.Ptr(int64(123)), + Name: github.Ptr("CI"), + Path: github.Ptr(".github/workflows/ci.yml"), + State: github.Ptr("active"), + CreatedAt: &github.Timestamp{}, + UpdatedAt: &github.Timestamp{}, + URL: github.Ptr("https://api.github.com/repos/owner/repo/actions/workflows/123"), + HTMLURL: github.Ptr("https://github.com/owner/repo/actions/workflows/ci.yml"), + BadgeURL: github.Ptr("https://github.com/owner/repo/workflows/CI/badge.svg"), + NodeID: github.Ptr("W_123"), + }, + { + ID: github.Ptr(int64(456)), + Name: github.Ptr("Deploy"), + Path: github.Ptr(".github/workflows/deploy.yml"), + State: github.Ptr("active"), + CreatedAt: &github.Timestamp{}, + UpdatedAt: &github.Timestamp{}, + URL: github.Ptr("https://api.github.com/repos/owner/repo/actions/workflows/456"), + HTMLURL: github.Ptr("https://github.com/owner/repo/actions/workflows/deploy.yml"), + BadgeURL: github.Ptr("https://github.com/owner/repo/workflows/Deploy/badge.svg"), + NodeID: github.Ptr("W_456"), }, - } - w.WriteHeader(http.StatusOK) - _ = json.NewEncoder(w).Encode(workflows) - }), - ), - ), + }, + } + w.WriteHeader(http.StatusOK) + _ = json.NewEncoder(w).Encode(workflows) + }), + }), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -92,7 +88,7 @@ func Test_ListWorkflows(t *testing.T) { }, { name: "missing required parameter owner", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]any{ "repo": "repo", }, @@ -161,14 +157,11 @@ func Test_RunWorkflow(t *testing.T) { }{ { name: "successful workflow run", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.PostReposActionsWorkflowsDispatchesByOwnerByRepoByWorkflowId, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusNoContent) - }), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + PostReposActionsWorkflowsDispatchesByOwnerByRepoByWorkflowId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusNoContent) + }), + }), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -179,7 +172,7 @@ func Test_RunWorkflow(t *testing.T) { }, { name: "missing required parameter workflow_id", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -239,14 +232,11 @@ func Test_RunWorkflow_WithFilename(t *testing.T) { }{ { name: "successful workflow run by filename", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.PostReposActionsWorkflowsDispatchesByOwnerByRepoByWorkflowId, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusNoContent) - }), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + PostReposActionsWorkflowsDispatchesByOwnerByRepoByWorkflowId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusNoContent) + }), + }), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -257,14 +247,11 @@ func Test_RunWorkflow_WithFilename(t *testing.T) { }, { name: "successful workflow run by numeric ID as string", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.PostReposActionsWorkflowsDispatchesByOwnerByRepoByWorkflowId, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusNoContent) - }), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + PostReposActionsWorkflowsDispatchesByOwnerByRepoByWorkflowId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusNoContent) + }), + }), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -275,7 +262,7 @@ func Test_RunWorkflow_WithFilename(t *testing.T) { }, { name: "missing required parameter workflow_id", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -343,17 +330,11 @@ func Test_CancelWorkflowRun(t *testing.T) { }{ { name: "successful workflow run cancellation", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.EndpointPattern{ - Pattern: "/repos/owner/repo/actions/runs/12345/cancel", - Method: "POST", - }, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusAccepted) - }), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + "POST /repos/owner/repo/actions/runs/12345/cancel": http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusAccepted) + }), + }), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -363,17 +344,11 @@ func Test_CancelWorkflowRun(t *testing.T) { }, { name: "conflict when cancelling a workflow run", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.EndpointPattern{ - Pattern: "/repos/owner/repo/actions/runs/12345/cancel", - Method: "POST", - }, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusConflict) - }), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + "POST /repos/owner/repo/actions/runs/12345/cancel": http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusConflict) + }), + }), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -384,7 +359,7 @@ func Test_CancelWorkflowRun(t *testing.T) { }, { name: "missing required parameter run_id", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -453,58 +428,55 @@ func Test_ListWorkflowRunArtifacts(t *testing.T) { }{ { name: "successful artifacts listing", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposActionsRunsArtifactsByOwnerByRepoByRunId, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - artifacts := &github.ArtifactList{ - TotalCount: github.Ptr(int64(2)), - Artifacts: []*github.Artifact{ - { - ID: github.Ptr(int64(1)), - NodeID: github.Ptr("A_1"), - Name: github.Ptr("build-artifacts"), - SizeInBytes: github.Ptr(int64(1024)), - URL: github.Ptr("https://api.github.com/repos/owner/repo/actions/artifacts/1"), - ArchiveDownloadURL: github.Ptr("https://api.github.com/repos/owner/repo/actions/artifacts/1/zip"), - Expired: github.Ptr(false), - CreatedAt: &github.Timestamp{}, - UpdatedAt: &github.Timestamp{}, - ExpiresAt: &github.Timestamp{}, - WorkflowRun: &github.ArtifactWorkflowRun{ - ID: github.Ptr(int64(12345)), - RepositoryID: github.Ptr(int64(1)), - HeadRepositoryID: github.Ptr(int64(1)), - HeadBranch: github.Ptr("main"), - HeadSHA: github.Ptr("abc123"), - }, + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposActionsRunsArtifactsByOwnerByRepoByRunId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + artifacts := &github.ArtifactList{ + TotalCount: github.Ptr(int64(2)), + Artifacts: []*github.Artifact{ + { + ID: github.Ptr(int64(1)), + NodeID: github.Ptr("A_1"), + Name: github.Ptr("build-artifacts"), + SizeInBytes: github.Ptr(int64(1024)), + URL: github.Ptr("https://api.github.com/repos/owner/repo/actions/artifacts/1"), + ArchiveDownloadURL: github.Ptr("https://api.github.com/repos/owner/repo/actions/artifacts/1/zip"), + Expired: github.Ptr(false), + CreatedAt: &github.Timestamp{}, + UpdatedAt: &github.Timestamp{}, + ExpiresAt: &github.Timestamp{}, + WorkflowRun: &github.ArtifactWorkflowRun{ + ID: github.Ptr(int64(12345)), + RepositoryID: github.Ptr(int64(1)), + HeadRepositoryID: github.Ptr(int64(1)), + HeadBranch: github.Ptr("main"), + HeadSHA: github.Ptr("abc123"), }, - { - ID: github.Ptr(int64(2)), - NodeID: github.Ptr("A_2"), - Name: github.Ptr("test-results"), - SizeInBytes: github.Ptr(int64(512)), - URL: github.Ptr("https://api.github.com/repos/owner/repo/actions/artifacts/2"), - ArchiveDownloadURL: github.Ptr("https://api.github.com/repos/owner/repo/actions/artifacts/2/zip"), - Expired: github.Ptr(false), - CreatedAt: &github.Timestamp{}, - UpdatedAt: &github.Timestamp{}, - ExpiresAt: &github.Timestamp{}, - WorkflowRun: &github.ArtifactWorkflowRun{ - ID: github.Ptr(int64(12345)), - RepositoryID: github.Ptr(int64(1)), - HeadRepositoryID: github.Ptr(int64(1)), - HeadBranch: github.Ptr("main"), - HeadSHA: github.Ptr("abc123"), - }, + }, + { + ID: github.Ptr(int64(2)), + NodeID: github.Ptr("A_2"), + Name: github.Ptr("test-results"), + SizeInBytes: github.Ptr(int64(512)), + URL: github.Ptr("https://api.github.com/repos/owner/repo/actions/artifacts/2"), + ArchiveDownloadURL: github.Ptr("https://api.github.com/repos/owner/repo/actions/artifacts/2/zip"), + Expired: github.Ptr(false), + CreatedAt: &github.Timestamp{}, + UpdatedAt: &github.Timestamp{}, + ExpiresAt: &github.Timestamp{}, + WorkflowRun: &github.ArtifactWorkflowRun{ + ID: github.Ptr(int64(12345)), + RepositoryID: github.Ptr(int64(1)), + HeadRepositoryID: github.Ptr(int64(1)), + HeadBranch: github.Ptr("main"), + HeadSHA: github.Ptr("abc123"), }, }, - } - w.WriteHeader(http.StatusOK) - _ = json.NewEncoder(w).Encode(artifacts) - }), - ), - ), + }, + } + w.WriteHeader(http.StatusOK) + _ = json.NewEncoder(w).Encode(artifacts) + }), + }), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -514,7 +486,7 @@ func Test_ListWorkflowRunArtifacts(t *testing.T) { }, { name: "missing required parameter run_id", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -582,19 +554,13 @@ func Test_DownloadWorkflowRunArtifact(t *testing.T) { }{ { name: "successful artifact download URL", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.EndpointPattern{ - Pattern: "/repos/owner/repo/actions/artifacts/123/zip", - Method: "GET", - }, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - // GitHub returns a 302 redirect to the download URL - w.Header().Set("Location", "https://api.github.com/repos/owner/repo/actions/artifacts/123/download") - w.WriteHeader(http.StatusFound) - }), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + "GET /repos/owner/repo/actions/artifacts/123/zip": http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + // GitHub returns a 302 redirect to the download URL + w.Header().Set("Location", "https://api.github.com/repos/owner/repo/actions/artifacts/123/download") + w.WriteHeader(http.StatusFound) + }), + }), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -604,7 +570,7 @@ func Test_DownloadWorkflowRunArtifact(t *testing.T) { }, { name: "missing required parameter artifact_id", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -673,14 +639,11 @@ func Test_DeleteWorkflowRunLogs(t *testing.T) { }{ { name: "successful logs deletion", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.DeleteReposActionsRunsLogsByOwnerByRepoByRunId, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusNoContent) - }), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + DeleteReposActionsRunsLogsByOwnerByRepoByRunId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusNoContent) + }), + }), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -690,7 +653,7 @@ func Test_DeleteWorkflowRunLogs(t *testing.T) { }, { name: "missing required parameter run_id", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -757,34 +720,31 @@ func Test_GetWorkflowRunUsage(t *testing.T) { }{ { name: "successful workflow run usage", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposActionsRunsTimingByOwnerByRepoByRunId, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - usage := &github.WorkflowRunUsage{ - Billable: &github.WorkflowRunBillMap{ - "UBUNTU": &github.WorkflowRunBill{ - TotalMS: github.Ptr(int64(120000)), - Jobs: github.Ptr(2), - JobRuns: []*github.WorkflowRunJobRun{ - { - JobID: github.Ptr(1), - DurationMS: github.Ptr(int64(60000)), - }, - { - JobID: github.Ptr(2), - DurationMS: github.Ptr(int64(60000)), - }, + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposActionsRunsTimingByOwnerByRepoByRunId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + usage := &github.WorkflowRunUsage{ + Billable: &github.WorkflowRunBillMap{ + "UBUNTU": &github.WorkflowRunBill{ + TotalMS: github.Ptr(int64(120000)), + Jobs: github.Ptr(2), + JobRuns: []*github.WorkflowRunJobRun{ + { + JobID: github.Ptr(1), + DurationMS: github.Ptr(int64(60000)), + }, + { + JobID: github.Ptr(2), + DurationMS: github.Ptr(int64(60000)), }, }, }, - RunDurationMS: github.Ptr(int64(120000)), - } - w.WriteHeader(http.StatusOK) - _ = json.NewEncoder(w).Encode(usage) - }), - ), - ), + }, + RunDurationMS: github.Ptr(int64(120000)), + } + w.WriteHeader(http.StatusOK) + _ = json.NewEncoder(w).Encode(usage) + }), + }), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -794,7 +754,7 @@ func Test_GetWorkflowRunUsage(t *testing.T) { }, { name: "missing required parameter run_id", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -865,15 +825,12 @@ func Test_GetJobLogs(t *testing.T) { }{ { name: "successful single job logs with URL", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposActionsJobsLogsByOwnerByRepoByJobId, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Location", "https://github.com/logs/job/123") - w.WriteHeader(http.StatusFound) - }), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposActionsJobsLogsByOwnerByRepoByJobId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Location", "https://github.com/logs/job/123") + w.WriteHeader(http.StatusFound) + }), + }), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -889,42 +846,36 @@ func Test_GetJobLogs(t *testing.T) { }, { name: "successful failed jobs logs", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposActionsRunsJobsByOwnerByRepoByRunId, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - jobs := &github.Jobs{ - TotalCount: github.Ptr(3), - Jobs: []*github.WorkflowJob{ - { - ID: github.Ptr(int64(1)), - Name: github.Ptr("test-job-1"), - Conclusion: github.Ptr("success"), - }, - { - ID: github.Ptr(int64(2)), - Name: github.Ptr("test-job-2"), - Conclusion: github.Ptr("failure"), - }, - { - ID: github.Ptr(int64(3)), - Name: github.Ptr("test-job-3"), - Conclusion: github.Ptr("failure"), - }, + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposActionsRunsJobsByOwnerByRepoByRunId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + jobs := &github.Jobs{ + TotalCount: github.Ptr(3), + Jobs: []*github.WorkflowJob{ + { + ID: github.Ptr(int64(1)), + Name: github.Ptr("test-job-1"), + Conclusion: github.Ptr("success"), + }, + { + ID: github.Ptr(int64(2)), + Name: github.Ptr("test-job-2"), + Conclusion: github.Ptr("failure"), + }, + { + ID: github.Ptr(int64(3)), + Name: github.Ptr("test-job-3"), + Conclusion: github.Ptr("failure"), }, - } - w.WriteHeader(http.StatusOK) - _ = json.NewEncoder(w).Encode(jobs) - }), - ), - mock.WithRequestMatchHandler( - mock.GetReposActionsJobsLogsByOwnerByRepoByJobId, - http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Location", "https://github.com/logs/job/"+r.URL.Path[len(r.URL.Path)-1:]) - w.WriteHeader(http.StatusFound) - }), - ), - ), + }, + } + w.WriteHeader(http.StatusOK) + _ = json.NewEncoder(w).Encode(jobs) + }), + GetReposActionsJobsLogsByOwnerByRepoByJobId: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Location", "https://github.com/logs/job/"+r.URL.Path[len(r.URL.Path)-1:]) + w.WriteHeader(http.StatusFound) + }), + }), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -946,30 +897,27 @@ func Test_GetJobLogs(t *testing.T) { }, { name: "no failed jobs found", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposActionsRunsJobsByOwnerByRepoByRunId, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - jobs := &github.Jobs{ - TotalCount: github.Ptr(2), - Jobs: []*github.WorkflowJob{ - { - ID: github.Ptr(int64(1)), - Name: github.Ptr("test-job-1"), - Conclusion: github.Ptr("success"), - }, - { - ID: github.Ptr(int64(2)), - Name: github.Ptr("test-job-2"), - Conclusion: github.Ptr("success"), - }, + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposActionsRunsJobsByOwnerByRepoByRunId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + jobs := &github.Jobs{ + TotalCount: github.Ptr(2), + Jobs: []*github.WorkflowJob{ + { + ID: github.Ptr(int64(1)), + Name: github.Ptr("test-job-1"), + Conclusion: github.Ptr("success"), + }, + { + ID: github.Ptr(int64(2)), + Name: github.Ptr("test-job-2"), + Conclusion: github.Ptr("success"), }, - } - w.WriteHeader(http.StatusOK) - _ = json.NewEncoder(w).Encode(jobs) - }), - ), - ), + }, + } + w.WriteHeader(http.StatusOK) + _ = json.NewEncoder(w).Encode(jobs) + }), + }), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -986,7 +934,7 @@ func Test_GetJobLogs(t *testing.T) { }, { name: "missing job_id when not using failed_only", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -996,7 +944,7 @@ func Test_GetJobLogs(t *testing.T) { }, { name: "missing run_id when using failed_only", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -1007,7 +955,7 @@ func Test_GetJobLogs(t *testing.T) { }, { name: "missing required parameter owner", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]any{ "repo": "repo", "job_id": float64(123), @@ -1017,7 +965,7 @@ func Test_GetJobLogs(t *testing.T) { }, { name: "missing required parameter repo", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]any{ "owner": "owner", "job_id": float64(123), @@ -1027,17 +975,14 @@ func Test_GetJobLogs(t *testing.T) { }, { name: "API error when getting single job logs", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposActionsJobsLogsByOwnerByRepoByJobId, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusNotFound) - _ = json.NewEncoder(w).Encode(map[string]string{ - "message": "Not Found", - }) - }), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposActionsJobsLogsByOwnerByRepoByJobId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusNotFound) + _ = json.NewEncoder(w).Encode(map[string]string{ + "message": "Not Found", + }) + }), + }), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -1047,17 +992,14 @@ func Test_GetJobLogs(t *testing.T) { }, { name: "API error when listing workflow jobs for failed_only", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposActionsRunsJobsByOwnerByRepoByRunId, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusNotFound) - _ = json.NewEncoder(w).Encode(map[string]string{ - "message": "Not Found", - }) - }), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposActionsRunsJobsByOwnerByRepoByRunId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusNotFound) + _ = json.NewEncoder(w).Encode(map[string]string{ + "message": "Not Found", + }) + }), + }), requestArgs: map[string]any{ "owner": "owner", "repo": "repo", @@ -1124,15 +1066,12 @@ func Test_GetJobLogs_WithContentReturn(t *testing.T) { })) defer testServer.Close() - mockedClient := mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposActionsJobsLogsByOwnerByRepoByJobId, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Location", testServer.URL) - w.WriteHeader(http.StatusFound) - }), - ), - ) + mockedClient := MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposActionsJobsLogsByOwnerByRepoByJobId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Location", testServer.URL) + w.WriteHeader(http.StatusFound) + }), + }) client := github.NewClient(mockedClient) toolDef := GetJobLogs(translations.NullTranslationHelper) @@ -1176,15 +1115,12 @@ func Test_GetJobLogs_WithContentReturnAndTailLines(t *testing.T) { })) defer testServer.Close() - mockedClient := mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposActionsJobsLogsByOwnerByRepoByJobId, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Location", testServer.URL) - w.WriteHeader(http.StatusFound) - }), - ), - ) + mockedClient := MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposActionsJobsLogsByOwnerByRepoByJobId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Location", testServer.URL) + w.WriteHeader(http.StatusFound) + }), + }) client := github.NewClient(mockedClient) toolDef := GetJobLogs(translations.NullTranslationHelper) @@ -1228,15 +1164,12 @@ func Test_GetJobLogs_WithContentReturnAndLargeTailLines(t *testing.T) { })) defer testServer.Close() - mockedClient := mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposActionsJobsLogsByOwnerByRepoByJobId, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Location", testServer.URL) - w.WriteHeader(http.StatusFound) - }), - ), - ) + mockedClient := MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposActionsJobsLogsByOwnerByRepoByJobId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Location", testServer.URL) + w.WriteHeader(http.StatusFound) + }), + }) client := github.NewClient(mockedClient) toolDef := GetJobLogs(translations.NullTranslationHelper) diff --git a/pkg/github/dependabot_test.go b/pkg/github/dependabot_test.go index 614c6f383..234b54deb 100644 --- a/pkg/github/dependabot_test.go +++ b/pkg/github/dependabot_test.go @@ -9,7 +9,6 @@ import ( "github.com/github/github-mcp-server/internal/toolsnaps" "github.com/github/github-mcp-server/pkg/translations" "github.com/google/go-github/v79/github" - "github.com/migueleliasweb/go-github-mock/src/mock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -42,12 +41,9 @@ func Test_GetDependabotAlert(t *testing.T) { }{ { name: "successful alert fetch", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.GetReposDependabotAlertsByOwnerByRepoByAlertNumber, - mockAlert, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposDependabotAlertsByOwnerByRepoByAlertNumber: mockResponse(t, http.StatusOK, mockAlert), + }), requestArgs: map[string]interface{}{ "owner": "owner", "repo": "repo", @@ -58,15 +54,12 @@ func Test_GetDependabotAlert(t *testing.T) { }, { name: "alert fetch fails", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposDependabotAlertsByOwnerByRepoByAlertNumber, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusNotFound) - _, _ = w.Write([]byte(`{"message": "Not Found"}`)) - }), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposDependabotAlertsByOwnerByRepoByAlertNumber: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusNotFound) + _, _ = w.Write([]byte(`{"message": "Not Found"}`)) + }), + }), requestArgs: map[string]interface{}{ "owner": "owner", "repo": "repo", @@ -154,16 +147,13 @@ func Test_ListDependabotAlerts(t *testing.T) { }{ { name: "successful open alerts listing", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposDependabotAlertsByOwnerByRepo, - expectQueryParams(t, map[string]string{ - "state": "open", - }).andThen( - mockResponse(t, http.StatusOK, []*github.DependabotAlert{&criticalAlert}), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposDependabotAlertsByOwnerByRepo: expectQueryParams(t, map[string]string{ + "state": "open", + }).andThen( + mockResponse(t, http.StatusOK, []*github.DependabotAlert{&criticalAlert}), ), - ), + }), requestArgs: map[string]interface{}{ "owner": "owner", "repo": "repo", @@ -174,16 +164,13 @@ func Test_ListDependabotAlerts(t *testing.T) { }, { name: "successful severity filtered listing", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposDependabotAlertsByOwnerByRepo, - expectQueryParams(t, map[string]string{ - "severity": "high", - }).andThen( - mockResponse(t, http.StatusOK, []*github.DependabotAlert{&highSeverityAlert}), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposDependabotAlertsByOwnerByRepo: expectQueryParams(t, map[string]string{ + "severity": "high", + }).andThen( + mockResponse(t, http.StatusOK, []*github.DependabotAlert{&highSeverityAlert}), ), - ), + }), requestArgs: map[string]interface{}{ "owner": "owner", "repo": "repo", @@ -194,14 +181,11 @@ func Test_ListDependabotAlerts(t *testing.T) { }, { name: "successful all alerts listing", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposDependabotAlertsByOwnerByRepo, - expectQueryParams(t, map[string]string{}).andThen( - mockResponse(t, http.StatusOK, []*github.DependabotAlert{&criticalAlert, &highSeverityAlert}), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposDependabotAlertsByOwnerByRepo: expectQueryParams(t, map[string]string{}).andThen( + mockResponse(t, http.StatusOK, []*github.DependabotAlert{&criticalAlert, &highSeverityAlert}), ), - ), + }), requestArgs: map[string]interface{}{ "owner": "owner", "repo": "repo", @@ -211,15 +195,12 @@ func Test_ListDependabotAlerts(t *testing.T) { }, { name: "alerts listing fails", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposDependabotAlertsByOwnerByRepo, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusUnauthorized) - _, _ = w.Write([]byte(`{"message": "Unauthorized access"}`)) - }), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposDependabotAlertsByOwnerByRepo: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusUnauthorized) + _, _ = w.Write([]byte(`{"message": "Unauthorized access"}`)) + }), + }), requestArgs: map[string]interface{}{ "owner": "owner", "repo": "repo", diff --git a/pkg/github/repositories_test.go b/pkg/github/repositories_test.go index c073cf22d..4e978a81a 100644 --- a/pkg/github/repositories_test.go +++ b/pkg/github/repositories_test.go @@ -95,7 +95,7 @@ func Test_GetFileContents(t *testing.T) { }), ), mock.WithRequestMatchHandler( - GetRawReposContentsByOwnerByRepoByBranchByPath, + raw.GetRawReposContentsByOwnerByRepoByBranchByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, _ = w.Write(mockRawContent) @@ -140,7 +140,7 @@ func Test_GetFileContents(t *testing.T) { }), ), mock.WithRequestMatchHandler( - GetRawReposContentsByOwnerByRepoByBranchByPath, + raw.GetRawReposContentsByOwnerByRepoByBranchByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "image/png") _, _ = w.Write(mockRawContent) @@ -185,7 +185,7 @@ func Test_GetFileContents(t *testing.T) { }), ), mock.WithRequestMatchHandler( - GetRawReposContentsByOwnerByRepoByBranchByPath, + raw.GetRawReposContentsByOwnerByRepoByBranchByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "application/pdf") _, _ = w.Write(mockRawContent) @@ -229,7 +229,7 @@ func Test_GetFileContents(t *testing.T) { ), ), mock.WithRequestMatchHandler( - GetRawReposContentsByOwnerByRepoByPath, + raw.GetRawReposContentsByOwnerByRepoByPath, expectQueryParams(t, map[string]string{ "branch": "main", }).andThen( @@ -263,7 +263,7 @@ func Test_GetFileContents(t *testing.T) { }), ), mock.WithRequestMatchHandler( - GetRawReposContentsByOwnerByRepoByPath, + raw.GetRawReposContentsByOwnerByRepoByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNotFound) _, _ = w.Write([]byte(`{"message": "Not Found"}`)) diff --git a/pkg/github/repository_resource_test.go b/pkg/github/repository_resource_test.go index 87d7ff2a1..99c06cdd6 100644 --- a/pkg/github/repository_resource_test.go +++ b/pkg/github/repository_resource_test.go @@ -36,7 +36,7 @@ func Test_repositoryResourceContents(t *testing.T) { name: "missing owner", mockedClient: mock.NewMockedHTTPClient( mock.WithRequestMatchHandler( - GetRawReposContentsByOwnerByRepoByPath, + raw.GetRawReposContentsByOwnerByRepoByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) @@ -55,7 +55,7 @@ func Test_repositoryResourceContents(t *testing.T) { name: "missing repo", mockedClient: mock.NewMockedHTTPClient( mock.WithRequestMatchHandler( - GetRawReposContentsByOwnerByRepoByBranchByPath, + raw.GetRawReposContentsByOwnerByRepoByBranchByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) @@ -74,7 +74,7 @@ func Test_repositoryResourceContents(t *testing.T) { name: "successful blob content fetch", mockedClient: mock.NewMockedHTTPClient( mock.WithRequestMatchHandler( - GetRawReposContentsByOwnerByRepoByPath, + raw.GetRawReposContentsByOwnerByRepoByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "image/png") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) @@ -98,7 +98,7 @@ func Test_repositoryResourceContents(t *testing.T) { name: "successful text content fetch (HEAD)", mockedClient: mock.NewMockedHTTPClient( mock.WithRequestMatchHandler( - GetRawReposContentsByOwnerByRepoByPath, + raw.GetRawReposContentsByOwnerByRepoByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) @@ -122,7 +122,7 @@ func Test_repositoryResourceContents(t *testing.T) { name: "successful text content fetch (HEAD)", mockedClient: mock.NewMockedHTTPClient( mock.WithRequestMatchHandler( - GetRawReposContentsByOwnerByRepoByPath, + raw.GetRawReposContentsByOwnerByRepoByPath, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain") @@ -148,7 +148,7 @@ func Test_repositoryResourceContents(t *testing.T) { name: "successful text content fetch (branch)", mockedClient: mock.NewMockedHTTPClient( mock.WithRequestMatchHandler( - GetRawReposContentsByOwnerByRepoByBranchByPath, + raw.GetRawReposContentsByOwnerByRepoByBranchByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) @@ -172,7 +172,7 @@ func Test_repositoryResourceContents(t *testing.T) { name: "successful text content fetch (tag)", mockedClient: mock.NewMockedHTTPClient( mock.WithRequestMatchHandler( - GetRawReposContentsByOwnerByRepoByTagByPath, + raw.GetRawReposContentsByOwnerByRepoByTagByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) @@ -196,7 +196,7 @@ func Test_repositoryResourceContents(t *testing.T) { name: "successful text content fetch (sha)", mockedClient: mock.NewMockedHTTPClient( mock.WithRequestMatchHandler( - GetRawReposContentsByOwnerByRepoBySHAByPath, + raw.GetRawReposContentsByOwnerByRepoBySHAByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) @@ -228,7 +228,7 @@ func Test_repositoryResourceContents(t *testing.T) { }), ), mock.WithRequestMatchHandler( - GetRawReposContentsByOwnerByRepoBySHAByPath, + raw.GetRawReposContentsByOwnerByRepoBySHAByPath, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) diff --git a/pkg/github/secret_scanning_test.go b/pkg/github/secret_scanning_test.go index b63617a46..89db56a87 100644 --- a/pkg/github/secret_scanning_test.go +++ b/pkg/github/secret_scanning_test.go @@ -10,7 +10,6 @@ import ( "github.com/github/github-mcp-server/pkg/translations" "github.com/google/go-github/v79/github" "github.com/google/jsonschema-go/jsonschema" - "github.com/migueleliasweb/go-github-mock/src/mock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -48,12 +47,9 @@ func Test_GetSecretScanningAlert(t *testing.T) { }{ { name: "successful alert fetch", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.GetReposSecretScanningAlertsByOwnerByRepoByAlertNumber, - mockAlert, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposSecretScanningAlertsByOwnerByRepoByAlertNumber: mockResponse(t, http.StatusOK, mockAlert), + }), requestArgs: map[string]interface{}{ "owner": "owner", "repo": "repo", @@ -64,15 +60,12 @@ func Test_GetSecretScanningAlert(t *testing.T) { }, { name: "alert fetch fails", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposSecretScanningAlertsByOwnerByRepoByAlertNumber, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusNotFound) - _, _ = w.Write([]byte(`{"message": "Not Found"}`)) - }), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposSecretScanningAlertsByOwnerByRepoByAlertNumber: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusNotFound) + _, _ = w.Write([]byte(`{"message": "Not Found"}`)) + }), + }), requestArgs: map[string]interface{}{ "owner": "owner", "repo": "repo", @@ -170,16 +163,13 @@ func Test_ListSecretScanningAlerts(t *testing.T) { }{ { name: "successful resolved alerts listing", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposSecretScanningAlertsByOwnerByRepo, - expectQueryParams(t, map[string]string{ - "state": "resolved", - }).andThen( - mockResponse(t, http.StatusOK, []*github.SecretScanningAlert{&resolvedAlert}), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposSecretScanningAlertsByOwnerByRepo: expectQueryParams(t, map[string]string{ + "state": "resolved", + }).andThen( + mockResponse(t, http.StatusOK, []*github.SecretScanningAlert{&resolvedAlert}), ), - ), + }), requestArgs: map[string]interface{}{ "owner": "owner", "repo": "repo", @@ -190,14 +180,11 @@ func Test_ListSecretScanningAlerts(t *testing.T) { }, { name: "successful alerts listing", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposSecretScanningAlertsByOwnerByRepo, - expectQueryParams(t, map[string]string{}).andThen( - mockResponse(t, http.StatusOK, []*github.SecretScanningAlert{&resolvedAlert, &openAlert}), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposSecretScanningAlertsByOwnerByRepo: expectQueryParams(t, map[string]string{}).andThen( + mockResponse(t, http.StatusOK, []*github.SecretScanningAlert{&resolvedAlert, &openAlert}), ), - ), + }), requestArgs: map[string]interface{}{ "owner": "owner", "repo": "repo", @@ -207,15 +194,12 @@ func Test_ListSecretScanningAlerts(t *testing.T) { }, { name: "alerts listing fails", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposSecretScanningAlertsByOwnerByRepo, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusUnauthorized) - _, _ = w.Write([]byte(`{"message": "Unauthorized access"}`)) - }), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposSecretScanningAlertsByOwnerByRepo: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusUnauthorized) + _, _ = w.Write([]byte(`{"message": "Unauthorized access"}`)) + }), + }), requestArgs: map[string]interface{}{ "owner": "owner", "repo": "repo", diff --git a/pkg/raw/raw_mock.go b/pkg/raw/raw_mock.go new file mode 100644 index 000000000..30c7759d3 --- /dev/null +++ b/pkg/raw/raw_mock.go @@ -0,0 +1,20 @@ +package raw + +import "github.com/migueleliasweb/go-github-mock/src/mock" + +var GetRawReposContentsByOwnerByRepoByPath mock.EndpointPattern = mock.EndpointPattern{ + Pattern: "/{owner}/{repo}/HEAD/{path:.*}", + Method: "GET", +} +var GetRawReposContentsByOwnerByRepoByBranchByPath mock.EndpointPattern = mock.EndpointPattern{ + Pattern: "/{owner}/{repo}/refs/heads/{branch}/{path:.*}", + Method: "GET", +} +var GetRawReposContentsByOwnerByRepoByTagByPath mock.EndpointPattern = mock.EndpointPattern{ + Pattern: "/{owner}/{repo}/refs/tags/{tag}/{path:.*}", + Method: "GET", +} +var GetRawReposContentsByOwnerByRepoBySHAByPath mock.EndpointPattern = mock.EndpointPattern{ + Pattern: "/{owner}/{repo}/{sha}/{path:.*}", + Method: "GET", +} From 3beeef94163a34c70ea63d2deaa9a124c6662073 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 09:35:13 +0000 Subject: [PATCH 05/13] Fix linting issues in helper constants Co-authored-by: JoannaaKL <67866556+JoannaaKL@users.noreply.github.com> --- pkg/github/actions_test.go | 30 +++--- pkg/github/helper_test.go | 142 ++++++++++++------------- pkg/github/security_advisories_test.go | 6 +- pkg/raw/raw_test.go | 50 ++++----- 4 files changed, 114 insertions(+), 114 deletions(-) diff --git a/pkg/github/actions_test.go b/pkg/github/actions_test.go index 8c00c9af5..9cf529c33 100644 --- a/pkg/github/actions_test.go +++ b/pkg/github/actions_test.go @@ -158,7 +158,7 @@ func Test_RunWorkflow(t *testing.T) { { name: "successful workflow run", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - PostReposActionsWorkflowsDispatchesByOwnerByRepoByWorkflowId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + PostReposActionsWorkflowsDispatchesByOwnerByRepoByWorkflowID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNoContent) }), }), @@ -233,7 +233,7 @@ func Test_RunWorkflow_WithFilename(t *testing.T) { { name: "successful workflow run by filename", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - PostReposActionsWorkflowsDispatchesByOwnerByRepoByWorkflowId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + PostReposActionsWorkflowsDispatchesByOwnerByRepoByWorkflowID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNoContent) }), }), @@ -248,7 +248,7 @@ func Test_RunWorkflow_WithFilename(t *testing.T) { { name: "successful workflow run by numeric ID as string", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - PostReposActionsWorkflowsDispatchesByOwnerByRepoByWorkflowId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + PostReposActionsWorkflowsDispatchesByOwnerByRepoByWorkflowID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNoContent) }), }), @@ -429,7 +429,7 @@ func Test_ListWorkflowRunArtifacts(t *testing.T) { { name: "successful artifacts listing", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetReposActionsRunsArtifactsByOwnerByRepoByRunId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + GetReposActionsRunsArtifactsByOwnerByRepoByRunID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { artifacts := &github.ArtifactList{ TotalCount: github.Ptr(int64(2)), Artifacts: []*github.Artifact{ @@ -640,7 +640,7 @@ func Test_DeleteWorkflowRunLogs(t *testing.T) { { name: "successful logs deletion", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - DeleteReposActionsRunsLogsByOwnerByRepoByRunId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + DeleteReposActionsRunsLogsByOwnerByRepoByRunID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNoContent) }), }), @@ -721,7 +721,7 @@ func Test_GetWorkflowRunUsage(t *testing.T) { { name: "successful workflow run usage", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetReposActionsRunsTimingByOwnerByRepoByRunId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + GetReposActionsRunsTimingByOwnerByRepoByRunID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { usage := &github.WorkflowRunUsage{ Billable: &github.WorkflowRunBillMap{ "UBUNTU": &github.WorkflowRunBill{ @@ -826,7 +826,7 @@ func Test_GetJobLogs(t *testing.T) { { name: "successful single job logs with URL", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetReposActionsJobsLogsByOwnerByRepoByJobId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + GetReposActionsJobsLogsByOwnerByRepoByJobID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Location", "https://github.com/logs/job/123") w.WriteHeader(http.StatusFound) }), @@ -847,7 +847,7 @@ func Test_GetJobLogs(t *testing.T) { { name: "successful failed jobs logs", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetReposActionsRunsJobsByOwnerByRepoByRunId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + GetReposActionsRunsJobsByOwnerByRepoByRunID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { jobs := &github.Jobs{ TotalCount: github.Ptr(3), Jobs: []*github.WorkflowJob{ @@ -871,7 +871,7 @@ func Test_GetJobLogs(t *testing.T) { w.WriteHeader(http.StatusOK) _ = json.NewEncoder(w).Encode(jobs) }), - GetReposActionsJobsLogsByOwnerByRepoByJobId: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + GetReposActionsJobsLogsByOwnerByRepoByJobID: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Location", "https://github.com/logs/job/"+r.URL.Path[len(r.URL.Path)-1:]) w.WriteHeader(http.StatusFound) }), @@ -898,7 +898,7 @@ func Test_GetJobLogs(t *testing.T) { { name: "no failed jobs found", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetReposActionsRunsJobsByOwnerByRepoByRunId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + GetReposActionsRunsJobsByOwnerByRepoByRunID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { jobs := &github.Jobs{ TotalCount: github.Ptr(2), Jobs: []*github.WorkflowJob{ @@ -976,7 +976,7 @@ func Test_GetJobLogs(t *testing.T) { { name: "API error when getting single job logs", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetReposActionsJobsLogsByOwnerByRepoByJobId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + GetReposActionsJobsLogsByOwnerByRepoByJobID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNotFound) _ = json.NewEncoder(w).Encode(map[string]string{ "message": "Not Found", @@ -993,7 +993,7 @@ func Test_GetJobLogs(t *testing.T) { { name: "API error when listing workflow jobs for failed_only", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetReposActionsRunsJobsByOwnerByRepoByRunId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + GetReposActionsRunsJobsByOwnerByRepoByRunID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNotFound) _ = json.NewEncoder(w).Encode(map[string]string{ "message": "Not Found", @@ -1067,7 +1067,7 @@ func Test_GetJobLogs_WithContentReturn(t *testing.T) { defer testServer.Close() mockedClient := MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetReposActionsJobsLogsByOwnerByRepoByJobId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + GetReposActionsJobsLogsByOwnerByRepoByJobID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Location", testServer.URL) w.WriteHeader(http.StatusFound) }), @@ -1116,7 +1116,7 @@ func Test_GetJobLogs_WithContentReturnAndTailLines(t *testing.T) { defer testServer.Close() mockedClient := MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetReposActionsJobsLogsByOwnerByRepoByJobId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + GetReposActionsJobsLogsByOwnerByRepoByJobID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Location", testServer.URL) w.WriteHeader(http.StatusFound) }), @@ -1165,7 +1165,7 @@ func Test_GetJobLogs_WithContentReturnAndLargeTailLines(t *testing.T) { defer testServer.Close() mockedClient := MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetReposActionsJobsLogsByOwnerByRepoByJobId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + GetReposActionsJobsLogsByOwnerByRepoByJobID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Location", testServer.URL) w.WriteHeader(http.StatusFound) }), diff --git a/pkg/github/helper_test.go b/pkg/github/helper_test.go index cfbbc91f0..aa0e11c11 100644 --- a/pkg/github/helper_test.go +++ b/pkg/github/helper_test.go @@ -19,89 +19,89 @@ import ( // These constants define the URL patterns used in HTTP mocking for tests const ( // User endpoints - GetUser = "GET /user" - GetUserStarred = "GET /user/starred" - GetUsersGistsByUsername = "GET /users/{username}/gists" - GetUsersStarredByUsername = "GET /users/{username}/starred" - PutUserStarredByOwnerByRepo = "PUT /user/starred/{owner}/{repo}" - DeleteUserStarredByOwnerByRepo = "DELETE /user/starred/{owner}/{repo}" + GetUser = "GET /user" + GetUserStarred = "GET /user/starred" + GetUsersGistsByUsername = "GET /users/{username}/gists" + GetUsersStarredByUsername = "GET /users/{username}/starred" + PutUserStarredByOwnerByRepo = "PUT /user/starred/{owner}/{repo}" + DeleteUserStarredByOwnerByRepo = "DELETE /user/starred/{owner}/{repo}" // Repository endpoints - GetReposByOwnerByRepo = "GET /repos/{owner}/{repo}" - GetReposBranchesByOwnerByRepo = "GET /repos/{owner}/{repo}/branches" - GetReposTagsByOwnerByRepo = "GET /repos/{owner}/{repo}/tags" - GetReposCommitsByOwnerByRepo = "GET /repos/{owner}/{repo}/commits" - GetReposCommitsByOwnerByRepoByRef = "GET /repos/{owner}/{repo}/commits/{ref}" - GetReposContentsByOwnerByRepoByPath = "GET /repos/{owner}/{repo}/contents/{path}" - PutReposContentsByOwnerByRepoByPath = "PUT /repos/{owner}/{repo}/contents/{path}" - PostReposForksByOwnerByRepo = "POST /repos/{owner}/{repo}/forks" - GetReposSubscriptionByOwnerByRepo = "GET /repos/{owner}/{repo}/subscription" - PutReposSubscriptionByOwnerByRepo = "PUT /repos/{owner}/{repo}/subscription" + GetReposByOwnerByRepo = "GET /repos/{owner}/{repo}" + GetReposBranchesByOwnerByRepo = "GET /repos/{owner}/{repo}/branches" + GetReposTagsByOwnerByRepo = "GET /repos/{owner}/{repo}/tags" + GetReposCommitsByOwnerByRepo = "GET /repos/{owner}/{repo}/commits" + GetReposCommitsByOwnerByRepoByRef = "GET /repos/{owner}/{repo}/commits/{ref}" + GetReposContentsByOwnerByRepoByPath = "GET /repos/{owner}/{repo}/contents/{path}" + PutReposContentsByOwnerByRepoByPath = "PUT /repos/{owner}/{repo}/contents/{path}" + PostReposForksByOwnerByRepo = "POST /repos/{owner}/{repo}/forks" + GetReposSubscriptionByOwnerByRepo = "GET /repos/{owner}/{repo}/subscription" + PutReposSubscriptionByOwnerByRepo = "PUT /repos/{owner}/{repo}/subscription" DeleteReposSubscriptionByOwnerByRepo = "DELETE /repos/{owner}/{repo}/subscription" // Git endpoints - GetReposGitTreesByOwnerByRepoByTree = "GET /repos/{owner}/{repo}/git/trees/{tree}" - GetReposGitRefByOwnerByRepoByRef = "GET /repos/{owner}/{repo}/git/ref/{ref}" - PostReposGitRefsByOwnerByRepo = "POST /repos/{owner}/{repo}/git/refs" - PatchReposGitRefsByOwnerByRepoByRef = "PATCH /repos/{owner}/{repo}/git/refs/{ref}" + GetReposGitTreesByOwnerByRepoByTree = "GET /repos/{owner}/{repo}/git/trees/{tree}" + GetReposGitRefByOwnerByRepoByRef = "GET /repos/{owner}/{repo}/git/ref/{ref}" + PostReposGitRefsByOwnerByRepo = "POST /repos/{owner}/{repo}/git/refs" + PatchReposGitRefsByOwnerByRepoByRef = "PATCH /repos/{owner}/{repo}/git/refs/{ref}" GetReposGitCommitsByOwnerByRepoByCommitSha = "GET /repos/{owner}/{repo}/git/commits/{commit_sha}" - PostReposGitCommitsByOwnerByRepo = "POST /repos/{owner}/{repo}/git/commits" - GetReposGitTagsByOwnerByRepoByTagSha = "GET /repos/{owner}/{repo}/git/tags/{tag_sha}" - PostReposGitTreesByOwnerByRepo = "POST /repos/{owner}/{repo}/git/trees" - GetReposCommitsStatusByOwnerByRepoByRef = "GET /repos/{owner}/{repo}/commits/{ref}/status" - GetReposCommitsStatusesByOwnerByRepoByRef = "GET /repos/{owner}/{repo}/commits/{ref}/statuses" + PostReposGitCommitsByOwnerByRepo = "POST /repos/{owner}/{repo}/git/commits" + GetReposGitTagsByOwnerByRepoByTagSha = "GET /repos/{owner}/{repo}/git/tags/{tag_sha}" + PostReposGitTreesByOwnerByRepo = "POST /repos/{owner}/{repo}/git/trees" + GetReposCommitsStatusByOwnerByRepoByRef = "GET /repos/{owner}/{repo}/commits/{ref}/status" + GetReposCommitsStatusesByOwnerByRepoByRef = "GET /repos/{owner}/{repo}/commits/{ref}/statuses" // Issues endpoints - GetReposIssuesByOwnerByRepoByIssueNumber = "GET /repos/{owner}/{repo}/issues/{issue_number}" - GetReposIssuesCommentsByOwnerByRepoByIssueNumber = "GET /repos/{owner}/{repo}/issues/{issue_number}/comments" - PostReposIssuesByOwnerByRepo = "POST /repos/{owner}/{repo}/issues" - PostReposIssuesCommentsByOwnerByRepoByIssueNumber = "POST /repos/{owner}/{repo}/issues/{issue_number}/comments" - PatchReposIssuesByOwnerByRepoByIssueNumber = "PATCH /repos/{owner}/{repo}/issues/{issue_number}" - GetReposIssuesSubIssuesByOwnerByRepoByIssueNumber = "GET /repos/{owner}/{repo}/issues/{issue_number}/sub_issues" - PostReposIssuesSubIssuesByOwnerByRepoByIssueNumber = "POST /repos/{owner}/{repo}/issues/{issue_number}/sub_issues" - DeleteReposIssuesSubIssueByOwnerByRepoByIssueNumber = "DELETE /repos/{owner}/{repo}/issues/{issue_number}/sub_issues" + GetReposIssuesByOwnerByRepoByIssueNumber = "GET /repos/{owner}/{repo}/issues/{issue_number}" + GetReposIssuesCommentsByOwnerByRepoByIssueNumber = "GET /repos/{owner}/{repo}/issues/{issue_number}/comments" + PostReposIssuesByOwnerByRepo = "POST /repos/{owner}/{repo}/issues" + PostReposIssuesCommentsByOwnerByRepoByIssueNumber = "POST /repos/{owner}/{repo}/issues/{issue_number}/comments" + PatchReposIssuesByOwnerByRepoByIssueNumber = "PATCH /repos/{owner}/{repo}/issues/{issue_number}" + GetReposIssuesSubIssuesByOwnerByRepoByIssueNumber = "GET /repos/{owner}/{repo}/issues/{issue_number}/sub_issues" + PostReposIssuesSubIssuesByOwnerByRepoByIssueNumber = "POST /repos/{owner}/{repo}/issues/{issue_number}/sub_issues" + DeleteReposIssuesSubIssueByOwnerByRepoByIssueNumber = "DELETE /repos/{owner}/{repo}/issues/{issue_number}/sub_issues" PatchReposIssuesSubIssuesPriorityByOwnerByRepoByIssueNumber = "PATCH /repos/{owner}/{repo}/issues/{issue_number}/sub_issues/priority" // Pull request endpoints - GetReposPullsByOwnerByRepo = "GET /repos/{owner}/{repo}/pulls" - GetReposPullsByOwnerByRepoByPullNumber = "GET /repos/{owner}/{repo}/pulls/{pull_number}" - GetReposPullsFilesByOwnerByRepoByPullNumber = "GET /repos/{owner}/{repo}/pulls/{pull_number}/files" - GetReposPullsReviewsByOwnerByRepoByPullNumber = "GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews" - PostReposPullsByOwnerByRepo = "POST /repos/{owner}/{repo}/pulls" - PatchReposPullsByOwnerByRepoByPullNumber = "PATCH /repos/{owner}/{repo}/pulls/{pull_number}" - PutReposPullsMergeByOwnerByRepoByPullNumber = "PUT /repos/{owner}/{repo}/pulls/{pull_number}/merge" - PutReposPullsUpdateBranchByOwnerByRepoByPullNumber = "PUT /repos/{owner}/{repo}/pulls/{pull_number}/update-branch" + GetReposPullsByOwnerByRepo = "GET /repos/{owner}/{repo}/pulls" + GetReposPullsByOwnerByRepoByPullNumber = "GET /repos/{owner}/{repo}/pulls/{pull_number}" + GetReposPullsFilesByOwnerByRepoByPullNumber = "GET /repos/{owner}/{repo}/pulls/{pull_number}/files" + GetReposPullsReviewsByOwnerByRepoByPullNumber = "GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews" + PostReposPullsByOwnerByRepo = "POST /repos/{owner}/{repo}/pulls" + PatchReposPullsByOwnerByRepoByPullNumber = "PATCH /repos/{owner}/{repo}/pulls/{pull_number}" + PutReposPullsMergeByOwnerByRepoByPullNumber = "PUT /repos/{owner}/{repo}/pulls/{pull_number}/merge" + PutReposPullsUpdateBranchByOwnerByRepoByPullNumber = "PUT /repos/{owner}/{repo}/pulls/{pull_number}/update-branch" PostReposPullsRequestedReviewersByOwnerByRepoByPullNumber = "POST /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers" // Notifications endpoints - GetNotifications = "GET /notifications" - PutNotifications = "PUT /notifications" - GetReposNotificationsByOwnerByRepo = "GET /repos/{owner}/{repo}/notifications" - PutReposNotificationsByOwnerByRepo = "PUT /repos/{owner}/{repo}/notifications" - GetNotificationsThreadsByThreadId = "GET /notifications/threads/{thread_id}" - PatchNotificationsThreadsByThreadId = "PATCH /notifications/threads/{thread_id}" - DeleteNotificationsThreadsByThreadId = "DELETE /notifications/threads/{thread_id}" - PutNotificationsThreadsSubscriptionByThreadId = "PUT /notifications/threads/{thread_id}/subscription" - DeleteNotificationsThreadsSubscriptionByThreadId = "DELETE /notifications/threads/{thread_id}/subscription" + GetNotifications = "GET /notifications" + PutNotifications = "PUT /notifications" + GetReposNotificationsByOwnerByRepo = "GET /repos/{owner}/{repo}/notifications" + PutReposNotificationsByOwnerByRepo = "PUT /repos/{owner}/{repo}/notifications" + GetNotificationsThreadsByThreadID = "GET /notifications/threads/{thread_id}" + PatchNotificationsThreadsByThreadID = "PATCH /notifications/threads/{thread_id}" + DeleteNotificationsThreadsByThreadID = "DELETE /notifications/threads/{thread_id}" + PutNotificationsThreadsSubscriptionByThreadID = "PUT /notifications/threads/{thread_id}/subscription" + DeleteNotificationsThreadsSubscriptionByThreadID = "DELETE /notifications/threads/{thread_id}/subscription" // Gists endpoints - GetGists = "GET /gists" - GetGistsByGistId = "GET /gists/{gist_id}" - PostGists = "POST /gists" - PatchGistsByGistId = "PATCH /gists/{gist_id}" + GetGists = "GET /gists" + GetGistsByGistID = "GET /gists/{gist_id}" + PostGists = "POST /gists" + PatchGistsByGistID = "PATCH /gists/{gist_id}" // Releases endpoints - GetReposReleasesByOwnerByRepo = "GET /repos/{owner}/{repo}/releases" - GetReposReleasesLatestByOwnerByRepo = "GET /repos/{owner}/{repo}/releases/latest" - GetReposReleasesTagsByOwnerByRepoByTag = "GET /repos/{owner}/{repo}/releases/tags/{tag}" + GetReposReleasesByOwnerByRepo = "GET /repos/{owner}/{repo}/releases" + GetReposReleasesLatestByOwnerByRepo = "GET /repos/{owner}/{repo}/releases/latest" + GetReposReleasesTagsByOwnerByRepoByTag = "GET /repos/{owner}/{repo}/releases/tags/{tag}" // Code scanning endpoints GetReposCodeScanningAlertsByOwnerByRepo = "GET /repos/{owner}/{repo}/code-scanning/alerts" GetReposCodeScanningAlertsByOwnerByRepoByAlertNumber = "GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}" // Secret scanning endpoints - GetReposSecretScanningAlertsByOwnerByRepo = "GET /repos/{owner}/{repo}/secret-scanning/alerts" - GetReposSecretScanningAlertsByOwnerByRepoByAlertNumber = "GET /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}" + GetReposSecretScanningAlertsByOwnerByRepo = "GET /repos/{owner}/{repo}/secret-scanning/alerts" //nolint:gosec // False positive - this is an API endpoint pattern, not a credential + GetReposSecretScanningAlertsByOwnerByRepoByAlertNumber = "GET /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}" //nolint:gosec // False positive - this is an API endpoint pattern, not a credential // Dependabot endpoints GetReposDependabotAlertsByOwnerByRepo = "GET /repos/{owner}/{repo}/dependabot/alerts" @@ -109,18 +109,18 @@ const ( // Security advisories endpoints GetAdvisories = "GET /advisories" - GetAdvisoriesByGhsaId = "GET /advisories/{ghsa_id}" + GetAdvisoriesByGhsaID = "GET /advisories/{ghsa_id}" GetReposSecurityAdvisoriesByOwnerByRepo = "GET /repos/{owner}/{repo}/security-advisories" GetOrgsSecurityAdvisoriesByOrg = "GET /orgs/{org}/security-advisories" // Actions endpoints - GetReposActionsWorkflowsByOwnerByRepo = "GET /repos/{owner}/{repo}/actions/workflows" - PostReposActionsWorkflowsDispatchesByOwnerByRepoByWorkflowId = "POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches" - GetReposActionsRunsJobsByOwnerByRepoByRunId = "GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs" - GetReposActionsRunsArtifactsByOwnerByRepoByRunId = "GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts" - GetReposActionsRunsTimingByOwnerByRepoByRunId = "GET /repos/{owner}/{repo}/actions/runs/{run_id}/timing" - GetReposActionsJobsLogsByOwnerByRepoByJobId = "GET /repos/{owner}/{repo}/actions/jobs/{job_id}/logs" - DeleteReposActionsRunsLogsByOwnerByRepoByRunId = "DELETE /repos/{owner}/{repo}/actions/runs/{run_id}/logs" + GetReposActionsWorkflowsByOwnerByRepo = "GET /repos/{owner}/{repo}/actions/workflows" + PostReposActionsWorkflowsDispatchesByOwnerByRepoByWorkflowID = "POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches" + GetReposActionsRunsJobsByOwnerByRepoByRunID = "GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs" + GetReposActionsRunsArtifactsByOwnerByRepoByRunID = "GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts" + GetReposActionsRunsTimingByOwnerByRepoByRunID = "GET /repos/{owner}/{repo}/actions/runs/{run_id}/timing" + GetReposActionsJobsLogsByOwnerByRepoByJobID = "GET /repos/{owner}/{repo}/actions/jobs/{job_id}/logs" + DeleteReposActionsRunsLogsByOwnerByRepoByRunID = "DELETE /repos/{owner}/{repo}/actions/runs/{run_id}/logs" // Search endpoints GetSearchCode = "GET /search/code" @@ -130,10 +130,10 @@ const ( // Raw content endpoints (used for GitHub raw content API, not standard API) // These are used with the raw content client that interacts with raw.githubusercontent.com - GetRawReposContentsByOwnerByRepoByPath = "GET /{owner}/{repo}/HEAD/{path}" - GetRawReposContentsByOwnerByRepoByBranchByPath = "GET /{owner}/{repo}/refs/heads/{branch}/{path}" - GetRawReposContentsByOwnerByRepoByTagByPath = "GET /{owner}/{repo}/refs/tags/{tag}/{path}" - GetRawReposContentsByOwnerByRepoBySHAByPath = "GET /{owner}/{repo}/{sha}/{path}" + GetRawReposContentsByOwnerByRepoByPath = "GET /{owner}/{repo}/HEAD/{path}" + GetRawReposContentsByOwnerByRepoByBranchByPath = "GET /{owner}/{repo}/refs/heads/{branch}/{path}" + GetRawReposContentsByOwnerByRepoByTagByPath = "GET /{owner}/{repo}/refs/tags/{tag}/{path}" + GetRawReposContentsByOwnerByRepoBySHAByPath = "GET /{owner}/{repo}/{sha}/{path}" ) type expectations struct { diff --git a/pkg/github/security_advisories_test.go b/pkg/github/security_advisories_test.go index 1bd8c12f8..c19e43f27 100644 --- a/pkg/github/security_advisories_test.go +++ b/pkg/github/security_advisories_test.go @@ -163,7 +163,7 @@ func Test_GetGlobalSecurityAdvisory(t *testing.T) { { name: "successful advisory fetch", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetAdvisoriesByGhsaId: mockResponse(t, http.StatusOK, mockAdvisory), + GetAdvisoriesByGhsaID: mockResponse(t, http.StatusOK, mockAdvisory), }), requestArgs: map[string]interface{}{ "ghsaId": "GHSA-xxxx-xxxx-xxxx", @@ -174,7 +174,7 @@ func Test_GetGlobalSecurityAdvisory(t *testing.T) { { name: "invalid ghsaId format", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetAdvisoriesByGhsaId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + GetAdvisoriesByGhsaID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusBadRequest) _, _ = w.Write([]byte(`{"message": "Bad Request"}`)) }), @@ -188,7 +188,7 @@ func Test_GetGlobalSecurityAdvisory(t *testing.T) { { name: "advisory not found", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetAdvisoriesByGhsaId: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + GetAdvisoriesByGhsaID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNotFound) _, _ = w.Write([]byte(`{"message": "Not Found"}`)) }), diff --git a/pkg/raw/raw_test.go b/pkg/raw/raw_test.go index 41c65d13b..4c4aa33b4 100644 --- a/pkg/raw/raw_test.go +++ b/pkg/raw/raw_test.go @@ -47,51 +47,51 @@ func TestGetRawContent(t *testing.T) { expectError string }{ { - name: "HEAD fetch success", - opts: nil, - owner: "octocat", - repo: "hello", - path: "README.md", + name: "HEAD fetch success", + opts: nil, + owner: "octocat", + repo: "hello", + path: "README.md", statusCode: 200, contentType: "text/plain", body: "# Test file", }, { - name: "branch fetch success", - opts: &ContentOpts{Ref: "refs/heads/main"}, - owner: "octocat", - repo: "hello", - path: "README.md", + name: "branch fetch success", + opts: &ContentOpts{Ref: "refs/heads/main"}, + owner: "octocat", + repo: "hello", + path: "README.md", statusCode: 200, contentType: "text/plain", body: "# Test file", }, { - name: "tag fetch success", - opts: &ContentOpts{Ref: "refs/tags/v1.0.0"}, - owner: "octocat", - repo: "hello", - path: "README.md", + name: "tag fetch success", + opts: &ContentOpts{Ref: "refs/tags/v1.0.0"}, + owner: "octocat", + repo: "hello", + path: "README.md", statusCode: 200, contentType: "text/plain", body: "# Test file", }, { - name: "sha fetch success", - opts: &ContentOpts{SHA: "abc123"}, - owner: "octocat", - repo: "hello", - path: "README.md", + name: "sha fetch success", + opts: &ContentOpts{SHA: "abc123"}, + owner: "octocat", + repo: "hello", + path: "README.md", statusCode: 200, contentType: "text/plain", body: "# Test file", }, { - name: "not found", - opts: nil, - owner: "octocat", - repo: "hello", - path: "notfound.txt", + name: "not found", + opts: nil, + owner: "octocat", + repo: "hello", + path: "notfound.txt", statusCode: 404, contentType: "application/json", body: `{"message": "Not Found"}`, From acf0be5b67e43949503e8e264c09d7075000abb2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 09:52:18 +0000 Subject: [PATCH 06/13] Migrate context_tools_test and repository_resource_test to testify Co-authored-by: JoannaaKL <67866556+JoannaaKL@users.noreply.github.com> --- pkg/github/context_tools_test.go | 46 ++++------ pkg/github/repository_resource_test.go | 116 ++++++++++--------------- 2 files changed, 60 insertions(+), 102 deletions(-) diff --git a/pkg/github/context_tools_test.go b/pkg/github/context_tools_test.go index e9faefc40..0ee55d098 100644 --- a/pkg/github/context_tools_test.go +++ b/pkg/github/context_tools_test.go @@ -11,7 +11,6 @@ import ( "github.com/github/github-mcp-server/internal/toolsnaps" "github.com/github/github-mcp-server/pkg/translations" "github.com/google/go-github/v79/github" - "github.com/migueleliasweb/go-github-mock/src/mock" "github.com/shurcooL/githubv4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -57,24 +56,18 @@ func Test_GetMe(t *testing.T) { }{ { name: "successful get user", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.GetUser, - mockUser, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetUser: mockResponse(t, http.StatusOK, mockUser), + }), requestArgs: map[string]any{}, expectToolError: false, expectedUser: mockUser, }, { name: "successful get user with reason", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.GetUser, - mockUser, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetUser: mockResponse(t, http.StatusOK, mockUser), + }), requestArgs: map[string]any{ "reason": "Testing API", }, @@ -90,12 +83,9 @@ func Test_GetMe(t *testing.T) { }, { name: "get user fails", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetUser, - badRequestHandler("expected test failure"), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetUser: badRequestHandler("expected test failure"), + }), requestArgs: map[string]any{}, expectToolError: true, expectedToolErrMsg: "expected test failure", @@ -255,21 +245,15 @@ func Test_GetTeams(t *testing.T) { // Factory function for mock HTTP clients with user response httpClientWithUser := func() *http.Client { - return mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.GetUser, - mockUser, - ), - ) + return MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetUser: mockResponse(t, http.StatusOK, mockUser), + }) } httpClientUserFails := func() *http.Client { - return mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetUser, - badRequestHandler("expected test failure"), - ), - ) + return MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetUser: badRequestHandler("expected test failure"), + }) } tests := []struct { diff --git a/pkg/github/repository_resource_test.go b/pkg/github/repository_resource_test.go index 99c06cdd6..adabaad2c 100644 --- a/pkg/github/repository_resource_test.go +++ b/pkg/github/repository_resource_test.go @@ -8,7 +8,6 @@ import ( "github.com/github/github-mcp-server/pkg/raw" "github.com/google/go-github/v79/github" - "github.com/migueleliasweb/go-github-mock/src/mock" "github.com/modelcontextprotocol/go-sdk/mcp" "github.com/stretchr/testify/require" ) @@ -34,16 +33,14 @@ func Test_repositoryResourceContents(t *testing.T) { }{ { name: "missing owner", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoByPath, + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetRawReposContentsByOwnerByRepoByPath: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) require.NoError(t, err) }), - ), - ), + }), uri: "repo:///repo/contents/README.md", handlerFn: func(deps ToolDependencies) mcp.ResourceHandler { return RepositoryResourceContentsHandler(deps, repositoryResourceContentURITemplate) @@ -53,16 +50,14 @@ func Test_repositoryResourceContents(t *testing.T) { }, { name: "missing repo", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoByBranchByPath, + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetRawReposContentsByOwnerByRepoByBranchByPath: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) require.NoError(t, err) }), - ), - ), + }), uri: "repo://owner//refs/heads/main/contents/README.md", handlerFn: func(deps ToolDependencies) mcp.ResourceHandler { return RepositoryResourceContentsHandler(deps, repositoryResourceBranchContentURITemplate) @@ -72,16 +67,14 @@ func Test_repositoryResourceContents(t *testing.T) { }, { name: "successful blob content fetch", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoByPath, + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetRawReposContentsByOwnerByRepoByPath: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "image/png") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) require.NoError(t, err) }), - ), - ), + }), uri: "repo://owner/repo/contents/data.png", handlerFn: func(deps ToolDependencies) mcp.ResourceHandler { return RepositoryResourceContentsHandler(deps, repositoryResourceContentURITemplate) @@ -96,16 +89,14 @@ func Test_repositoryResourceContents(t *testing.T) { }, { name: "successful text content fetch (HEAD)", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoByPath, + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetRawReposContentsByOwnerByRepoByPath: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) require.NoError(t, err) }), - ), - ), + }), uri: "repo://owner/repo/contents/README.md", handlerFn: func(deps ToolDependencies) mcp.ResourceHandler { return RepositoryResourceContentsHandler(deps, repositoryResourceContentURITemplate) @@ -120,9 +111,8 @@ func Test_repositoryResourceContents(t *testing.T) { }, { name: "successful text content fetch (HEAD)", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoByPath, + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetRawReposContentsByOwnerByRepoByPath: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain") @@ -130,8 +120,7 @@ func Test_repositoryResourceContents(t *testing.T) { _, err := w.Write([]byte("package actions\n\nfunc main() {\n // Sample Go file content\n}\n")) require.NoError(t, err) }), - ), - ), + }), uri: "repo://owner/repo/contents/pkg/github/actions.go", handlerFn: func(deps ToolDependencies) mcp.ResourceHandler { return RepositoryResourceContentsHandler(deps, repositoryResourceContentURITemplate) @@ -146,16 +135,14 @@ func Test_repositoryResourceContents(t *testing.T) { }, { name: "successful text content fetch (branch)", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoByBranchByPath, + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetRawReposContentsByOwnerByRepoByBranchByPath: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) require.NoError(t, err) }), - ), - ), + }), uri: "repo://owner/repo/refs/heads/main/contents/README.md", handlerFn: func(deps ToolDependencies) mcp.ResourceHandler { return RepositoryResourceContentsHandler(deps, repositoryResourceBranchContentURITemplate) @@ -170,16 +157,14 @@ func Test_repositoryResourceContents(t *testing.T) { }, { name: "successful text content fetch (tag)", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoByTagByPath, + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetRawReposContentsByOwnerByRepoByTagByPath: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) require.NoError(t, err) }), - ), - ), + }), uri: "repo://owner/repo/refs/tags/v1.0.0/contents/README.md", handlerFn: func(deps ToolDependencies) mcp.ResourceHandler { return RepositoryResourceContentsHandler(deps, repositoryResourceTagContentURITemplate) @@ -194,16 +179,14 @@ func Test_repositoryResourceContents(t *testing.T) { }, { name: "successful text content fetch (sha)", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoBySHAByPath, + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetRawReposContentsByOwnerByRepoBySHAByPath: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/markdown") _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) require.NoError(t, err) }), - ), - ), + }), uri: "repo://owner/repo/sha/abc123/contents/README.md", handlerFn: func(deps ToolDependencies) mcp.ResourceHandler { return RepositoryResourceContentsHandler(deps, repositoryResourceCommitContentURITemplate) @@ -218,24 +201,18 @@ func Test_repositoryResourceContents(t *testing.T) { }, { name: "successful text content fetch (pr)", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposPullsByOwnerByRepoByPullNumber, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "application/json") - _, err := w.Write([]byte(`{"head": {"sha": "abc123"}}`)) - require.NoError(t, err) - }), - ), - mock.WithRequestMatchHandler( - raw.GetRawReposContentsByOwnerByRepoBySHAByPath, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "text/markdown") - _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) - require.NoError(t, err) - }), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposPullsByOwnerByRepoByPullNumber: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + _, err := w.Write([]byte(`{"head": {"sha": "abc123"}}`)) + require.NoError(t, err) + }), + GetRawReposContentsByOwnerByRepoBySHAByPath: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "text/markdown") + _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) + require.NoError(t, err) + }), + }), uri: "repo://owner/repo/refs/pull/42/head/contents/README.md", handlerFn: func(deps ToolDependencies) mcp.ResourceHandler { return RepositoryResourceContentsHandler(deps, repositoryResourcePrContentURITemplate) @@ -250,15 +227,12 @@ func Test_repositoryResourceContents(t *testing.T) { }, { name: "content fetch fails", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetReposContentsByOwnerByRepoByPath, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusNotFound) - _, _ = w.Write([]byte(`{"message": "Not Found"}`)) - }), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposContentsByOwnerByRepoByPath: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusNotFound) + _, _ = w.Write([]byte(`{"message": "Not Found"}`)) + }), + }), uri: "repo://owner/repo/contents/nonexistent.md", handlerFn: func(deps ToolDependencies) mcp.ResourceHandler { return RepositoryResourceContentsHandler(deps, repositoryResourceContentURITemplate) @@ -295,11 +269,11 @@ func Test_repositoryResourceContents(t *testing.T) { content := resp.Contents[0] switch tc.expectedResponseType { - case resourceResponseTypeBlob: + case resourceResponseTypeBlob: require.Equal(t, tc.expectedResult.Contents[0].Blob, content.Blob) - case resourceResponseTypeText: + case resourceResponseTypeText: require.Equal(t, tc.expectedResult.Contents[0].Text, content.Text) - default: + default: t.Fatalf("unknown expectedResponseType %v", tc.expectedResponseType) } }) From 6d01033a31e5e1eeb96d8fea721c0635a8ed1637 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 09:58:05 +0000 Subject: [PATCH 07/13] Fix wildcard path matching for raw content endpoints Co-authored-by: JoannaaKL <67866556+JoannaaKL@users.noreply.github.com> --- pkg/github/helper_test.go | 8 +-- pkg/github/repository_resource_test.go | 96 ++++++++++++-------------- 2 files changed, 48 insertions(+), 56 deletions(-) diff --git a/pkg/github/helper_test.go b/pkg/github/helper_test.go index aa0e11c11..4da03dabe 100644 --- a/pkg/github/helper_test.go +++ b/pkg/github/helper_test.go @@ -130,10 +130,10 @@ const ( // Raw content endpoints (used for GitHub raw content API, not standard API) // These are used with the raw content client that interacts with raw.githubusercontent.com - GetRawReposContentsByOwnerByRepoByPath = "GET /{owner}/{repo}/HEAD/{path}" - GetRawReposContentsByOwnerByRepoByBranchByPath = "GET /{owner}/{repo}/refs/heads/{branch}/{path}" - GetRawReposContentsByOwnerByRepoByTagByPath = "GET /{owner}/{repo}/refs/tags/{tag}/{path}" - GetRawReposContentsByOwnerByRepoBySHAByPath = "GET /{owner}/{repo}/{sha}/{path}" + GetRawReposContentsByOwnerByRepoByPath = "GET /{owner}/{repo}/HEAD/{path:.*}" + GetRawReposContentsByOwnerByRepoByBranchByPath = "GET /{owner}/{repo}/refs/heads/{branch}/{path:.*}" + GetRawReposContentsByOwnerByRepoByTagByPath = "GET /{owner}/{repo}/refs/tags/{tag}/{path:.*}" + GetRawReposContentsByOwnerByRepoBySHAByPath = "GET /{owner}/{repo}/{sha}/{path:.*}" ) type expectations struct { diff --git a/pkg/github/repository_resource_test.go b/pkg/github/repository_resource_test.go index adabaad2c..b55b821af 100644 --- a/pkg/github/repository_resource_test.go +++ b/pkg/github/repository_resource_test.go @@ -34,12 +34,11 @@ func Test_repositoryResourceContents(t *testing.T) { { name: "missing owner", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetRawReposContentsByOwnerByRepoByPath: - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "text/markdown") - _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) - require.NoError(t, err) - }), + GetRawReposContentsByOwnerByRepoByPath: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "text/markdown") + _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) + require.NoError(t, err) + }), }), uri: "repo:///repo/contents/README.md", handlerFn: func(deps ToolDependencies) mcp.ResourceHandler { @@ -51,12 +50,11 @@ func Test_repositoryResourceContents(t *testing.T) { { name: "missing repo", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetRawReposContentsByOwnerByRepoByBranchByPath: - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "text/markdown") - _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) - require.NoError(t, err) - }), + GetRawReposContentsByOwnerByRepoByBranchByPath: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "text/markdown") + _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) + require.NoError(t, err) + }), }), uri: "repo://owner//refs/heads/main/contents/README.md", handlerFn: func(deps ToolDependencies) mcp.ResourceHandler { @@ -68,12 +66,11 @@ func Test_repositoryResourceContents(t *testing.T) { { name: "successful blob content fetch", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetRawReposContentsByOwnerByRepoByPath: - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "image/png") - _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) - require.NoError(t, err) - }), + GetRawReposContentsByOwnerByRepoByPath: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "image/png") + _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) + require.NoError(t, err) + }), }), uri: "repo://owner/repo/contents/data.png", handlerFn: func(deps ToolDependencies) mcp.ResourceHandler { @@ -90,12 +87,11 @@ func Test_repositoryResourceContents(t *testing.T) { { name: "successful text content fetch (HEAD)", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetRawReposContentsByOwnerByRepoByPath: - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "text/markdown") - _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) - require.NoError(t, err) - }), + GetRawReposContentsByOwnerByRepoByPath: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "text/markdown") + _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) + require.NoError(t, err) + }), }), uri: "repo://owner/repo/contents/README.md", handlerFn: func(deps ToolDependencies) mcp.ResourceHandler { @@ -112,14 +108,13 @@ func Test_repositoryResourceContents(t *testing.T) { { name: "successful text content fetch (HEAD)", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetRawReposContentsByOwnerByRepoByPath: - http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "text/plain") + GetRawReposContentsByOwnerByRepoByPath: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/plain") - require.Contains(t, r.URL.Path, "pkg/github/actions.go") - _, err := w.Write([]byte("package actions\n\nfunc main() {\n // Sample Go file content\n}\n")) - require.NoError(t, err) - }), + require.Contains(t, r.URL.Path, "pkg/github/actions.go") + _, err := w.Write([]byte("package actions\n\nfunc main() {\n // Sample Go file content\n}\n")) + require.NoError(t, err) + }), }), uri: "repo://owner/repo/contents/pkg/github/actions.go", handlerFn: func(deps ToolDependencies) mcp.ResourceHandler { @@ -136,12 +131,11 @@ func Test_repositoryResourceContents(t *testing.T) { { name: "successful text content fetch (branch)", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetRawReposContentsByOwnerByRepoByBranchByPath: - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "text/markdown") - _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) - require.NoError(t, err) - }), + GetRawReposContentsByOwnerByRepoByBranchByPath: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "text/markdown") + _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) + require.NoError(t, err) + }), }), uri: "repo://owner/repo/refs/heads/main/contents/README.md", handlerFn: func(deps ToolDependencies) mcp.ResourceHandler { @@ -158,12 +152,11 @@ func Test_repositoryResourceContents(t *testing.T) { { name: "successful text content fetch (tag)", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetRawReposContentsByOwnerByRepoByTagByPath: - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "text/markdown") - _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) - require.NoError(t, err) - }), + GetRawReposContentsByOwnerByRepoByTagByPath: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "text/markdown") + _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) + require.NoError(t, err) + }), }), uri: "repo://owner/repo/refs/tags/v1.0.0/contents/README.md", handlerFn: func(deps ToolDependencies) mcp.ResourceHandler { @@ -180,12 +173,11 @@ func Test_repositoryResourceContents(t *testing.T) { { name: "successful text content fetch (sha)", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetRawReposContentsByOwnerByRepoBySHAByPath: - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "text/markdown") - _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) - require.NoError(t, err) - }), + GetRawReposContentsByOwnerByRepoBySHAByPath: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "text/markdown") + _, err := w.Write([]byte("# Test Repository\n\nThis is a test repository.")) + require.NoError(t, err) + }), }), uri: "repo://owner/repo/sha/abc123/contents/README.md", handlerFn: func(deps ToolDependencies) mcp.ResourceHandler { @@ -269,11 +261,11 @@ func Test_repositoryResourceContents(t *testing.T) { content := resp.Contents[0] switch tc.expectedResponseType { - case resourceResponseTypeBlob: + case resourceResponseTypeBlob: require.Equal(t, tc.expectedResult.Contents[0].Blob, content.Blob) - case resourceResponseTypeText: + case resourceResponseTypeText: require.Equal(t, tc.expectedResult.Contents[0].Text, content.Text) - default: + default: t.Fatalf("unknown expectedResponseType %v", tc.expectedResponseType) } }) From 0e32603819021806bf69a8180623c4893459a300 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 10:05:47 +0000 Subject: [PATCH 08/13] Migrate gists_test.go to testify mocks Co-authored-by: JoannaaKL <67866556+JoannaaKL@users.noreply.github.com> --- pkg/github/gists_test.go | 120 ++++++++++++++------------------------- 1 file changed, 43 insertions(+), 77 deletions(-) diff --git a/pkg/github/gists_test.go b/pkg/github/gists_test.go index 7c6f69833..981e2dae9 100644 --- a/pkg/github/gists_test.go +++ b/pkg/github/gists_test.go @@ -11,7 +11,6 @@ import ( "github.com/github/github-mcp-server/pkg/translations" "github.com/google/go-github/v79/github" "github.com/google/jsonschema-go/jsonschema" - "github.com/migueleliasweb/go-github-mock/src/mock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -77,24 +76,18 @@ func Test_ListGists(t *testing.T) { }{ { name: "list authenticated user's gists", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.GetGists, - mockGists, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetGists: mockResponse(t, http.StatusOK, mockGists), + }), requestArgs: map[string]interface{}{}, expectError: false, expectedGists: mockGists, }, { name: "list specific user's gists", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetUsersGistsByUsername, - mockResponse(t, http.StatusOK, mockGists), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetUsersGistsByUsername: mockResponse(t, http.StatusOK, mockGists), + }), requestArgs: map[string]interface{}{ "username": "testuser", }, @@ -103,18 +96,15 @@ func Test_ListGists(t *testing.T) { }, { name: "list gists with pagination and since parameter", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetGists, - expectQueryParams(t, map[string]string{ - "since": "2023-01-01T00:00:00Z", - "page": "2", - "per_page": "5", - }).andThen( - mockResponse(t, http.StatusOK, mockGists), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetGists: expectQueryParams(t, map[string]string{ + "since": "2023-01-01T00:00:00Z", + "page": "2", + "per_page": "5", + }).andThen( + mockResponse(t, http.StatusOK, mockGists), ), - ), + }), requestArgs: map[string]interface{}{ "since": "2023-01-01T00:00:00Z", "page": float64(2), @@ -125,12 +115,9 @@ func Test_ListGists(t *testing.T) { }, { name: "invalid since parameter", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.GetGists, - mockGists, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetGists: mockResponse(t, http.StatusOK, mockGists), + }), requestArgs: map[string]interface{}{ "since": "invalid-date", }, @@ -139,15 +126,12 @@ func Test_ListGists(t *testing.T) { }, { name: "list gists fails with error", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetGists, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetGists: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusUnauthorized) _, _ = w.Write([]byte(`{"message": "Requires authentication"}`)) }), - ), - ), + }), requestArgs: map[string]interface{}{}, expectError: true, expectedErrMsg: "failed to list gists", @@ -242,12 +226,9 @@ func Test_GetGist(t *testing.T) { }{ { name: "Successful fetching different gist", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetGistsByGistId, - mockResponse(t, http.StatusOK, mockGist), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetGistsByGistID: mockResponse(t, http.StatusOK, mockGist), + }), requestArgs: map[string]interface{}{ "gist_id": "gist1", }, @@ -256,15 +237,12 @@ func Test_GetGist(t *testing.T) { }, { name: "gist_id parameter missing", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetGistsByGistId, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetGistsByGistID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusUnprocessableEntity) _, _ = w.Write([]byte(`{"message": "Invalid Request"}`)) }), - ), - ), + }), requestArgs: map[string]interface{}{}, expectError: true, expectedErrMsg: "missing required parameter: gist_id", @@ -361,12 +339,9 @@ func Test_CreateGist(t *testing.T) { }{ { name: "create gist successfully", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.PostGists, - mockResponse(t, http.StatusCreated, createdGist), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + PostGists: mockResponse(t, http.StatusCreated, createdGist), + }), requestArgs: map[string]interface{}{ "filename": "test.go", "content": "package main\n\nfunc main() {\n\tfmt.Println(\"Hello, Gist!\")\n}", @@ -378,7 +353,7 @@ func Test_CreateGist(t *testing.T) { }, { name: "missing required filename", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]interface{}{ "content": "test content", "description": "Test Gist", @@ -388,7 +363,7 @@ func Test_CreateGist(t *testing.T) { }, { name: "missing required content", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]interface{}{ "filename": "test.go", "description": "Test Gist", @@ -398,15 +373,12 @@ func Test_CreateGist(t *testing.T) { }, { name: "api returns error", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.PostGists, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + PostGists: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusUnauthorized) _, _ = w.Write([]byte(`{"message": "Requires authentication"}`)) }), - ), - ), + }), requestArgs: map[string]interface{}{ "filename": "test.go", "content": "package main", @@ -506,12 +478,9 @@ func Test_UpdateGist(t *testing.T) { }{ { name: "update gist successfully", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.PatchGistsByGistId, - mockResponse(t, http.StatusOK, updatedGist), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + PatchGistsByGistID: mockResponse(t, http.StatusOK, updatedGist), + }), requestArgs: map[string]interface{}{ "gist_id": "existing-gist-id", "filename": "updated.go", @@ -523,7 +492,7 @@ func Test_UpdateGist(t *testing.T) { }, { name: "missing required gist_id", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]interface{}{ "filename": "updated.go", "content": "updated content", @@ -534,7 +503,7 @@ func Test_UpdateGist(t *testing.T) { }, { name: "missing required filename", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]interface{}{ "gist_id": "existing-gist-id", "content": "updated content", @@ -545,7 +514,7 @@ func Test_UpdateGist(t *testing.T) { }, { name: "missing required content", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]interface{}{ "gist_id": "existing-gist-id", "filename": "updated.go", @@ -556,15 +525,12 @@ func Test_UpdateGist(t *testing.T) { }, { name: "api returns error", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.PatchGistsByGistId, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + PatchGistsByGistID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNotFound) _, _ = w.Write([]byte(`{"message": "Not Found"}`)) }), - ), - ), + }), requestArgs: map[string]interface{}{ "gist_id": "nonexistent-gist-id", "filename": "updated.go", From 299884149322008171e8141a137ff2b1e503f6d0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 10:13:19 +0000 Subject: [PATCH 09/13] Add comprehensive migration guide for remaining files Co-authored-by: JoannaaKL <67866556+JoannaaKL@users.noreply.github.com> --- MIGRATION_GUIDE.md | 179 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 MIGRATION_GUIDE.md diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md new file mode 100644 index 000000000..a366c2b78 --- /dev/null +++ b/MIGRATION_GUIDE.md @@ -0,0 +1,179 @@ +# go-github-mock to testify Migration Guide + +## Status + +**Completed: 8/14 files (57%)** + +### ✅ Migrated Files +1. pkg/raw/raw_test.go +2. pkg/github/actions_test.go (1,428 lines) +3. pkg/github/context_tools_test.go (530 lines) +4. pkg/github/dependabot_test.go (271 lines) +5. pkg/github/gists_test.go (617 lines) +6. pkg/github/repository_resource_test.go (307 lines) +7. pkg/github/secret_scanning_test.go (267 lines) +8. pkg/github/security_advisories_test.go (551 lines) + +### ⏳ Remaining Files +1. pkg/github/issues_test.go (3,755 lines) - **Largest file** +2. pkg/github/pullrequests_test.go (3,355 lines) +3. pkg/github/repositories_test.go (3,532 lines) +4. pkg/github/projects_test.go (1,711 lines) +5. pkg/github/notifications_test.go (801 lines) +6. pkg/github/search_test.go (776 lines) + +**Total remaining: ~13,930 lines** + +## Migration Pattern + +### Step 1: Remove Import +```go +// Remove this line +"github.com/migueleliasweb/go-github-mock/src/mock" +``` + +### Step 2: Replace Mock Client Creation + +**Pattern A: Simple Mock with Data** +```go +// BEFORE: +mock.NewMockedHTTPClient( + mock.WithRequestMatch( + mock.GetAdvisories, + mockData, + ), +) + +// AFTER: +MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetAdvisories: mockResponse(t, http.StatusOK, mockData), +}) +``` + +**Pattern B: Mock with Custom Handler** +```go +// BEFORE: +mock.NewMockedHTTPClient( + mock.WithRequestMatchHandler( + mock.GetUser, + http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(mockUser) + }), + ), +) + +// AFTER: +MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetUser: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(mockUser) + }), +}) +``` + +**Pattern C: Mock with Query Parameter Expectations** +```go +// BEFORE: +mock.NewMockedHTTPClient( + mock.WithRequestMatchHandler( + mock.GetSearchRepositories, + expectQueryParams(t, map[string]string{"q": "test"}).andThen( + mockResponse(t, http.StatusOK, mockData), + ), + ), +) + +// AFTER: +MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetSearchRepositories: expectQueryParams(t, map[string]string{"q": "test"}).andThen( + mockResponse(t, http.StatusOK, mockData), + ), +}) +``` + +**Pattern D: Empty Mock (for validation tests)** +```go +// BEFORE: +mock.NewMockedHTTPClient() + +// AFTER: +MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}) +``` + +### Step 3: Fix Constant Names + +Replace old mock constants with new ones (note ID vs Id): +- `mock.GetGistsByGistId` → `GetGistsByGistID` +- `mock.GetNotificationsThreadsByThreadId` → `GetNotificationsThreadsByThreadID` +- `mock.PatchGistsByGistId` → `PatchGistsByGistID` + +All endpoint constants are defined in `pkg/github/helper_test.go`. + +## Common Issues and Solutions + +### Issue 1: Extra Closing Braces +**Symptom:** Syntax errors with `expected operand, found '}'` + +**Cause:** Regex replacement left extra `)` or `}` + +**Fix:** Check for patterns like: +- `mockResponse(t, http.StatusOK, data})` should be `mockResponse(t, http.StatusOK, data)` +- `}),` at wrong indentation - should be `})` to close map then `,` + +### Issue 2: Missing Closing Braces +**Symptom:** `missing ',' in argument list` + +**Fix:** Map literal should close with `})` not just `)`: +```go +MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetUser: mockResponse(t, http.StatusOK, mockUser), +}), // Note the closing }), +``` + +### Issue 3: Raw Content Endpoints +For raw content endpoints that handle paths with slashes (e.g., `pkg/github/actions.go`), use wildcard patterns: +- `GetRawReposContentsByOwnerByRepoByPath` uses `{path:.*}` pattern +- This is already configured in `helper_test.go` + +## Testing After Migration + +```bash +# Test specific file +go test ./pkg/github -run TestFunctionName -v + +# Test all GitHub tests +go test ./pkg/github -v + +# Run linter +script/lint +``` + +## Available Helper Functions + +All defined in `pkg/github/helper_test.go`: + +1. **MockHTTPClientWithHandlers** - Creates HTTP client with route handlers +2. **mockResponse** - Creates standard JSON response handler +3. **expectQueryParams** - Validates query parameters +4. **expectPath** - Validates request path +5. **expect** - Combines multiple expectations + +## Endpoint Constants + +All ~130 endpoint constants are in `pkg/github/helper_test.go`, including: +- User endpoints (GetUser, GetUserStarred, etc.) +- Repository endpoints (GetReposByOwnerByRepo, etc.) +- Issues endpoints (GetReposIssuesByOwnerByRepoByIssueNumber, etc.) +- Pull request endpoints +- Actions endpoints +- And many more... + +## Final Steps (After All Files Migrated) + +1. Remove `migueleliasweb/go-github-mock` from go.mod +2. Remove `pkg/raw/raw_mock.go` (temporarily restored for compatibility) +3. Run `go mod tidy` +4. Run `script/licenses` to update license files +5. Run full test suite: `script/test` +6. Run linter: `script/lint` From 7cea3b5cfb7af1f307bf6a2cb8f5becacf96e010 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 10:32:34 +0000 Subject: [PATCH 10/13] Add completion script and enhanced migration guide Co-authored-by: JoannaaKL <67866556+JoannaaKL@users.noreply.github.com> --- MIGRATION_GUIDE.md | 42 ++++++++++++++++++ complete_migration.sh | 94 ++++++++++++++++++++++++++++++++++++++++ pkg/github/gists_test.go | 24 +++++----- 3 files changed, 148 insertions(+), 12 deletions(-) create mode 100755 complete_migration.sh diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index a366c2b78..3aa198748 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -4,6 +4,14 @@ **Completed: 8/14 files (57%)** +**Next Priority Files:** +1. notifications_test.go (801 lines) - **Easiest** - only 4 simple WithRequestMatch patterns +2. search_test.go (776 lines) - 16 WithRequestMatchHandler (all with expectQueryParams) +3. projects_test.go (1,711 lines) - 31 WithRequestMatchHandler +4. pullrequests_test.go (3,355 lines) - Mixed patterns +5. repositories_test.go (3,532 lines) - Mixed patterns +6. issues_test.go (3,755 lines) - **Largest** - mixed patterns + ### ✅ Migrated Files 1. pkg/raw/raw_test.go 2. pkg/github/actions_test.go (1,428 lines) @@ -110,6 +118,40 @@ Replace old mock constants with new ones (note ID vs Id): All endpoint constants are defined in `pkg/github/helper_test.go`. +## Special Cases + +### Case 1: With expectQueryParams and andThen + +When the handler uses `expectQueryParams(...).andThen(...)`, the structure must be carefully closed: + +```go +// CORRECT: +MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetSearchRepositories: expectQueryParams(t, map[string]string{ + "q": "test", + }).andThen( + mockResponse(t, http.StatusOK, data), + ), // <- Close andThen with ), +}), // <- Close map with }), + +// INCORRECT (missing map close): +MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetSearchRepositories: expectQueryParams(t, map[string]string{ + "q": "test", + }).andThen( + mockResponse(t, http.StatusOK, data), + ), // <- Only closes andThen, missing }), +``` + +### Case 2: Multiple Endpoints in One Mock + +```go +MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposPullsByOwnerByRepoByPullNumber: mockResponse(t, http.StatusOK, mockPR), + GetRawReposContentsByOwnerByRepoBySHAByPath: mockResponse(t, http.StatusOK, mockContent), +}), +``` + ## Common Issues and Solutions ### Issue 1: Extra Closing Braces diff --git a/complete_migration.sh b/complete_migration.sh new file mode 100755 index 000000000..39c3aca81 --- /dev/null +++ b/complete_migration.sh @@ -0,0 +1,94 @@ +#!/bin/bash +# Script to complete the go-github-mock to testify migration +# Usage: ./complete_migration.sh + +set -e + +echo "=== Completing go-github-mock Migration ===" +echo "" +echo "This script will:" +echo "1. Migrate remaining 6 test files" +echo "2. Remove go-github-mock dependency" +echo "3. Remove raw_mock.go" +echo "4. Run tests and linter" +echo "" + +# Files to migrate +FILES=( + "pkg/github/notifications_test.go" + "pkg/github/search_test.go" + "pkg/github/projects_test.go" + "pkg/github/pullrequests_test.go" + "pkg/github/repositories_test.go" + "pkg/github/issues_test.go" +) + +echo "Files to migrate:" +for f in "${FILES[@]}"; do + lines=$(wc -l < "$f") + echo " - $f ($lines lines)" +done +echo "" + +read -p "Continue with migration? (y/n) " -n 1 -r +echo +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "Migration cancelled" + exit 1 +fi + +# Backup files +echo "Creating backups..." +for f in "${FILES[@]}"; do + cp "$f" "$f.backup" +done + +# Migration function +migrate_file() { + local file=$1 + echo "Migrating $file..." + + # Remove mock import + sed -i '/github\.com\/migueleliasweb\/go-github-mock\/src\/mock/d' "$file" + + # Fix ID naming + sed -i 's/ThreadId/ThreadID/g; s/GistId/GistID/g; s/GhsaId/GhsaID/g' "$file" + sed -i 's/WorkflowId/WorkflowID/g; s/RunId/RunID/g; s/JobId/JobID/g' "$file" + + # Replace empty mocks + sed -i 's/mock\.NewMockedHTTPClient()/MockHTTPClientWithHandlers(map[string]http.HandlerFunc{})/g' "$file" + + echo " Basic patterns applied. Manual review needed for:" + echo " - mock.WithRequestMatch patterns" + echo " - mock.WithRequestMatchHandler patterns" + echo " - Closing braces for maps" +} + +# Migrate each file +for f in "${FILES[@]}"; do + migrate_file "$f" +done + +echo "" +echo "=== Migration Step 1 Complete ===" +echo "" +echo "NEXT STEPS (Manual):" +echo "1. For each file, replace mock.NewMockedHTTPClient patterns:" +echo " - Find: mock.NewMockedHTTPClient(mock.WithRequestMatch(mock.GetX, data),)" +echo " - Replace with: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{GetX: mockResponse(t, http.StatusOK, data),})" +echo "" +echo "2. For mock.WithRequestMatchHandler patterns:" +echo " - Find: mock.NewMockedHTTPClient(mock.WithRequestMatchHandler(mock.GetX, handler),)" +echo " - Replace with: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{GetX: handler,})" +echo "" +echo "3. Test each file: go test ./pkg/github -run TestName -v" +echo "" +echo "4. When all files pass tests:" +echo " - Remove: go.mod entry for migueleliasweb/go-github-mock" +echo " - Remove: pkg/raw/raw_mock.go" +echo " - Run: go mod tidy" +echo " - Run: script/licenses" +echo " - Run: script/test" +echo " - Run: script/lint" +echo "" +echo "Backups saved as *.backup in case you need to revert." diff --git a/pkg/github/gists_test.go b/pkg/github/gists_test.go index 981e2dae9..339861958 100644 --- a/pkg/github/gists_test.go +++ b/pkg/github/gists_test.go @@ -128,9 +128,9 @@ func Test_ListGists(t *testing.T) { name: "list gists fails with error", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ GetGists: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusUnauthorized) - _, _ = w.Write([]byte(`{"message": "Requires authentication"}`)) - }), + w.WriteHeader(http.StatusUnauthorized) + _, _ = w.Write([]byte(`{"message": "Requires authentication"}`)) + }), }), requestArgs: map[string]interface{}{}, expectError: true, @@ -239,9 +239,9 @@ func Test_GetGist(t *testing.T) { name: "gist_id parameter missing", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ GetGistsByGistID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusUnprocessableEntity) - _, _ = w.Write([]byte(`{"message": "Invalid Request"}`)) - }), + w.WriteHeader(http.StatusUnprocessableEntity) + _, _ = w.Write([]byte(`{"message": "Invalid Request"}`)) + }), }), requestArgs: map[string]interface{}{}, expectError: true, @@ -375,9 +375,9 @@ func Test_CreateGist(t *testing.T) { name: "api returns error", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ PostGists: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusUnauthorized) - _, _ = w.Write([]byte(`{"message": "Requires authentication"}`)) - }), + w.WriteHeader(http.StatusUnauthorized) + _, _ = w.Write([]byte(`{"message": "Requires authentication"}`)) + }), }), requestArgs: map[string]interface{}{ "filename": "test.go", @@ -527,9 +527,9 @@ func Test_UpdateGist(t *testing.T) { name: "api returns error", mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ PatchGistsByGistID: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusNotFound) - _, _ = w.Write([]byte(`{"message": "Not Found"}`)) - }), + w.WriteHeader(http.StatusNotFound) + _, _ = w.Write([]byte(`{"message": "Not Found"}`)) + }), }), requestArgs: map[string]interface{}{ "gist_id": "nonexistent-gist-id", From e359be520f22f8fb8c25200114d8c9272bee69ec Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 10:56:15 +0000 Subject: [PATCH 11/13] Migrate notifications_test.go to testify mocks Co-authored-by: JoannaaKL <67866556+JoannaaKL@users.noreply.github.com> --- pkg/github/notifications_test.go | 194 +++++++++++-------------------- 1 file changed, 68 insertions(+), 126 deletions(-) diff --git a/pkg/github/notifications_test.go b/pkg/github/notifications_test.go index f730654db..8f6bdada5 100644 --- a/pkg/github/notifications_test.go +++ b/pkg/github/notifications_test.go @@ -10,7 +10,6 @@ import ( "github.com/github/github-mcp-server/pkg/translations" "github.com/google/go-github/v79/github" "github.com/google/jsonschema-go/jsonschema" - "github.com/migueleliasweb/go-github-mock/src/mock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -50,24 +49,18 @@ func Test_ListNotifications(t *testing.T) { }{ { name: "success default filter (no params)", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.GetNotifications, - []*github.Notification{mockNotification}, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetNotifications: mockResponse(t, http.StatusOK, []*github.Notification{mockNotification}), + }), requestArgs: map[string]interface{}{}, expectError: false, expectedResult: []*github.Notification{mockNotification}, }, { name: "success with filter=include_read_notifications", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.GetNotifications, - []*github.Notification{mockNotification}, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetNotifications: mockResponse(t, http.StatusOK, []*github.Notification{mockNotification}), + }), requestArgs: map[string]interface{}{ "filter": "include_read_notifications", }, @@ -76,12 +69,9 @@ func Test_ListNotifications(t *testing.T) { }, { name: "success with filter=only_participating", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.GetNotifications, - []*github.Notification{mockNotification}, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetNotifications: mockResponse(t, http.StatusOK, []*github.Notification{mockNotification}), + }), requestArgs: map[string]interface{}{ "filter": "only_participating", }, @@ -90,12 +80,9 @@ func Test_ListNotifications(t *testing.T) { }, { name: "success for repo notifications", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.GetReposNotificationsByOwnerByRepo, - []*github.Notification{mockNotification}, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetReposNotificationsByOwnerByRepo: mockResponse(t, http.StatusOK, []*github.Notification{mockNotification}), + }), requestArgs: map[string]interface{}{ "filter": "default", "since": "2024-01-01T00:00:00Z", @@ -110,12 +97,9 @@ func Test_ListNotifications(t *testing.T) { }, { name: "error", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetNotifications, - mockResponse(t, http.StatusInternalServerError, `{"message": "error"}`), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetNotifications: mockResponse(t, http.StatusInternalServerError, `{"message": "error"}`), + }), requestArgs: map[string]interface{}{}, expectError: true, expectedErrMsg: "error", @@ -184,12 +168,9 @@ func Test_ManageNotificationSubscription(t *testing.T) { }{ { name: "ignore subscription", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.PutNotificationsThreadsSubscriptionByThreadId, - mockSub, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + PutNotificationsThreadsSubscriptionByThreadID: mockResponse(t, http.StatusOK, mockSub), + }), requestArgs: map[string]interface{}{ "notificationID": "123", "action": "ignore", @@ -199,12 +180,9 @@ func Test_ManageNotificationSubscription(t *testing.T) { }, { name: "watch subscription", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.PutNotificationsThreadsSubscriptionByThreadId, - mockSubWatch, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + PutNotificationsThreadsSubscriptionByThreadID: mockResponse(t, http.StatusOK, mockSubWatch), + }), requestArgs: map[string]interface{}{ "notificationID": "123", "action": "watch", @@ -214,12 +192,9 @@ func Test_ManageNotificationSubscription(t *testing.T) { }, { name: "delete subscription", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.DeleteNotificationsThreadsSubscriptionByThreadId, - nil, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + DeleteNotificationsThreadsSubscriptionByThreadID: mockResponse(t, http.StatusOK, nil), + }), requestArgs: map[string]interface{}{ "notificationID": "123", "action": "delete", @@ -229,7 +204,7 @@ func Test_ManageNotificationSubscription(t *testing.T) { }, { name: "invalid action", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]interface{}{ "notificationID": "123", "action": "invalid", @@ -239,7 +214,7 @@ func Test_ManageNotificationSubscription(t *testing.T) { }, { name: "missing required notificationID", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]interface{}{ "action": "ignore", }, @@ -247,7 +222,7 @@ func Test_ManageNotificationSubscription(t *testing.T) { }, { name: "missing required action", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]interface{}{ "notificationID": "123", }, @@ -331,12 +306,9 @@ func Test_ManageRepositoryNotificationSubscription(t *testing.T) { }{ { name: "ignore subscription", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.PutReposSubscriptionByOwnerByRepo, - mockSub, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + PutReposSubscriptionByOwnerByRepo: mockResponse(t, http.StatusOK, mockSub), + }), requestArgs: map[string]interface{}{ "owner": "owner", "repo": "repo", @@ -347,12 +319,9 @@ func Test_ManageRepositoryNotificationSubscription(t *testing.T) { }, { name: "watch subscription", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.PutReposSubscriptionByOwnerByRepo, - mockWatchSub, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + PutReposSubscriptionByOwnerByRepo: mockResponse(t, http.StatusOK, mockWatchSub), + }), requestArgs: map[string]interface{}{ "owner": "owner", "repo": "repo", @@ -364,12 +333,9 @@ func Test_ManageRepositoryNotificationSubscription(t *testing.T) { }, { name: "delete subscription", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.DeleteReposSubscriptionByOwnerByRepo, - nil, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + DeleteReposSubscriptionByOwnerByRepo: mockResponse(t, http.StatusOK, nil), + }), requestArgs: map[string]interface{}{ "owner": "owner", "repo": "repo", @@ -380,7 +346,7 @@ func Test_ManageRepositoryNotificationSubscription(t *testing.T) { }, { name: "invalid action", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]interface{}{ "owner": "owner", "repo": "repo", @@ -391,7 +357,7 @@ func Test_ManageRepositoryNotificationSubscription(t *testing.T) { }, { name: "missing required owner", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]interface{}{ "repo": "repo", "action": "ignore", @@ -400,7 +366,7 @@ func Test_ManageRepositoryNotificationSubscription(t *testing.T) { }, { name: "missing required repo", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]interface{}{ "owner": "owner", "action": "ignore", @@ -409,7 +375,7 @@ func Test_ManageRepositoryNotificationSubscription(t *testing.T) { }, { name: "missing required action", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]interface{}{ "owner": "owner", "repo": "repo", @@ -495,12 +461,9 @@ func Test_DismissNotification(t *testing.T) { }{ { name: "mark as read", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.PatchNotificationsThreadsByThreadId, - nil, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + PatchNotificationsThreadsByThreadID: mockResponse(t, http.StatusOK, nil), + }), requestArgs: map[string]interface{}{ "threadID": "123", "state": "read", @@ -510,12 +473,9 @@ func Test_DismissNotification(t *testing.T) { }, { name: "mark as done", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.DeleteNotificationsThreadsByThreadId, - nil, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + DeleteNotificationsThreadsByThreadID: mockResponse(t, http.StatusOK, nil), + }), requestArgs: map[string]interface{}{ "threadID": "123", "state": "done", @@ -525,7 +485,7 @@ func Test_DismissNotification(t *testing.T) { }, { name: "invalid threadID format", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]interface{}{ "threadID": "notanumber", "state": "done", @@ -535,7 +495,7 @@ func Test_DismissNotification(t *testing.T) { }, { name: "missing required threadID", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]interface{}{ "state": "read", }, @@ -543,7 +503,7 @@ func Test_DismissNotification(t *testing.T) { }, { name: "missing required state", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]interface{}{ "threadID": "123", }, @@ -551,7 +511,7 @@ func Test_DismissNotification(t *testing.T) { }, { name: "invalid state value", - mockedClient: mock.NewMockedHTTPClient(), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}), requestArgs: map[string]interface{}{ "threadID": "123", "state": "invalid", @@ -632,24 +592,18 @@ func Test_MarkAllNotificationsRead(t *testing.T) { }{ { name: "success (no params)", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.PutNotifications, - nil, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + PutNotifications: mockResponse(t, http.StatusOK, nil), + }), requestArgs: map[string]interface{}{}, expectError: false, expectMarked: true, }, { name: "success with lastReadAt param", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.PutNotifications, - nil, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + PutNotifications: mockResponse(t, http.StatusOK, nil), + }), requestArgs: map[string]interface{}{ "lastReadAt": "2024-01-01T00:00:00Z", }, @@ -658,12 +612,9 @@ func Test_MarkAllNotificationsRead(t *testing.T) { }, { name: "success with owner and repo", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.PutReposNotificationsByOwnerByRepo, - nil, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + PutReposNotificationsByOwnerByRepo: mockResponse(t, http.StatusOK, nil), + }), requestArgs: map[string]interface{}{ "owner": "octocat", "repo": "hello-world", @@ -673,12 +624,9 @@ func Test_MarkAllNotificationsRead(t *testing.T) { }, { name: "API error", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.PutNotifications, - mockResponse(t, http.StatusInternalServerError, `{"message": "error"}`), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + PutNotifications: mockResponse(t, http.StatusInternalServerError, `{"message": "error"}`), + }), requestArgs: map[string]interface{}{}, expectError: true, expectedErrMsg: "error", @@ -741,12 +689,9 @@ func Test_GetNotificationDetails(t *testing.T) { }{ { name: "success", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.GetNotificationsThreadsByThreadId, - mockThread, - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetNotificationsThreadsByThreadID: mockResponse(t, http.StatusOK, mockThread), + }), requestArgs: map[string]interface{}{ "notificationID": "123", }, @@ -755,12 +700,9 @@ func Test_GetNotificationDetails(t *testing.T) { }, { name: "not found", - mockedClient: mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetNotificationsThreadsByThreadId, - mockResponse(t, http.StatusNotFound, `{"message": "not found"}`), - ), - ), + mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ + GetNotificationsThreadsByThreadID: mockResponse(t, http.StatusNotFound, `{"message": "not found"}`), + }), requestArgs: map[string]interface{}{ "notificationID": "123", }, From 0e050f1bb5563114ecc42fc121c8bcd95098ffd1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 11:15:47 +0000 Subject: [PATCH 12/13] Remove migration guide and completion script Co-authored-by: JoannaaKL <67866556+JoannaaKL@users.noreply.github.com> --- MIGRATION_GUIDE.md | 221 ------------------------------------------ complete_migration.sh | 94 ------------------ 2 files changed, 315 deletions(-) delete mode 100644 MIGRATION_GUIDE.md delete mode 100755 complete_migration.sh diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md deleted file mode 100644 index 3aa198748..000000000 --- a/MIGRATION_GUIDE.md +++ /dev/null @@ -1,221 +0,0 @@ -# go-github-mock to testify Migration Guide - -## Status - -**Completed: 8/14 files (57%)** - -**Next Priority Files:** -1. notifications_test.go (801 lines) - **Easiest** - only 4 simple WithRequestMatch patterns -2. search_test.go (776 lines) - 16 WithRequestMatchHandler (all with expectQueryParams) -3. projects_test.go (1,711 lines) - 31 WithRequestMatchHandler -4. pullrequests_test.go (3,355 lines) - Mixed patterns -5. repositories_test.go (3,532 lines) - Mixed patterns -6. issues_test.go (3,755 lines) - **Largest** - mixed patterns - -### ✅ Migrated Files -1. pkg/raw/raw_test.go -2. pkg/github/actions_test.go (1,428 lines) -3. pkg/github/context_tools_test.go (530 lines) -4. pkg/github/dependabot_test.go (271 lines) -5. pkg/github/gists_test.go (617 lines) -6. pkg/github/repository_resource_test.go (307 lines) -7. pkg/github/secret_scanning_test.go (267 lines) -8. pkg/github/security_advisories_test.go (551 lines) - -### ⏳ Remaining Files -1. pkg/github/issues_test.go (3,755 lines) - **Largest file** -2. pkg/github/pullrequests_test.go (3,355 lines) -3. pkg/github/repositories_test.go (3,532 lines) -4. pkg/github/projects_test.go (1,711 lines) -5. pkg/github/notifications_test.go (801 lines) -6. pkg/github/search_test.go (776 lines) - -**Total remaining: ~13,930 lines** - -## Migration Pattern - -### Step 1: Remove Import -```go -// Remove this line -"github.com/migueleliasweb/go-github-mock/src/mock" -``` - -### Step 2: Replace Mock Client Creation - -**Pattern A: Simple Mock with Data** -```go -// BEFORE: -mock.NewMockedHTTPClient( - mock.WithRequestMatch( - mock.GetAdvisories, - mockData, - ), -) - -// AFTER: -MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetAdvisories: mockResponse(t, http.StatusOK, mockData), -}) -``` - -**Pattern B: Mock with Custom Handler** -```go -// BEFORE: -mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetUser, - http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) - json.NewEncoder(w).Encode(mockUser) - }), - ), -) - -// AFTER: -MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetUser: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(http.StatusOK) - json.NewEncoder(w).Encode(mockUser) - }), -}) -``` - -**Pattern C: Mock with Query Parameter Expectations** -```go -// BEFORE: -mock.NewMockedHTTPClient( - mock.WithRequestMatchHandler( - mock.GetSearchRepositories, - expectQueryParams(t, map[string]string{"q": "test"}).andThen( - mockResponse(t, http.StatusOK, mockData), - ), - ), -) - -// AFTER: -MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetSearchRepositories: expectQueryParams(t, map[string]string{"q": "test"}).andThen( - mockResponse(t, http.StatusOK, mockData), - ), -}) -``` - -**Pattern D: Empty Mock (for validation tests)** -```go -// BEFORE: -mock.NewMockedHTTPClient() - -// AFTER: -MockHTTPClientWithHandlers(map[string]http.HandlerFunc{}) -``` - -### Step 3: Fix Constant Names - -Replace old mock constants with new ones (note ID vs Id): -- `mock.GetGistsByGistId` → `GetGistsByGistID` -- `mock.GetNotificationsThreadsByThreadId` → `GetNotificationsThreadsByThreadID` -- `mock.PatchGistsByGistId` → `PatchGistsByGistID` - -All endpoint constants are defined in `pkg/github/helper_test.go`. - -## Special Cases - -### Case 1: With expectQueryParams and andThen - -When the handler uses `expectQueryParams(...).andThen(...)`, the structure must be carefully closed: - -```go -// CORRECT: -MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetSearchRepositories: expectQueryParams(t, map[string]string{ - "q": "test", - }).andThen( - mockResponse(t, http.StatusOK, data), - ), // <- Close andThen with ), -}), // <- Close map with }), - -// INCORRECT (missing map close): -MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetSearchRepositories: expectQueryParams(t, map[string]string{ - "q": "test", - }).andThen( - mockResponse(t, http.StatusOK, data), - ), // <- Only closes andThen, missing }), -``` - -### Case 2: Multiple Endpoints in One Mock - -```go -MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetReposPullsByOwnerByRepoByPullNumber: mockResponse(t, http.StatusOK, mockPR), - GetRawReposContentsByOwnerByRepoBySHAByPath: mockResponse(t, http.StatusOK, mockContent), -}), -``` - -## Common Issues and Solutions - -### Issue 1: Extra Closing Braces -**Symptom:** Syntax errors with `expected operand, found '}'` - -**Cause:** Regex replacement left extra `)` or `}` - -**Fix:** Check for patterns like: -- `mockResponse(t, http.StatusOK, data})` should be `mockResponse(t, http.StatusOK, data)` -- `}),` at wrong indentation - should be `})` to close map then `,` - -### Issue 2: Missing Closing Braces -**Symptom:** `missing ',' in argument list` - -**Fix:** Map literal should close with `})` not just `)`: -```go -MockHTTPClientWithHandlers(map[string]http.HandlerFunc{ - GetUser: mockResponse(t, http.StatusOK, mockUser), -}), // Note the closing }), -``` - -### Issue 3: Raw Content Endpoints -For raw content endpoints that handle paths with slashes (e.g., `pkg/github/actions.go`), use wildcard patterns: -- `GetRawReposContentsByOwnerByRepoByPath` uses `{path:.*}` pattern -- This is already configured in `helper_test.go` - -## Testing After Migration - -```bash -# Test specific file -go test ./pkg/github -run TestFunctionName -v - -# Test all GitHub tests -go test ./pkg/github -v - -# Run linter -script/lint -``` - -## Available Helper Functions - -All defined in `pkg/github/helper_test.go`: - -1. **MockHTTPClientWithHandlers** - Creates HTTP client with route handlers -2. **mockResponse** - Creates standard JSON response handler -3. **expectQueryParams** - Validates query parameters -4. **expectPath** - Validates request path -5. **expect** - Combines multiple expectations - -## Endpoint Constants - -All ~130 endpoint constants are in `pkg/github/helper_test.go`, including: -- User endpoints (GetUser, GetUserStarred, etc.) -- Repository endpoints (GetReposByOwnerByRepo, etc.) -- Issues endpoints (GetReposIssuesByOwnerByRepoByIssueNumber, etc.) -- Pull request endpoints -- Actions endpoints -- And many more... - -## Final Steps (After All Files Migrated) - -1. Remove `migueleliasweb/go-github-mock` from go.mod -2. Remove `pkg/raw/raw_mock.go` (temporarily restored for compatibility) -3. Run `go mod tidy` -4. Run `script/licenses` to update license files -5. Run full test suite: `script/test` -6. Run linter: `script/lint` diff --git a/complete_migration.sh b/complete_migration.sh deleted file mode 100755 index 39c3aca81..000000000 --- a/complete_migration.sh +++ /dev/null @@ -1,94 +0,0 @@ -#!/bin/bash -# Script to complete the go-github-mock to testify migration -# Usage: ./complete_migration.sh - -set -e - -echo "=== Completing go-github-mock Migration ===" -echo "" -echo "This script will:" -echo "1. Migrate remaining 6 test files" -echo "2. Remove go-github-mock dependency" -echo "3. Remove raw_mock.go" -echo "4. Run tests and linter" -echo "" - -# Files to migrate -FILES=( - "pkg/github/notifications_test.go" - "pkg/github/search_test.go" - "pkg/github/projects_test.go" - "pkg/github/pullrequests_test.go" - "pkg/github/repositories_test.go" - "pkg/github/issues_test.go" -) - -echo "Files to migrate:" -for f in "${FILES[@]}"; do - lines=$(wc -l < "$f") - echo " - $f ($lines lines)" -done -echo "" - -read -p "Continue with migration? (y/n) " -n 1 -r -echo -if [[ ! $REPLY =~ ^[Yy]$ ]]; then - echo "Migration cancelled" - exit 1 -fi - -# Backup files -echo "Creating backups..." -for f in "${FILES[@]}"; do - cp "$f" "$f.backup" -done - -# Migration function -migrate_file() { - local file=$1 - echo "Migrating $file..." - - # Remove mock import - sed -i '/github\.com\/migueleliasweb\/go-github-mock\/src\/mock/d' "$file" - - # Fix ID naming - sed -i 's/ThreadId/ThreadID/g; s/GistId/GistID/g; s/GhsaId/GhsaID/g' "$file" - sed -i 's/WorkflowId/WorkflowID/g; s/RunId/RunID/g; s/JobId/JobID/g' "$file" - - # Replace empty mocks - sed -i 's/mock\.NewMockedHTTPClient()/MockHTTPClientWithHandlers(map[string]http.HandlerFunc{})/g' "$file" - - echo " Basic patterns applied. Manual review needed for:" - echo " - mock.WithRequestMatch patterns" - echo " - mock.WithRequestMatchHandler patterns" - echo " - Closing braces for maps" -} - -# Migrate each file -for f in "${FILES[@]}"; do - migrate_file "$f" -done - -echo "" -echo "=== Migration Step 1 Complete ===" -echo "" -echo "NEXT STEPS (Manual):" -echo "1. For each file, replace mock.NewMockedHTTPClient patterns:" -echo " - Find: mock.NewMockedHTTPClient(mock.WithRequestMatch(mock.GetX, data),)" -echo " - Replace with: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{GetX: mockResponse(t, http.StatusOK, data),})" -echo "" -echo "2. For mock.WithRequestMatchHandler patterns:" -echo " - Find: mock.NewMockedHTTPClient(mock.WithRequestMatchHandler(mock.GetX, handler),)" -echo " - Replace with: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{GetX: handler,})" -echo "" -echo "3. Test each file: go test ./pkg/github -run TestName -v" -echo "" -echo "4. When all files pass tests:" -echo " - Remove: go.mod entry for migueleliasweb/go-github-mock" -echo " - Remove: pkg/raw/raw_mock.go" -echo " - Run: go mod tidy" -echo " - Run: script/licenses" -echo " - Run: script/test" -echo " - Run: script/lint" -echo "" -echo "Backups saved as *.backup in case you need to revert." From 669a77f633d01fd78db876db58a441ad3a05db22 Mon Sep 17 00:00:00 2001 From: JoannaaKL Date: Wed, 17 Dec 2025 12:24:10 +0100 Subject: [PATCH 13/13] Update pkg/github/helper_test.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- pkg/github/helper_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/github/helper_test.go b/pkg/github/helper_test.go index 4da03dabe..972903520 100644 --- a/pkg/github/helper_test.go +++ b/pkg/github/helper_test.go @@ -40,14 +40,14 @@ const ( DeleteReposSubscriptionByOwnerByRepo = "DELETE /repos/{owner}/{repo}/subscription" // Git endpoints - GetReposGitTreesByOwnerByRepoByTree = "GET /repos/{owner}/{repo}/git/trees/{tree}" - GetReposGitRefByOwnerByRepoByRef = "GET /repos/{owner}/{repo}/git/ref/{ref}" - PostReposGitRefsByOwnerByRepo = "POST /repos/{owner}/{repo}/git/refs" - PatchReposGitRefsByOwnerByRepoByRef = "PATCH /repos/{owner}/{repo}/git/refs/{ref}" - GetReposGitCommitsByOwnerByRepoByCommitSha = "GET /repos/{owner}/{repo}/git/commits/{commit_sha}" - PostReposGitCommitsByOwnerByRepo = "POST /repos/{owner}/{repo}/git/commits" - GetReposGitTagsByOwnerByRepoByTagSha = "GET /repos/{owner}/{repo}/git/tags/{tag_sha}" - PostReposGitTreesByOwnerByRepo = "POST /repos/{owner}/{repo}/git/trees" + GetReposGitTreesByOwnerByRepoByTree = "GET /repos/{owner}/{repo}/git/trees/{tree}" + GetReposGitRefByOwnerByRepoByRef = "GET /repos/{owner}/{repo}/git/ref/{ref}" + PostReposGitRefsByOwnerByRepo = "POST /repos/{owner}/{repo}/git/refs" + PatchReposGitRefsByOwnerByRepoByRef = "PATCH /repos/{owner}/{repo}/git/refs/{ref}" + GetReposGitCommitsByOwnerByRepoByCommitSHA = "GET /repos/{owner}/{repo}/git/commits/{commit_sha}" + PostReposGitCommitsByOwnerByRepo = "POST /repos/{owner}/{repo}/git/commits" + GetReposGitTagsByOwnerByRepoByTagSHA = "GET /repos/{owner}/{repo}/git/tags/{tag_sha}" + PostReposGitTreesByOwnerByRepo = "POST /repos/{owner}/{repo}/git/trees" GetReposCommitsStatusByOwnerByRepoByRef = "GET /repos/{owner}/{repo}/commits/{ref}/status" GetReposCommitsStatusesByOwnerByRepoByRef = "GET /repos/{owner}/{repo}/commits/{ref}/statuses"