Skip to content
This repository has been archived by the owner on Apr 4, 2024. It is now read-only.

Commit

Permalink
Add co-author trailers to merge commit.
Browse files Browse the repository at this point in the history
When creating the merge commit for a batch, add a "Co-authored-by"
trailer to the commit message for each author contributing to the batch.

Fixes: #382
  • Loading branch information
couchand committed Apr 8, 2018
1 parent a553f58 commit 4b7aedb
Show file tree
Hide file tree
Showing 8 changed files with 512 additions and 96 deletions.
12 changes: 12 additions & 0 deletions lib/github/github.ex
Expand Up @@ -37,6 +37,18 @@ defmodule BorsNG.GitHub do
GenServer.call(BorsNG.GitHub, {:get_pr, repo_conn, {pr_xref}})
end

@spec get_pr_commits!(tconn, integer | bitstring) :: [BorsNG.GitHub.Commit.t]
def get_pr_commits!(repo_conn, pr_xref) do
{:ok, commits} = get_pr_commits(repo_conn, pr_xref)
commits
end

@spec get_pr_commits(tconn, integer | bitstring) ::
{:ok, [BorsNG.GitHub.Commit.t]} | {:error, term}
def get_pr_commits(repo_conn, pr_xref) do
GenServer.call(BorsNG.GitHub, {:get_pr_commits, repo_conn, {pr_xref}})
end

@spec get_open_prs!(tconn) :: [tpr]
def get_open_prs!(repo_conn) do
{:ok, prs} = GenServer.call(
Expand Down
48 changes: 48 additions & 0 deletions lib/github/github/commit.ex
@@ -0,0 +1,48 @@
defmodule BorsNG.GitHub.Commit do
@moduledoc """
The structure of GitHub commit data.
"""

defstruct sha: "", author_name: "", author_email: ""

@type tjson :: map

@type t :: %BorsNG.GitHub.Commit{
sha: bitstring,
author_name: bitstring,
author_email: bitstring,
}

@doc """
Convert from Poison-decoded JSON to a Commit struct.
"""
@spec from_json!(tjson) :: t
def from_json!(json) do
{:ok, pr} = from_json(json)
pr
end

@doc """
Convert from Poison-decoded JSON to a Commit struct.
"""
@spec from_json(tjson) :: {:ok, t} | :err
def from_json(%{
"sha" => sha,
"commit" => %{
"author" => %{
"name" => author_name,
"email" => author_email,
},
},
}) do
{:ok, %BorsNG.GitHub.Commit{
sha: sha,
author_name: author_name,
author_email: author_email,
}}
end

def from_json(x) do
{:error, x}
end
end
12 changes: 12 additions & 0 deletions lib/github/github/server.ex
Expand Up @@ -82,6 +82,18 @@ defmodule BorsNG.GitHub.Server do
end
end

def do_handle_call(:get_pr_commits, repo_conn, {pr_xref}) do
case get!(repo_conn, "pulls/#{pr_xref}/commits") do
%{body: raw, status_code: 200} ->
commits = raw
|> Poison.decode!()
|> Enum.map(&BorsNG.GitHub.Commit.from_json!/1)
{:ok, commits}
e ->
{:error, :get_pr_commits, e.status_code, pr_xref}
end
end

def do_handle_call(:get_open_prs, {{:raw, token}, repo_xref}, {}) do
{:ok, get_open_prs_!(
token,
Expand Down
17 changes: 17 additions & 0 deletions lib/github/github/server_mock.ex
Expand Up @@ -43,6 +43,13 @@ defmodule BorsNG.GitHub.ServerMock do
...> id: 6,
...> login: "bors-fanboi",
...> avatar_url: "data:image/svg+xml,<svg></svg>"}}},
...> pr_commits: %{
...> 1 => [
...> %GitHub.Commit{
...> sha: "00000001",
...> author_name: "Bors Fanboi",
...> author_email: "bors-fanboi@example.com"}
...> ] },
...> statuses: %{},
...> files: %{}}})
iex> GitHub.get_open_prs!({{:installation, 91}, 14})
Expand Down Expand Up @@ -132,6 +139,16 @@ defmodule BorsNG.GitHub.ServerMock do
end
end

def do_handle_call(:get_pr_commits, repo_conn, {pr_xref}, state) do
with({:ok, repo} <- Map.fetch(state, repo_conn),
{:ok, pr_commits} <- Map.fetch(repo, :pr_commits),
do: Map.fetch(pr_commits, pr_xref))
|> case do
{:ok, _} = res -> {res, state}
_ -> {{:error, :get_pr_commits}, state}
end
end

def do_handle_call(:get_installation_repos, installation_conn, {}, state) do
with({:ok, installation} <- Map.fetch(state, installation_conn),
{:ok, repos} <- Map.fetch(installation, :repos),
Expand Down
12 changes: 11 additions & 1 deletion lib/worker/batcher.ex
Expand Up @@ -292,7 +292,8 @@ defmodule BorsNG.Worker.Batcher do
parents = [base.commit | Enum.map(patch_links, &(&1.patch.commit))]
commit_message = Batcher.Message.generate_commit_message(
patch_links,
toml.cut_body_after)
toml.cut_body_after,
gather_co_authors(batch, patch_links))
head = GitHub.synthesize_commit!(
repo_conn,
%{
Expand All @@ -317,6 +318,15 @@ defmodule BorsNG.Worker.Batcher do
{:conflict, nil}
end

def gather_co_authors(batch, patch_links) do
repo_conn = get_repo_conn(batch.project)
patch_links
|> Enum.map(&(&1.patch.pr_xref))
|> Enum.flat_map(&GitHub.get_pr_commits!(repo_conn, &1))
|> Enum.map(&("#{&1.author_name} <#{&1.author_email}>"))
|> Enum.uniq
end

defp setup_statuses(batch, toml) do
toml.status
|> Enum.map(&%Status{
Expand Down
7 changes: 5 additions & 2 deletions lib/worker/batcher/message.ex
Expand Up @@ -83,7 +83,7 @@ defmodule BorsNG.Worker.Batcher.Message do
"#{acc}\n * #{status_link}"
end

def generate_commit_message(patch_links, cut_body_after) do
def generate_commit_message(patch_links, cut_body_after, co_authors) do
commit_title = Enum.reduce(patch_links,
"Merge", &"#{&2} \##{&1.patch.pr_xref}")
commit_body = Enum.reduce(patch_links, "", fn link, acc ->
Expand All @@ -102,7 +102,10 @@ defmodule BorsNG.Worker.Batcher.Message do
#{body}
"""
end)
"#{commit_title}\n#{commit_body}"
co_author_trailers = co_authors
|> Enum.map(&("Co-authored-by: #{&1}"))
|> Enum.join("\n")
"#{commit_title}\n#{commit_body}\n#{co_author_trailers}\n"
end

def cut_body(nil, _), do: ""
Expand Down

0 comments on commit 4b7aedb

Please sign in to comment.