Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/app/processors/push_processor.rb
blob: 99144c6fd3fa4257978b0f9c2ac038cb01cf853f (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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# encoding: utf-8
#--
#   Copyright (C) 2011 Gitorious AS
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Affero General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU Affero General Public License for more details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
#++

# This is required because ActiveMessaging actually forcefully loads
# all processors before initializers are run. Hopefully this can go away
# when the vendored ActiveMessaging plugin is removed.
require File.join(Rails.root, "config/initializers/messaging")

class PushProcessor
  include Gitorious::Messaging::Consumer
  consumes "/queue/GitoriousPush"
  attr_reader :user, :repository, :spec

  include Patchwork
  include Emailer

  unless const_defined? :GIT_PRETTY_FORMAT
    PUSH_EVENT_GIT_OUTPUT_SEPARATOR = "\t"
    PUSH_EVENT_GIT_OUTPUT_SEPARATOR_ESCAPED = "\\\t"
    GIT_PRETTY_FORMAT = "format:#{['%H','%cn <%ce>','%at','%s','%an'].join(PUSH_EVENT_GIT_OUTPUT_SEPARATOR)}"
  end

  def on_message(message)
    load_message(message)
    log_message("Got payload: #{spec} from user #{user && user.login}")

    if spec.merge_request?
      log_message("Processing merge request")
      process_merge_request
    elsif repository.wiki?
      log_message("Processing wiki update")
      process_wiki_update
    else
      log_message("Processing regular push")
      process_push
    end
  end

  def process_merge_request
    return if spec.action_delete?
    merge_request.update_from_push!
  end

  def process_push
    ensure_user
    log = PushEventLogger.new(repository, spec, user)
    log.create_push_event if log.create_push_event?
    log.create_meta_event if log.create_meta_event?
    repository.register_push
    repository.save
    trigger_hooks unless repository.hooks.blank?

    if spec.head? && spec.action_update?
      begin
        notify
      rescue => e
        logger.error("Notification failed: #{e.class.name} #{e.message}:\n #{e.backtrace.join("\n  ")}")
      end
    end
  end

  def notify
    commits = []

    repository.git.git.log(
        {:pretty => GIT_PRETTY_FORMAT, :s => true, :timeout => false},
        "#{spec.from_sha.sha}..#{spec.to_sha.sha}").split("\n").each do |commit|
      sha, email, timestamp, message, author = commit.split(PUSH_EVENT_GIT_OUTPUT_SEPARATOR_ESCAPED)
      commits.push({
        :sha => sha,
        :timestamp => Time.at(timestamp.to_i).utc,
        :user => user,
        :author => author,
        :message => message,
      })
    end

    notify_patchwork(repository, spec.ref.name, commits) if GitoriousConfig["patchwork"]
    notify_emailer(repository, spec.ref.name, commits) if GitoriousConfig["emailer"]
  end

  def trigger_hooks
    generator = Gitorious::WebHookGenerator.new(repository, spec, user)
    generator.generate!
  end

  def process_wiki_update
    ensure_user
    logger = Gitorious::Wiki::UpdateEventLogger.new(repository, spec, user)
    logger.create_wiki_events
  end

  def load_message(message)
    @user = User.find_by_login(message["username"])
    @repository = Repository.find_by_hashed_path(message["gitdir"])
    @spec = PushSpecParser.new(*message["message"].split(" "))
  end

  private
  
  def merge_request
    @repository.merge_requests.find_by_sequence_number!(@spec.ref_name.to_i)
  end

  def ensure_user
    raise "Username was nil" if user.nil?
  end

  def log_message(message)
    logger.info("#{Time.now.to_s(:short)} #{message}")
  end
end