Skip to content

Commit

Permalink
Remove ProjectGithubRepo
Browse files Browse the repository at this point in the history
  • Loading branch information
joshsmith committed Nov 15, 2017
1 parent 4764879 commit 5db3605
Show file tree
Hide file tree
Showing 55 changed files with 460 additions and 866 deletions.
24 changes: 15 additions & 9 deletions lib/code_corps/analytics/segment_traits_builder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,22 @@ defmodule CodeCorps.Analytics.SegmentTraitsBuilder do
user_id: installation.user_id
}
end
defp traits(%CodeCorps.ProjectGithubRepo{} = record) do
record = record |> Repo.preload([:project, :github_repo])
defp traits(%CodeCorps.GithubRepo{} = record) do
project_title =
record
|> Repo.preload([:project])
|> Map.get(:project)
|> (&(&1 || %{})).()
|> Map.get(:title, "")

%{
project: record.project.title,
project_id: record.project_id,
github_repo_id: record.github_repo_id,
github_repo_github_account_login: record.github_repo.github_account_login,
github_repo_github_account_type: record.github_repo.github_account_type,
github_repo_github_id: record.github_repo.github_id,
github_repo_name: record.github_repo.name
id: record.id,
github_account_login: record.github_account_login,
github_account_type: record.github_account_type,
github_id: record.github_id,
github_repo_name: record.name,
project: project_title,
project_id: record.project_id
}
end
defp traits(%CodeCorps.ProjectSkill{} = record) do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ defmodule CodeCorps.GitHub.Event.InstallationRepositories do
- delete affected `CodeCorps.GithubRepo` records, respecting the rules
- if the GitHub payload for a repo is not matched with a record in our
database, just skip deleting it
- if the deleted `CodeCorps.GithubRepo` record is associated with
`CodeCorps.ProjectGithubRepo` records, they are deleted automatically,
due to `on_delete: :delete_all` set at the database level.
"""
@spec handle(map) :: outcome
def handle(payload) do
Expand Down
21 changes: 9 additions & 12 deletions lib/code_corps/github/sync/comment/comment/comment.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ defmodule CodeCorps.GitHub.Sync.Comment.Comment do
GithubIssue,
GithubRepo,
GithubUser,
Project,
ProjectGithubRepo,
Repo,
Task,
User
Expand Down Expand Up @@ -48,37 +46,36 @@ defmodule CodeCorps.GitHub.Sync.Comment.Comment do

@doc ~S"""
Creates or updates `CodeCorps.Comment` records for the specified
`CodeCorps.ProjectGithubRepo`.
`CodeCorps.GithubRepo`.
For each `CodeCorps.GithubComment` record that relates to the
`CodeCorps.GithubRepo` for a given`CodeCorps.ProjectGithubRepo`:
`CodeCorps.GithubRepo` for a given`CodeCorps.GithubRepo`:
- Find the related `CodeCorps.Task` record
- Create or update the related `CodeCorps.Comment` record
- Associate the `CodeCorps.Comment` record with the `CodeCorps.User` that
relates to the `CodeCorps.GithubUser` for the `CodeCorps.GithubComment`
"""
@spec sync_project_github_repo(ProjectGithubRepo.t) :: outcome
def sync_project_github_repo(%ProjectGithubRepo{github_repo: %GithubRepo{} = _} = project_github_repo) do
@spec sync_github_repo(GithubRepo.t) :: outcome
def sync_github_repo(%GithubRepo{} = github_repo) do
preloads = [
:project,
github_repo: [github_comments: [:github_issue, github_user: [:user]]]
github_comments: [:github_issue, github_user: [:user]]
]
%ProjectGithubRepo{github_repo: %{github_comments: github_comments}} =
project_github_repo |> Repo.preload(preloads)
%GithubRepo{github_comments: github_comments} =
github_repo |> Repo.preload(preloads)

github_comments
|> Enum.map(fn %GithubComment{github_user: %GithubUser{user: %User{} = user}} = github_comment ->
github_comment
|> find_task(project_github_repo)
|> find_task(github_repo)
|> sync(github_comment, user)
end)
|> ResultAggregator.aggregate
end

defp find_task(
%GithubComment{github_issue: %GithubIssue{id: github_issue_id}},
%ProjectGithubRepo{project: %Project{id: project_id}}) do
%GithubRepo{project_id: project_id}) do
query = from t in Task,
where: t.project_id == ^project_id,
join: gi in GithubIssue, on: t.github_issue_id == gi.id, where: gi.id == ^github_issue_id
Expand Down
6 changes: 3 additions & 3 deletions lib/code_corps/github/sync/issue/issue.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ defmodule CodeCorps.GitHub.Sync.Issue do
The process is as follows:
- match with `User` using `GitHub.Sync.User.RecordLinker`
- for the `ProjectGithubRepo` belonging to the matched repo:
- create or update the `Task` for the `Project`
- match with `CodeCorps.User` using `CodeCorps.GitHub.Sync.User.RecordLinker`
- create or update the `CodeCorps.Task` for the `CodeCorps.Project` in the
matched `CodeCorps.GithubRepo`
If the sync succeeds, it will return an `:ok` tuple with the created or
updated task.
Expand Down
18 changes: 9 additions & 9 deletions lib/code_corps/github/sync/issue/task/changeset.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ defmodule CodeCorps.GitHub.Sync.Issue.Task.Changeset do

alias CodeCorps.{
GithubIssue,
ProjectGithubRepo,
GithubRepo,
Repo,
Services.MarkdownRendererService,
Task,
Expand All @@ -23,25 +23,25 @@ defmodule CodeCorps.GitHub.Sync.Issue.Task.Changeset do
The changeset can be used to create or update a `Task`
"""
@spec build_changeset(Task.t, GithubIssue.t, ProjectGithubRepo.t, User.t) :: Changeset.t
@spec build_changeset(Task.t, GithubIssue.t, GithubRepo.t, User.t) :: Changeset.t
def build_changeset(
%Task{id: task_id} = task,
%GithubIssue{} = github_issue,
%ProjectGithubRepo{} = project_github_repo,
%GithubRepo{} = github_repo,
%User{} = user) do

