Skip to content

Commit 6732f4e

Browse files
authored
Adds codeberg backend and Limeleaf coop with it (#154)
1 parent 2af4354 commit 6732f4e

5 files changed

Lines changed: 7848 additions & 6096 deletions

File tree

.tool-versions

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
elixir 1.14.3
2-
erlang 24.3.3
3-
nodejs 14.21.3
1+
elixir 1.14.5
2+
erlang 26.2.5
3+
nodejs 18.20.8

cooperatives.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,3 +701,11 @@ the-tech-support-cooperative:
701701
url: https://techsupport.coop
702702
description: "Retail Technology experts. Cooperative by design. Committed to Freedom."
703703
location: "US, CAN"
704+
705+
limeleaf:
706+
source: codeberg
707+
login: limeleaf
708+
name: Limeleaf Worker Collective
709+
url: https://limeleaf.coop/
710+
description: "Limeleaf is a worker-owned cooperative, based in Upstate New York"
711+
location: NY, USA

lib/coophub/backends/backends.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ defmodule Coophub.Backends do
3333
defp get_backend_module!("gitlab"), do: Backends.GitlabCom
3434
defp get_backend_module!("git.coop"), do: Backends.GitCoop
3535
defp get_backend_module!("0xacab"), do: Backends.HexAcab
36+
defp get_backend_module!("codeberg"), do: Backends.Codeberg
3637
defp get_backend_module!(source), do: raise("Unknown backend source: #{source}")
3738

3839
########

lib/coophub/backends/codeberg.ex

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
defmodule Coophub.Backends.Codeberg do
2+
alias Coophub.Repos
3+
alias Coophub.Backends
4+
alias Coophub.Schemas.{Organization, Repository}
5+
6+
require Logger
7+
8+
@type request_data :: Backends.request_data()
9+
@type org :: Backends.org()
10+
@type repo :: Backends.repo()
11+
@type langs :: Backends.langs()
12+
@type topics :: Backends.topics()
13+
14+
@behaviour Backends
15+
16+
########
17+
## BEHAVIOUR IMPLEMENTATION
18+
########
19+
20+
@impl Backends
21+
@spec name() :: String.t()
22+
def name(), do: "codeberg.org"
23+
24+
@impl Backends
25+
@spec prepare_request_org(String.t()) :: request_data
26+
def prepare_request_org(login) do
27+
prepare_request(login, "orgs/#{login}")
28+
end
29+
30+
@impl Backends
31+
@spec parse_org(map) :: org
32+
def parse_org(data) do
33+
data =
34+
%{
35+
"login" => data["name"],
36+
"name" => data["full_name"] || data["name"],
37+
"description" => data["description"],
38+
"avatar_url" => data["avatar_url"],
39+
"html_url" => "https://codeberg.org/#{data["name"]}",
40+
"url" => "https://codeberg.org/#{data["name"]}",
41+
"location" => data["location"]
42+
}
43+
|> Enum.into(data)
44+
45+
Repos.to_struct(Organization, data)
46+
end
47+
48+
@impl Backends
49+
@spec prepare_request_repos(org, integer) :: request_data
50+
def prepare_request_repos(%Organization{login: login}, limit) do
51+
prepare_request(
52+
login,
53+
"orgs/#{login}/repos?limit=#{limit}&sort=updated&order=desc"
54+
)
55+
end
56+
57+
@impl Backends
58+
@spec prepare_request_repo(org, map) :: request_data
59+
def prepare_request_repo(%Organization{login: login}, %{"name" => name}) do
60+
prepare_request("#{login}/#{name}", "repos/#{login}/#{name}")
61+
end
62+
63+
@impl Backends
64+
@spec parse_repo(map) :: repo
65+
def parse_repo(data) do
66+
data =
67+
%{
68+
"stargazers_count" => data["stars_count"] || 0,
69+
"html_url" => data["html_url"],
70+
"full_name" => data["full_name"],
71+
"topics" => data["topics"] || [],
72+
"pushed_at" => data["updated_at"],
73+
"fork" => data["fork"] || false,
74+
"forks_count" => data["forks_count"] || 0,
75+
"open_issues_count" => data["open_issues_count"] || 0,
76+
"owner" => %{
77+
"login" => get_in(data, ["owner", "login"]),
78+
"avatar_url" => get_in(data, ["owner", "avatar_url"]) || ""
79+
}
80+
}
81+
|> Enum.into(data)
82+
83+
repo = Repos.to_struct(Repository, data)
84+
85+
case repo.parent do
86+
%{"full_name" => name, "html_url" => url} ->
87+
Map.put(repo, :parent, %{name: name, url: url})
88+
89+
_ ->
90+
repo
91+
end
92+
end
93+
94+
@impl Backends
95+
@spec prepare_request_topics(org, repo) :: request_data
96+
def prepare_request_topics(%Organization{login: login}, %Repository{name: name}) do
97+
prepare_request("#{login}/#{name}", "repos/#{login}/#{name}/topics")
98+
end
99+
100+
@impl Backends
101+
@spec parse_topics(map) :: topics
102+
def parse_topics(data) do
103+
Map.get(data, "topics", [])
104+
end
105+
106+
@impl Backends
107+
@spec prepare_request_languages(org, repo) :: request_data
108+
def prepare_request_languages(%Organization{login: login}, %Repository{name: name}) do
109+
prepare_request("#{login}/#{name}", "repos/#{login}/#{name}/languages")
110+
end
111+
112+
@impl Backends
113+
@spec parse_languages(langs) :: langs
114+
def parse_languages(languages) do
115+
percentage_from_bytes(languages)
116+
end
117+
118+
########
119+
## INTERNALS
120+
########
121+
defp percentage_from_bytes(languages) do
122+
total = Enum.reduce(languages, 0, fn {_lang, bytes}, acc -> acc + bytes end)
123+
124+
if total > 0 do
125+
Enum.reduce(languages, %{}, fn {lang, bytes}, acc ->
126+
percentage_for_lang = (bytes * 100 / total) |> Float.round(2)
127+
Map.put(acc, lang, %{"percentage" => percentage_for_lang})
128+
end)
129+
else
130+
%{}
131+
end
132+
end
133+
134+
defp prepare_request(name, path) do
135+
{name, full_url(path), headers()}
136+
end
137+
138+
defp headers() do
139+
[]
140+
end
141+
142+
defp full_url(path), do: "https://codeberg.org/api/v1/#{path}"
143+
end

0 commit comments

Comments
 (0)