Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita48e306

Browse files
authored
Improvements & refactoring of get_file_contents (github#1582)
* Improvements & refactoring of get_file_contents* Fix logical path when file or directory not found* Fix comment* Docs update* Do file matching when raw API returns error
1 parentadaa6a1 commita48e306

File tree

3 files changed

+62
-68
lines changed

3 files changed

+62
-68
lines changed

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1092,7 +1092,7 @@ The following sets of tools are available:
10921092

10931093
-**get_file_contents** - Get file or directory contents
10941094
-`owner`: Repository owner (username or organization) (string, required)
1095-
-`path`: Path to file/directory (directories must end with a slash '/') (string, optional)
1095+
-`path`: Path to file/directory (string, optional)
10961096
-`ref`: Accepts optional git refs such as`refs/tags/{tag}`,`refs/heads/{branch}` or`refs/pull/{pr_number}/head` (string, optional)
10971097
-`repo`: Repository name (string, required)
10981098
-`sha`: Accepts optional commit SHA. If specified, it will be used instead of ref (string, optional)

‎pkg/github/__toolsnaps__/get_file_contents.snap‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
},
1818
"path": {
1919
"type":"string",
20-
"description":"Path to file/directory (directories must end with a slash '/')",
20+
"description":"Path to file/directory",
2121
"default":"/"
2222
},
2323
"ref": {

‎pkg/github/repositories.go‎

Lines changed: 60 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@ func GetFileContents(getClient GetClientFn, getRawClient raw.GetRawClientFn, t t
560560
},
561561
"path": {
562562
Type:"string",
563-
Description:"Path to file/directory (directories must end with a slash '/')",
563+
Description:"Path to file/directory",
564564
Default:json.RawMessage(`"/"`),
565565
},
566566
"ref": {
@@ -608,28 +608,26 @@ func GetFileContents(getClient GetClientFn, getRawClient raw.GetRawClientFn, t t
608608
returnutils.NewToolResultError(fmt.Sprintf("failed to resolve git reference: %s",err)),nil,nil
609609
}
610610

611-
// If the path is (most likely) not to be a directory, we will
612-
// first try to get the raw content from the GitHub raw content API.
611+
ifrawOpts.SHA!="" {
612+
ref=rawOpts.SHA
613+
}
613614

614-
varrawAPIResponseCodeint
615-
ifpath!=""&&!strings.HasSuffix(path,"/") {
616-
// First, get file info from Contents API to retrieve SHA
617-
varfileSHAstring
618-
opts:=&github.RepositoryContentGetOptions{Ref:ref}
619-
fileContent,_,respContents,err:=client.Repositories.GetContents(ctx,owner,repo,path,opts)
620-
ifrespContents!=nil {
621-
deferfunc() {_=respContents.Body.Close() }()
622-
}
623-
iferr!=nil {
624-
returnghErrors.NewGitHubAPIErrorResponse(ctx,
625-
"failed to get file SHA",
626-
respContents,
627-
err,
628-
),nil,nil
629-
}
630-
iffileContent==nil||fileContent.SHA==nil {
631-
returnutils.NewToolResultError("file content SHA is nil, if a directory was requested, path parameters should end with a trailing slash '/'"),nil,nil
632-
}
615+
varfileSHAstring
616+
opts:=&github.RepositoryContentGetOptions{Ref:ref}
617+
618+
// Always call GitHub Contents API first to get metadata including SHA and determine if it's a file or directory
619+
fileContent,dirContent,respContents,err:=client.Repositories.GetContents(ctx,owner,repo,path,opts)
620+
ifrespContents!=nil {
621+
deferfunc() {_=respContents.Body.Close() }()
622+
}
623+
624+
// The path does not point to a file or directory.
625+
// Instead let's try to find it in the Git Tree by matching the end of the path.
626+
iferr!=nil|| (fileContent==nil&&dirContent==nil) {
627+
returnmatchFiles(ctx,client,owner,repo,ref,path,rawOpts,0)
628+
}
629+
630+
iffileContent!=nil&&fileContent.SHA!=nil {
633631
fileSHA=*fileContent.SHA
634632

635633
rawClient,err:=getRawClient(ctx)
@@ -702,55 +700,19 @@ func GetFileContents(getClient GetClientFn, getRawClient raw.GetRawClientFn, t t
702700
}
703701
returnutils.NewToolResultResource("successfully downloaded binary file",result),nil,nil
704702
}
705-
rawAPIResponseCode=resp.StatusCode
706-
}
707703

708-
ifrawOpts.SHA!="" {
709-
ref=rawOpts.SHA
710-
}
711-
ifstrings.HasSuffix(path,"/") {
712-
opts:=&github.RepositoryContentGetOptions{Ref:ref}
713-
_,dirContent,resp,err:=client.Repositories.GetContents(ctx,owner,repo,path,opts)
714-
iferr==nil&&resp.StatusCode==http.StatusOK {
715-
deferfunc() {_=resp.Body.Close() }()
716-
r,err:=json.Marshal(dirContent)
717-
iferr!=nil {
718-
returnutils.NewToolResultError("failed to marshal response"),nil,nil
719-
}
720-
returnutils.NewToolResultText(string(r)),nil,nil
721-
}
722-
}
723-
724-
// The path does not point to a file or directory.
725-
// Instead let's try to find it in the Git Tree by matching the end of the path.
726-
727-
// Step 1: Get Git Tree recursively
728-
tree,resp,err:=client.Git.GetTree(ctx,owner,repo,ref,true)
729-
iferr!=nil {
730-
returnghErrors.NewGitHubAPIErrorResponse(ctx,
731-
"failed to get git tree",
732-
resp,
733-
err,
734-
),nil,nil
735-
}
736-
deferfunc() {_=resp.Body.Close() }()
737-
738-
// Step 2: Filter tree for matching paths
739-
constmaxMatchingFiles=3
740-
matchingFiles:=filterPaths(tree.Entries,path,maxMatchingFiles)
741-
iflen(matchingFiles)>0 {
742-
matchingFilesJSON,err:=json.Marshal(matchingFiles)
704+
// Raw API call failed
705+
returnmatchFiles(ctx,client,owner,repo,ref,path,rawOpts,resp.StatusCode)
706+
}elseifdirContent!=nil {
707+
// file content or file SHA is nil which means it's a directory
708+
r,err:=json.Marshal(dirContent)
743709
iferr!=nil {
744-
returnutils.NewToolResultError(fmt.Sprintf("failed to marshalmatching files: %s",err)),nil,nil
710+
returnutils.NewToolResultError("failed to marshalresponse"),nil,nil
745711
}
746-
resolvedRefs,err:=json.Marshal(rawOpts)
747-
iferr!=nil {
748-
returnutils.NewToolResultError(fmt.Sprintf("failed to marshal resolved refs: %s",err)),nil,nil
749-
}
750-
returnutils.NewToolResultError(fmt.Sprintf("Resolved potential matches in the repository tree (resolved refs: %s, matching files: %s), but the raw content API returned an unexpected status code %d.",string(resolvedRefs),string(matchingFilesJSON),rawAPIResponseCode)),nil,nil
712+
returnutils.NewToolResultText(string(r)),nil,nil
751713
}
752714

753-
returnutils.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."),nil,nil
715+
returnutils.NewToolResultError("failed to get file contents"),nil,nil
754716
})
755717

