code-corps-api icon indicating copy to clipboard operation
code-corps-api copied to clipboard

Sync assignees from GitHub

Open joshsmith opened this issue 7 years ago • 3 comments

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.

joshsmith avatar Nov 17 '17 23:11 joshsmith

When getting assignees from GitHub, we should:

  • Create or delete GithubIssueAssignee records
  • If there's already a UserTask for the Task, do nothing
  • If there is no UserTask, assign the User that relates to the GithubIssueAssignee to the Task that relates to the GithubIssue

joshsmith avatar Nov 19 '17 00:11 joshsmith

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 the GithubIssue
    • Delete all the GithubIssueAssignee records that do not match the GithubUser records for the extracted IDs
    • Create new GithubIssueAssignee records for any remaining GithubUser records that match

joshsmith avatar Nov 19 '17 01:11 joshsmith

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 or unassigned
  • assignee -> the specific github user that was assigned or unassigned
  • issue, containing assignees, 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

begedin avatar Nov 20 '17 15:11 begedin