diff options
| author | Paul Buetow <paul@buetow.org> | 2025-06-23 23:51:54 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-06-23 23:51:54 +0300 |
| commit | ca38df1f30ddedbbdbf73d1f8d4ddd98b12d3740 (patch) | |
| tree | 322d1cf903fbc86b1383361cf0370b878b61768e /internal/github/github.go | |
| parent | 2caf07a82d89c8f3e0ecb3bdc6662bd757600b22 (diff) | |
Add --sync-github-public flag to sync GitHub repos to Codeberg
- Implement GitHub API client methods to list public repositories
- Add --sync-github-public flag to sync all public GitHub repos to Codeberg
- Add --create-codeberg-repos flag (placeholder for future implementation)
- Support pagination for GitHub API to handle users with many repos
- Filter GitHub repos to exclude forks, archived, and private repos
- Update README with new sync direction and features
- Add dry-run support for GitHub->Codeberg sync
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Diffstat (limited to 'internal/github/github.go')
| -rw-r--r-- | internal/github/github.go | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/internal/github/github.go b/internal/github/github.go index 38aafa0..7d6213a 100644 --- a/internal/github/github.go +++ b/internal/github/github.go @@ -197,4 +197,79 @@ func (c *Client) CreateRepo(repoName, description string, private bool) error { // HasToken returns whether a token is configured func (c *Client) HasToken() bool { return c.token != "" +} + +// Repository represents a GitHub repository +type Repository struct { + Name string `json:"name"` + Description string `json:"description"` + Private bool `json:"private"` + Fork bool `json:"fork"` + Archived bool `json:"archived"` + Disabled bool `json:"disabled"` + Size int `json:"size"` +} + +// ListPublicRepos lists all public repositories for the user/org +func (c *Client) ListPublicRepos() ([]Repository, error) { + if c.token == "" { + return nil, fmt.Errorf("GitHub token required to list repositories") + } + + var allRepos []Repository + page := 1 + perPage := 100 + + for { + url := fmt.Sprintf("https://api.github.com/users/%s/repos?page=%d&per_page=%d&type=owner", c.org, page, perPage) + fmt.Printf(" Fetching page %d...\n", page) + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + + req.Header.Set("Authorization", "Bearer "+c.token) + req.Header.Set("Accept", "application/vnd.github.v3+json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != 200 { + body, _ := io.ReadAll(resp.Body) + return nil, fmt.Errorf("failed to list repos: status %d: %s", resp.StatusCode, string(body)) + } + + var repos []Repository + if err := json.NewDecoder(resp.Body).Decode(&repos); err != nil { + return nil, fmt.Errorf("failed to decode response: %w", err) + } + + // Filter for public, non-fork, non-archived, non-empty repos + for _, repo := range repos { + if !repo.Private && !repo.Fork && !repo.Archived && !repo.Disabled && repo.Size > 0 { + allRepos = append(allRepos, repo) + } + } + + // Check if there are more pages + if len(repos) < perPage { + break + } + page++ + } + + return allRepos, nil +} + +// GetRepoNames extracts repository names from a list of repos +func GetRepoNames(repos []Repository) []string { + names := make([]string, len(repos)) + for i, repo := range repos { + names[i] = repo.Name + } + return names }
\ No newline at end of file |