case is_nil(task_id) do
true -> create_changeset(task, github_issue, project_github_repo, user)
false -> update_changeset(task, github_issue, project_github_repo)
true -> create_changeset(task, github_issue, github_repo, user)
false -> update_changeset(task, github_issue, github_repo)
end
end

@create_attrs ~w(created_at markdown modified_at status title)a
@spec create_changeset(Task.t, GithubIssue.t, ProjectGithubRepo.t, User.t) :: Changeset.t
@spec create_changeset(Task.t, GithubIssue.t, GithubRepo.t, User.t) :: Changeset.t
defp create_changeset(
%Task{} = task,
%GithubIssue{id: github_issue_id} = github_issue,
%ProjectGithubRepo{project_id: project_id, github_repo_id: github_repo_id},
%GithubRepo{id: github_repo_id, project_id: project_id},
%User{id: user_id}) do

task
Expand All @@ -64,11 +64,11 @@ defmodule CodeCorps.GitHub.Sync.Issue.Task.Changeset do
end

@update_attrs ~w(markdown modified_at status title)a
@spec update_changeset(Task.t, GithubIssue.t, ProjectGithubRepo.t) :: Changeset.t
@spec update_changeset(Task.t, GithubIssue.t, GithubRepo.t) :: Changeset.t
defp update_changeset(
%Task{} = task,
%GithubIssue{} = github_issue,
%ProjectGithubRepo{project_id: project_id}) do
%GithubRepo{project_id: project_id}) do
task
|> Changeset.cast(github_issue |> IssueAdapter.to_task, @update_attrs)
|> MarkdownRendererService.render_markdown_to_html(:markdown, :body)
Expand Down
48 changes: 22 additions & 26 deletions lib/code_corps/github/sync/issue/task/task.ex
Original file line number Diff line number Diff line change
@@ -1,75 +1,71 @@
defmodule CodeCorps.GitHub.Sync.Issue.Task do
alias CodeCorps.{
GitHub.Sync,
GitHub.Utils.ResultAggregator,
GithubIssue,
GithubRepo,
GithubUser,
ProjectGithubRepo,
Task,
User,
Repo
}
alias CodeCorps.GitHub.Sync.Issue.Task.Changeset, as: TaskChangeset
alias Ecto.Changeset