756718
returntool,handler
@@ -2115,3 +2077,35 @@ func UnstarRepository(getClient GetClientFn, t translations.TranslationHelperFun
21152077

21162078
returntool,handler
21172079
}
2080+
2081+
funcmatchFiles(ctx context.Context,client*github.Client,owner,repo,ref,pathstring,rawOpts*raw.ContentOpts,rawAPIResponseCodeint) (*mcp.CallToolResult,any,error) {
2082+
// Step 1: Get Git Tree recursively
2083+
tree,response,err:=client.Git.GetTree(ctx,owner,repo,ref,true)
2084+
iferr!=nil {
2085+
returnghErrors.NewGitHubAPIErrorResponse(ctx,
2086+
"failed to get git tree",
2087+
response,
2088+
err,
2089+
),nil,nil
2090+
}
2091+
deferfunc() {_=response.Body.Close() }()
2092+
2093+
// Step 2: Filter tree for matching paths
2094+
constmaxMatchingFiles=3
2095+
matchingFiles:=filterPaths(tree.Entries,path,maxMatchingFiles)
2096+
iflen(matchingFiles)>0 {
2097+
matchingFilesJSON,err:=json.Marshal(matchingFiles)
2098+
iferr!=nil {
2099+
returnutils.NewToolResultError(fmt.Sprintf("failed to marshal matching files: %s",err)),nil,nil
2100+
}
2101+
resolvedRefs,err:=json.Marshal(rawOpts)
2102+
iferr!=nil {
2103+
returnutils.NewToolResultError(fmt.Sprintf("failed to marshal resolved refs: %s",err)),nil,nil
2104+
}
2105+
ifrawAPIResponseCode>0 {
2106+
returnutils.NewToolResultText(fmt.Sprintf("Resolved potential matches in the repository tree (resolved refs: %s, matching files: %s), but the content API returned an unexpected status code %d.",string(resolvedRefs),string(matchingFilesJSON),rawAPIResponseCode)),nil,nil
2107+
}
2108+
returnutils.NewToolResultText(fmt.Sprintf("Resolved potential matches in the repository tree (resolved refs: %s, matching files: %s).",string(resolvedRefs),string(matchingFilesJSON))),nil,nil
2109+
}
2110+
returnutils.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."),nil,nil
2111+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp