Skip to content

Commit cc5747b

Browse files
committed
feat: add include_sha parameter to get_file_contents tool
Add optional boolean parameter to retrieve file metadata instead of raw content. When include_sha=true, returns SHA, size, and other metadata via GitHub Contents API. Maintains backward compatibility and performance with Raw API as default. - Add include_sha parameter with comprehensive test coverage - Support metadata retrieval for both files and directories - Update tool description and schema validation
1 parent 1152eb9 commit cc5747b

File tree

1 file changed

+102
-4
lines changed

1 file changed

+102
-4
lines changed

pkg/github/repositories_test.go

Lines changed: 102 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,25 @@ func Test_GetFileContents(t *testing.T) {
3333
assert.Contains(t, tool.InputSchema.Properties, "path")
3434
assert.Contains(t, tool.InputSchema.Properties, "ref")
3535
assert.Contains(t, tool.InputSchema.Properties, "sha")
36+
assert.Contains(t, tool.InputSchema.Properties, "include_sha")
3637
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "path"})
3738

3839
// Mock response for raw content
3940
mockRawContent := []byte("# Test Repository\n\nThis is a test repository.")
4041

42+
// Setup mock file content for include_sha test
43+
mockFileContent := &github.RepositoryContent{
44+
Type: github.Ptr("file"),
45+
Name: github.Ptr("README.md"),
46+
Path: github.Ptr("README.md"),
47+
SHA: github.Ptr("abc123"),
48+
Size: github.Ptr(42),
49+
HTMLURL: github.Ptr("https://github.com/owner/repo/blob/main/README.md"),
50+
DownloadURL: github.Ptr("https://raw.githubusercontent.com/owner/repo/main/README.md"),
51+
Content: github.Ptr(base64.StdEncoding.EncodeToString(mockRawContent)),
52+
Encoding: github.Ptr("base64"),
53+
}
54+
4155
// Setup mock directory content for success case
4256
mockDirContent := []*github.RepositoryContent{
4357
{
@@ -140,6 +154,68 @@ func Test_GetFileContents(t *testing.T) {
140154
expectError: false,
141155
expectedResult: mockDirContent,
142156
},
157+
{
158+
name: "successful file metadata fetch with include_sha",
159+
mockedClient: mock.NewMockedHTTPClient(
160+
mock.WithRequestMatchHandler(
161+
mock.GetReposContentsByOwnerByRepoByPath,
162+
expectQueryParams(t, map[string]string{"ref": "refs/heads/main"}).andThen(
163+
mockResponse(t, http.StatusOK, mockFileContent),
164+
),
165+
),
166+
),
167+
requestArgs: map[string]interface{}{
168+
"owner": "owner",
169+
"repo": "repo",
170+
"path": "README.md",
171+
"ref": "refs/heads/main",
172+
"include_sha": true,
173+
},
174+
expectError: false,
175+
expectedResult: mockFileContent,
176+
},
177+
{
178+
name: "successful text content fetch with include_sha false",
179+
mockedClient: mock.NewMockedHTTPClient(
180+
mock.WithRequestMatchHandler(
181+
raw.GetRawReposContentsByOwnerByRepoByBranchByPath,
182+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
183+
w.Header().Set("Content-Type", "text/markdown")
184+
_, _ = w.Write(mockRawContent)
185+
}),
186+
),
187+
),
188+
requestArgs: map[string]interface{}{
189+
"owner": "owner",
190+
"repo": "repo",
191+
"path": "README.md",
192+
"ref": "refs/heads/main",
193+
"include_sha": false,
194+
},
195+
expectError: false,
196+
expectedResult: mcp.TextResourceContents{
197+
URI: "repo://owner/repo/refs/heads/main/contents/README.md",
198+
Text: "# Test Repository\n\nThis is a test repository.",
199+
MIMEType: "text/markdown",
200+
},
201+
},
202+
{
203+
name: "successful directory metadata fetch with include_sha",
204+
mockedClient: mock.NewMockedHTTPClient(
205+
mock.WithRequestMatchHandler(
206+
mock.GetReposContentsByOwnerByRepoByPath,
207+
mockResponse(t, http.StatusOK, mockDirContent),
208+
),
209+
),
210+
requestArgs: map[string]interface{}{
211+
"owner": "owner",
212+
"repo": "repo",
213+
"path": "src/",
214+
"include_sha": true,
215+
},
216+
expectError: false,
217+
expectedResult: mockDirContent,
218+
},
143219
{
144220
name: "content fetch fails",
145221
mockedClient: mock.NewMockedHTTPClient(
@@ -165,7 +241,8 @@ func Test_GetFileContents(t *testing.T) {
165241
"ref": "refs/heads/main",
166242
},
167243
expectError: false,
168-
expectedResult: mcp.NewToolResultError("Failed to get file contents. The path does not point to a file or directory, or the file does not exist in the repository."),
244+
expectedResult: nil,
245+
expectedErrMsg: "failed to get file contents",
169246
},
170247
}
171248

@@ -190,6 +267,17 @@ func Test_GetFileContents(t *testing.T) {
190267
}
191268

192269
require.NoError(t, err)
270+
271+
// Check for tool errors (API errors that return as tool results)
272+
if tc.expectedErrMsg != "" {
273+
require.True(t, result.IsError)
274+
errorContent := getErrorResult(t, result)
275+
assert.Contains(t, errorContent.Text, tc.expectedErrMsg)
276+
return
277+
}
278+
279+
// Process successful results
280+
require.False(t, result.IsError)
193281
// Use the correct result helper based on the expected type
194282
switch expected := tc.expectedResult.(type) {
195283
case mcp.TextResourceContents:
@@ -210,9 +298,19 @@ func Test_GetFileContents(t *testing.T) {
210298
assert.Equal(t, *expected[i].Path, *content.Path)
211299
assert.Equal(t, *expected[i].Type, *content.Type)
212300
}
213-
case mcp.TextContent:
214-
textContent := getErrorResult(t, result)
215-
require.Equal(t, textContent, expected)
301+
case *github.RepositoryContent:
302+
// File metadata fetch returns a text result (JSON object)
303+
textContent := getTextResult(t, result)
304+
var returnedContent github.RepositoryContent
305+
err = json.Unmarshal([]byte(textContent.Text), &returnedContent)
306+
require.NoError(t, err)
307+
assert.Equal(t, *expected.Name, *returnedContent.Name)
308+
assert.Equal(t, *expected.Path, *returnedContent.Path)
309+
assert.Equal(t, *expected.SHA, *returnedContent.SHA)
310+
assert.Equal(t, *expected.Size, *returnedContent.Size)
311+
if expected.Content != nil {
312+
assert.Equal(t, *expected.Content, *returnedContent.Content)
313+
}
216314
}
217315
})
218316
}

0 commit comments

Comments
 (0)