summaryrefslogtreecommitdiff
path: root/app/workers/process_commit_worker.rb
blob: 071741fbacd2cd6e6aca6860b9731f9a3040cc31 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# Worker for processing individiual commit messages pushed to a repository.
#
# Jobs for this worker are scheduled for every commit that is being pushed. As a
# result of this the workload of this worker should be kept to a bare minimum.
# Consider using an extra worker if you need to add any extra (and potentially
# slow) processing of commits.
class ProcessCommitWorker
  include Sidekiq::Worker
  include DedicatedSidekiqQueue

  # project_id - The ID of the project this commit belongs to.
  # user_id - The ID of the user that pushed the commit.
  # commit_sha - The SHA1 of the commit to process.
  # default - The data was pushed to the default branch.
  def perform(project_id, user_id, commit_sha, default = false)
    project = Project.find_by(id: project_id)

    return unless project

    user = User.find_by(id: user_id)

    return unless user

    commit = find_commit(project, commit_sha)

    return unless commit

    author = commit.author || user

    process_commit_message(project, commit, user, author, default)

    update_issue_metrics(commit, author)
  end

  def process_commit_message(project, commit, user, author, default = false)
    closed_issues = default ? commit.closes_issues(user) : []

    unless closed_issues.empty?
      close_issues(project, user, author, commit, closed_issues)
    end

    commit.create_cross_references!(author, closed_issues)
  end

  def close_issues(project, user, author, commit, issues)
    # We don't want to run permission related queries for every single issue,
    # therefor we use IssueCollection here and skip the authorization check in
    # Issues::CloseService#execute.
    IssueCollection.new(issues).updatable_by_user(user).each do |issue|
      Issues::CloseService.new(project, author).
        close_issue(issue, commit: commit)
    end
  end

  def update_issue_metrics(commit, author)
    mentioned_issues = commit.all_references(author).issues

    Issue::Metrics.where(issue_id: mentioned_issues.map(&:id), first_mentioned_in_commit_at: nil).
      update_all(first_mentioned_in_commit_at: commit.committed_date)
  end

  private

  def find_commit(project, sha)
    project.commit(sha)
  end
end