code-corps-api
code-corps-api copied to clipboard
Sync assignees from GitHub
Problem
When an issues is assigned/unassigned a user from GitHub, we need to sync that assignment to our assigned user on Code Corps.
In the short-term, we can just accept a single assignee (if no one is assigned on Code Corps yet) and ignore any other assignees.
When getting assignees from GitHub, we should:
- Create or delete
GithubIssueAssignee
records - If there's already a
UserTask
for theTask
, do nothing - If there is no
UserTask
, assign theUser
that relates to theGithubIssueAssignee
to theTask
that relates to theGithubIssue
We'll need to, given the issue payload from the API:
- Grab the
"assignees"
array - Extract all the GitHub
id
values for the assignees - Find or create GithubUsers for each assignee
- In a transaction
- Fetch all the existing
GithubIssueAssignee
records for theGithubIssue
- Delete all the
GithubIssueAssignee
records that do not match theGithubUser
records for the extracted IDs - Create new
GithubIssueAssignee
records for any remainingGithubUser
records that match
- Fetch all the existing
Looking into this, we do not currently respond to specific changes on a record during any github webhook event. Instead, we simply sync the entire record at once.
To elaborate, we don't really look at the changes
map in the payload. We just take the main record map, in this case, issue
, and use the data in it to sync our information.
In the case of assigned/unassigned
, the payload will have
-
action
->assigned
orunassigned
-
assignee
-> the specific github user that was assigned or unassigned -
issue
, containingassignees
, which is a list of users currently assigned
If we want to follow our current convention, we would ignore the assignee
and instead just look at assignees
, then follow a process similar to the initial repo sync which is part of handling an installation
created event - look at this assignees
list as master list and delete/insert what does not match locally.
That means that, in the least optimized scenario, or current Sync.issues_event
simply adds another couple of steps:
def issue_event(%{"issue" => issue_payload}) do
Multi.new
|> Multi.run(:repo, fn _ -> RepoFinder.find_repo(payload) end)
|> Multi.run(fn %{github_repo: github_repo} -> issue_payload |> Sync.Issue.sync(github_repo) end)
# this one
|> Multi.run(:github_issue_assignees, fn %{github_issue: github_issue} -> github_issue |> Sync.GiuthubIssueAssignee.sync(issue_payload) end)
|> Multi.run(:task_user, fn %{github_issue_assignees: assignees} -> assignees |> Sync.TaskUser.sync end)
|> Repo.transaction()
|> marshall_result()
end
A more optimized scenario adds the above function as a separate clause, matching against the "action"
key in the payload