1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
package codeberg
import (
"encoding/json"
"fmt"
"net/http"
"time"
)
// Repository represents a Codeberg/Gitea repository
type Repository struct {
ID int64 `json:"id"`
Name string `json:"name"`
FullName string `json:"full_name"`
Description string `json:"description"`
Private bool `json:"private"`
Fork bool `json:"fork"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
CloneURL string `json:"clone_url"`
SSHURL string `json:"ssh_url"`
Size int `json:"size"`
Archived bool `json:"archived"`
Empty bool `json:"empty"`
}
// Client handles Codeberg API operations
type Client struct {
baseURL string
org string
}
// CLAUDE: Is there a rason, that we return a pointer of Client?
// NewClient creates a new Codeberg API client
func NewClient(org string) *Client {
return &Client{
baseURL: "https://codeberg.org/api/v1",
org: org,
}
}
// ListPublicRepos lists all public repositories for an organization
func (c *Client) ListPublicRepos() ([]Repository, error) {
var allRepos []Repository
page := 1
perPage := 50
for {
url := fmt.Sprintf("%s/orgs/%s/repos?page=%d&limit=%d", c.baseURL, c.org, page, perPage)
resp, err := http.Get(url)
if err != nil {
return nil, fmt.Errorf("failed to fetch repositories: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("API returned status %d", resp.StatusCode)
}
var repos []Repository
if err := json.NewDecoder(resp.Body).Decode(&repos); err != nil {
return nil, fmt.Errorf("failed to parse response: %w", err)
}
// Filter only public, non-fork, non-archived, non-empty repos
for _, repo := range repos {
if !repo.Private && !repo.Fork && !repo.Archived && !repo.Empty {
allRepos = append(allRepos, repo)
}
}
// If we got fewer repos than requested, we've reached the end
if len(repos) < perPage {
break
}
page++
}
return allRepos, nil
}
// ListUserPublicRepos lists all public repositories for a user
func (c *Client) ListUserPublicRepos() ([]Repository, error) {
var allRepos []Repository
page := 1
perPage := 50
for {
url := fmt.Sprintf("%s/users/%s/repos?page=%d&limit=%d", c.baseURL, c.org, page, perPage)
resp, err := http.Get(url)
if err != nil {
return nil, fmt.Errorf("failed to fetch repositories: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("API returned status %d", resp.StatusCode)
}
var repos []Repository
if err := json.NewDecoder(resp.Body).Decode(&repos); err != nil {
return nil, fmt.Errorf("failed to parse response: %w", err)
}
// Filter only public, non-fork, non-archived, non-empty repos
for _, repo := range repos {
if !repo.Private && !repo.Fork && !repo.Archived && !repo.Empty {
allRepos = append(allRepos, repo)
}
}
// If we got fewer repos than requested, we've reached the end
if len(repos) < perPage {
break
}
page++
}
return allRepos, nil
}
// GetRepoNames returns just the repository names
func GetRepoNames(repos []Repository) []string {
names := make([]string, 0, len(repos))
for _, repo := range repos {
names = append(names, repo.Name)
}
return names
}
|