Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Entrega iOSLab diplomado

diplomado7g-eval.livemd

Entrega iOSLab diplomado

Mix.install([
  {:req, "~> 0.4.8"},
  {:req_github_oauth, "~> 0.1.1"},
  {:kino_explorer, "~> 0.1.11"}
])

Section

repo = "iOSLabUNAM/SwiftUIBasics"
req = Req.new(http_errors: :raise) |> ReqGitHubOAuth.attach()
defmodule GHUser do
  defstruct(id: nil, name: nil, username: nil, email: nil, bio: nil, url: nil, evaluations: %{})

  def parse(usr) do
    %GHUser{
      id: usr["id"],
      name: usr["name"],
      username: usr["login"],
      email: usr["email"],
      bio: usr["bio"],
      url: usr["url"]
    }
  end

  def fetch(req, username) do
    body = Req.get!(req, url: "https://api.github.com/users/#{username}").body

    parse(body)
  end
end
defmodule Issue do
  defstruct id: nil, title: nil

  def parse(iss) do
    %Issue{
      id: iss["number"],
      title: iss["title"]
    }
  end

  def load_all(req, repo, max_page \\ 8) do
    1..max_page
    |> Task.async_stream(fn page ->
      Req.get!(req, url: "https://api.github.com/repos/#{repo}/issues?page=#{page}&per_page=50").body
    end)
    |> Stream.map(fn {:ok, res} -> res end)
    |> Enum.to_list()
    |> List.flatten()
    |> Enum.filter(fn iss -> is_nil(iss["closed_at"]) && is_nil(iss["pull_request"]) end)
    |> Enum.map(&parse/1)
  end
end

issues = Issue.load_all(req, repo)
defmodule PullRequest do
  defstruct(
    number: nil,
    username: nil,
    body: nil,
    url: nil,
    html_url: nil,
    timeline_url: nil,
    review: nil,
    evaluation: 0
  )

  def parse(pr) do
    %PullRequest{
      number: pr["number"],
      username: pr["user"]["login"],
      body: pr["body"],
      url: pr["url"],
      html_url: pr["html_url"],
      timeline_url: "#{pr["issue_url"]}/timeline"
    }
  end

  def load_all(req, repo, max_page \\ 8) do
    1..max_page
    |> Task.async_stream(
      fn page ->
        Req.get!(req, url: "https://api.github.com/repos/#{repo}/pulls?page=#{page}&per_page=50").body
      end,
      max_concurrency: 8
    )
    |> Stream.map(fn {:ok, res} -> res end)
    |> Enum.to_list()
    |> List.flatten()
    |> Enum.filter(fn pr -> is_nil(pr["closed_at"]) || !is_nil(pr["body"]) end)
    |> Enum.map(&PullRequest.parse/1)
  end

  def fetch_reviews(req, pull_requests) do
    pull_requests
    |> Task.async_stream(&fetch_review(req, &1), max_concurrency: 8)
    |> Enum.map(fn {:ok, res} -> res end)
  end

  def fetch_review(req, %PullRequest{timeline_url: timeline_url} = pr) do
    comments = Req.get!(req, url: timeline_url).body

    review =
      comments
      |> Stream.filter(fn %{"event" => event} -> event == "reviewed" end)
      |> Stream.filter(fn %{"author_association" => author} -> author == "MEMBER" end)
      |> Enum.map(fn rev -> rev["body"] || "" end)
      |> Enum.join("\n")
      |> String.trim()

    pr
    |> Map.put(:review, review)
    |> parse_evaluation()
  end

  defp parse_evaluation(%PullRequest{review: review} = pr) do
    if String.contains?(review, "LGTM") do
      [{eval, _rem} | _] =
        ~r/\[(\d+)\]/
        |> Regex.scan(review)
        |> List.flatten()
        |> tl()
        |> Enum.map(&Integer.parse/1)

      %PullRequest{pr | evaluation: eval}
    else
      pr
    end
  end
end
pulls = PullRequest.load_all(req, repo)
evaluated = PullRequest.fetch_reviews(req, pulls)
students =
  evaluated
  |> Enum.map(fn %{username: username} -> username end)
  |> Enum.uniq()
  |> Task.async_stream(&GHUser.fetch(req, &1))
  |> Stream.map(fn {:ok, res} -> res end)
  |> Enum.to_list()
  |> List.flatten()
evaluation_map =
  students
  |> Enum.map(fn student ->
    student_prs =
      evaluated |> Enum.filter(fn %{username: username} -> username == student.username end)

    evals =
      issues
      |> Enum.map(fn iss ->
        {
          iss.id,
          Enum.find(student_prs, fn %{body: body} ->
            String.contains?(body || "", "##{iss.id}")
          end)
        }
      end)
      |> Map.new()

    %GHUser{student | evaluations: evals}
  end)
csv =
  evaluation_map
  |> Enum.map(fn student ->
    res =
      student
      |> Map.get(:evaluations)
      |> Enum.map(fn {_iss_id, pr} ->
        if is_nil(pr) do
          ""
        else
          "#{pr.evaluation || pr.html_url}"
        end
      end)
      |> Enum.join(",")

    "#{student.name || student.username},#{res}"
  end)
  |> Enum.join("\n")

hd_issues =
  issues
  |> Enum.map(&"##{&1.id}")
  |> Enum.join(",")

Explorer.DataFrame.load_csv!("name,#{hd_issues}\n#{csv}")