feat: multi-repo patterns + directory recursion
patterns-repo now accepts a comma-separated list of repos: PATTERNS_REPO="rodin/elixir-patterns,rodin/phoenix-conventions" patterns-files accepts files AND directories: PATTERNS_FILES="README.md,docs/" When a path is a directory, all files within it are fetched recursively via the Gitea contents API. Only .md, .txt, .yml, and .yaml files are included as pattern content. New API methods: - ListContents: list files/dirs at a path via contents API - GetAllFilesInPath: recursively fetch all file contents This allows a single review action to pull idioms from multiple pattern repos (e.g. elixir-patterns + phoenix-conventions) and include entire directories of documentation as review criteria.
This commit is contained in:
@@ -177,3 +177,63 @@ func (c *Client) doGet(url string) ([]byte, error) {
|
||||
}
|
||||
return io.ReadAll(resp.Body)
|
||||
}
|
||||
|
||||
// ContentEntry represents a file or directory entry from the contents API.
|
||||
type ContentEntry struct {
|
||||
Name string `json:"name"`
|
||||
Path string `json:"path"`
|
||||
Type string `json:"type"` // "file" or "dir"
|
||||
}
|
||||
|
||||
// ListContents lists files and directories at a given path in a repo.
|
||||
func (c *Client) ListContents(owner, repo, path string) ([]ContentEntry, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/repos/%s/%s/contents/%s", c.BaseURL, owner, repo, path)
|
||||
body, err := c.doGet(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list contents %s: %w", path, err)
|
||||
}
|
||||
var entries []ContentEntry
|
||||
if err := json.Unmarshal(body, &entries); err != nil {
|
||||
return nil, fmt.Errorf("parse contents JSON: %w", err)
|
||||
}
|
||||
return entries, nil
|
||||
}
|
||||
|
||||
// GetAllFilesInPath recursively fetches all file contents under a path.
|
||||
// If the path is a file, returns just that file's content.
|
||||
// If the path is a directory, recursively fetches all files within it.
|
||||
func (c *Client) GetAllFilesInPath(owner, repo, path string) (map[string]string, error) {
|
||||
results := make(map[string]string)
|
||||
|
||||
// Try listing as directory first
|
||||
entries, err := c.ListContents(owner, repo, path)
|
||||
if err != nil {
|
||||
// Might be a file, try fetching directly
|
||||
content, fileErr := c.GetFileContent(owner, repo, path)
|
||||
if fileErr != nil {
|
||||
return nil, fmt.Errorf("path %q is neither a file nor directory: %w", path, err)
|
||||
}
|
||||
results[path] = content
|
||||
return results, nil
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
switch entry.Type {
|
||||
case "file":
|
||||
content, err := c.GetFileContent(owner, repo, entry.Path)
|
||||
if err != nil {
|
||||
continue // Skip files we can't read
|
||||
}
|
||||
results[entry.Path] = content
|
||||
case "dir":
|
||||
subResults, err := c.GetAllFilesInPath(owner, repo, entry.Path)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for k, v := range subResults {
|
||||
results[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user