@type outcome :: {:ok, list(Task.t)} |
{:error, {list(Task.t), list(Changeset.t)}}

@doc """
When provided a `CodeCorps.GithubIssue` and a `CodeCorps.User`, for the
`CodeCorps.Project` associated to that `CodeCorps.GithubRepo` via a
`CodeCorps.ProjectGithubRepo`, it creates or updates a `CodeCorps.Task`.
`CodeCorps.Project` associated to that `CodeCorps.GithubRepo`, it creates or
updates a `CodeCorps.Task`.
"""
@spec sync_github_issue(GithubIssue.t, User.t) :: {:ok, Task.t}
def sync_github_issue(%GithubIssue{} = github_issue, %User{} = user) do
%GithubIssue{
github_repo: %GithubRepo{project_github_repo: project_github_repo}
} = github_issue |> Repo.preload(github_repo: :project_github_repo)
github_repo: %GithubRepo{} = github_repo
} = github_issue |> Repo.preload(:github_repo)

github_issue
|> sync(project_github_repo, user)
|> sync(github_repo, user)
end

@doc ~S"""
Creates or updates `CodeCorps.Task` records for the specified
`CodeCorps.ProjectGithubRepo`.
For each `CodeCorps.GithubIssue` record that relates to the
`CodeCorps.GithubRepo` for a given `CodeCorps.ProjectGithubRepo`:
Creates or updates `CodeCorps.Task` records for each `CodeCorps.GithubIssue`
record that relates to the `CodeCorps.GithubRepo`:
- Create or update the `CodeCorps.Task`
- Associate the `CodeCorps.Task` record with the `CodeCorps.User` that
relates to the `CodeCorps.GithubUser` for the `CodeCorps.GithubIssue`
"""
@spec sync_project_github_repo(ProjectGithubRepo.t) :: outcome
def sync_project_github_repo(%ProjectGithubRepo{github_repo: %GithubRepo{} = _} = project_github_repo) do
%ProjectGithubRepo{
github_repo: %GithubRepo{github_issues: github_issues}
} = project_github_repo |> Repo.preload([:project, github_repo: [github_issues: [github_user: [:user]]]])
@spec sync_github_repo(GithubRepo.t) :: outcome
def sync_github_repo(%GithubRepo{} = github_repo) do
%GithubRepo{
github_issues: github_issues
} = github_repo |> Repo.preload([:project, github_issues: [github_user: [:user]]])

github_issues
|> Enum.map(&find_or_create_task(&1, project_github_repo))
|> Enum.map(&find_or_create_task(&1, github_repo))
|> ResultAggregator.aggregate
end

defp find_or_create_task(
%GithubIssue{github_user: %GithubUser{user: %User{} = user}} = github_issue,
%ProjectGithubRepo{} = project_github_repo) do
%GithubRepo{} = github_repo) do

sync(github_issue, project_github_repo, user)
sync(github_issue, github_repo, user)
end

@spec sync(GithubIssue.t, ProjectGithubRepo.t, User.t) :: {:ok, ProjectGithubRepo.t} | {:error, Changeset.t}
defp sync(%GithubIssue{} = github_issue, %ProjectGithubRepo{} = project_github_repo, %User{} = user) do
project_github_repo
@spec sync(GithubIssue.t, GithubRepo.t, User.t) :: {:ok, GithubRepo.t} | {:error, Changeset.t}
defp sync(%GithubIssue{} = github_issue, %GithubRepo{} = github_repo, %User{} = user) do
github_repo
|> find_or_init_task(github_issue)
|> TaskChangeset.build_changeset(github_issue, project_github_repo, user)
|> Sync.Issue.Task.Changeset.build_changeset(github_issue, github_repo, user)
|> Repo.insert_or_update()
end

