|
| 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