@spec find_or_init_task(ProjectGithubRepo.t, GithubIssue.t) :: Task.t
@spec find_or_init_task(GithubRepo.t, GithubIssue.t) :: Task.t
defp find_or_init_task(
%ProjectGithubRepo{project_id: project_id},
%GithubRepo{project_id: project_id},
%GithubIssue{id: github_issue_id}
) do
case Task |> Repo.get_by(github_issue_id: github_issue_id, project_id: project_id) do
Expand Down
4 changes: 2 additions & 2 deletions lib/code_corps/github/sync/pull_request/pull_request.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ defmodule CodeCorps.GitHub.Sync.PullRequest do
`CodeCorps.GitHub.Sync.Utils.RepoFinder`
- match with `CodeCorps.User` using
`CodeCorps.GitHub.Event.PullRequest.UserLinker`
- for each `CodeCorps.ProjectGithubRepo` belonging to matched repo:
- create or update `CodeCorps.Task` for the `CodeCorps.Project`
- create or update each `CodeCorps.Task` for the `CodeCorps.Project` matching
the `CodeCorps.GithubRepo`
If the sync succeeds, it will return an `:ok` tuple with a list of created or
updated tasks.
Expand Down
77 changes: 25 additions & 52 deletions lib/code_corps/github/sync/sync.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ defmodule CodeCorps.GitHub.Sync do
GithubRepo,
GitHub.Sync,
GitHub.Sync.Utils.RepoFinder,
ProjectGithubRepo,
Repo
}

Expand Down Expand Up @@ -134,14 +133,6 @@ defmodule CodeCorps.GitHub.Sync do
|> Repo.update
end

@spec mark_project_repo(ProjectGithubRepo.t, String.t, Keyword.t) :: {:ok, GithubRepo.t} | {:error, Changeset.t}
defp mark_project_repo(%ProjectGithubRepo{} = project_github_repo, sync_state, opts \\ []) do
params = build_sync_params(sync_state, opts)
project_github_repo
|> ProjectGithubRepo.update_sync_changeset(params)
|> Repo.update
end

@count_fields [
:syncing_comments_count,
:syncing_issues_count,
Expand Down Expand Up @@ -181,9 +172,15 @@ defmodule CodeCorps.GitHub.Sync do
- Fetches the comments from the API
- Creates or updates `GithubComment` records (and their related `GithubUser`
records)
- Creates or updates `User` records for the `GithubUser` records
- Creates or updates `Task` records, and relates them to any related
`GithubIssue` and `User` records created previously
- Creates or updates `Comment` records, and relates them to any related
`GithubComment` and `User` records created previously
"""
@spec sync_repo(GithubRepo.t) :: {:ok, GithubRepo.t}
def sync_repo(%GithubRepo{} = repo) do
repo = preload_github_repo(repo)
with {:ok, repo} <- repo |> mark_repo("fetching_pull_requests"),
{:ok, pr_payloads} <- repo |> GitHub.API.Repository.pulls |> sync_step(:fetch_pull_requests),
{:ok, repo} <- repo |> mark_repo("syncing_github_pull_requests", [syncing_pull_requests_count: pr_payloads |> Enum.count]),
Expand All @@ -196,7 +193,14 @@ defmodule CodeCorps.GitHub.Sync do
{:ok, comment_payloads} <- repo |> GitHub.API.Repository.issue_comments |> sync_step(:fetch_comments),
{:ok, repo} <- repo |> mark_repo("syncing_github_comments", [syncing_comments_count: comment_payloads |> Enum.count]),
{:ok, _comments} <- comment_payloads |> Enum.map(&Sync.Comment.GithubComment.create_or_update_comment(repo, &1)) |> ResultAggregator.aggregate |> sync_step(:sync_comments),
{:ok, repo} <- repo |> mark_repo("receiving_webhooks")
repo <- Repo.get(GithubRepo, repo.id) |> preload_github_repo(),
{:ok, repo} <- repo |> mark_repo("syncing_users"),
{:ok, _users} <- repo |> Sync.User.User.sync_github_repo() |> sync_step(:sync_users),
{:ok, repo} <- repo |> mark_repo("syncing_tasks"),
{:ok, _tasks} <- repo |> Sync.Issue.Task.sync_github_repo() |> sync_step(:sync_tasks),
{:ok, repo} <- repo |> mark_repo("syncing_comments"),
{:ok, _comments} <- repo |> Sync.Comment.Comment.sync_github_repo() |> sync_step(:sync_comments),
{:ok, repo} <- repo |> mark_repo("synced")
do
{:ok, repo}
else
Expand All @@ -206,51 +210,20 @@ defmodule CodeCorps.GitHub.Sync do
{:error, :sync_issues} -> repo |> mark_repo("errored_syncing_issues")
{:error, :fetch_comments} -> repo |> mark_repo("errored_fetching_comments")
{:error, :sync_comments} -> repo |> mark_repo("errored_syncing_comments")
{:error, :sync_users} -> repo |> mark_repo("errored_syncing_users")
{:error, :sync_tasks} -> repo |> mark_repo("errored_syncing_tasks")
{:error, :sync_comments} -> repo |> mark_repo("errored_syncing_comments")
end
end

@doc ~S"""
Syncs a `ProjectGithubRepo` with Code Corps.
Fetches and syncs records from the GitHub API for a given project's GitHub
repository, marking progress of the sync state along the way.
- Finds the `GithubRepo` and syncs it with Github using `sync_repo/1`
- Creates or updates `User` records for the `GithubUser` records
- Creates or updates `Task` records, and relates them to any related
`GithubIssue` and `User` records created previously
- Creates or updates `Comment` records, and relates them to any related
`GithubComment` and `User` records created previously
"""
@spec sync_project_github_repo(ProjectGithubRepo.t) :: {:ok, ProjectGithubRepo.t}
def sync_project_github_repo(%ProjectGithubRepo{} = project_github_repo) do
%ProjectGithubRepo{github_repo: %GithubRepo{} = repo} = project_github_repo =
project_github_repo
|> preload_project_github_repo

with {:ok, project_github_repo} <- project_github_repo |> mark_project_repo("syncing_github_repo"),
{:ok, %GithubRepo{sync_state: "receiving_webhooks"}} <- repo |> sync_repo(),
project_github_repo <- Repo.get(ProjectGithubRepo, project_github_repo.id) |> preload_project_github_repo(),
{:ok, project_github_repo} <- project_github_repo |> mark_project_repo("syncing_users"),
{:ok, _users} <- project_github_repo |> Sync.User.User.sync_project_github_repo() |> sync_step(:sync_users),
{:ok, project_github_repo} <- project_github_repo |> mark_project_repo("syncing_tasks"),
{:ok, _tasks} <- project_github_repo |> Sync.Issue.Task.sync_project_github_repo() |> sync_step(:sync_tasks),
{:ok, project_github_repo} <- project_github_repo |> mark_project_repo("syncing_comments"),
{:ok, _comments} <- project_github_repo |> Sync.Comment.Comment.sync_project_github_repo() |> sync_step(:sync_comments),
{:ok, project_github_repo} <- project_github_repo |> mark_project_repo("synced")
do
{:ok, project_github_repo}
else
{:ok, %GithubRepo{}} -> project_github_repo |> mark_project_repo("errored_syncing_github_repo")
{:error, :sync_users} -> repo |> mark_project_repo("errored_syncing_users")
{:error, :sync_tasks} -> repo |> mark_project_repo("errored_syncing_tasks")
{:error, :sync_comments} -> repo |> mark_project_repo("errored_syncing_comments")
end
end

defp preload_project_github_repo(%ProjectGithubRepo{} = project_github_repo) do
project_github_repo
|> Repo.preload([:project, github_repo: [:github_app_installation, [github_comments: [:github_issue, :github_user], github_issues: [:github_comments, :github_user]]]])
defp preload_github_repo(%GithubRepo{} = github_repo) do
github_repo
|> Repo.preload([
:github_app_installation,
:project,
github_comments: [:github_issue, :github_user],
github_issues: [:github_comments, :github_user]
])
end

@spec marshall_result(tuple) :: tuple
Expand Down

0 comments on commit 5db3605

Please sign in to comment.