1
#!/usr/bin/env ruby -KU
2
3
ENV["PATH"] = "/usr/local/bin/:/opt/local/bin:#{ENV["PATH"]}"
4
ENV["RAILS_ENV"] ||= "production"
5
6
require File.dirname(__FILE__) + "/../config/environment"
7
8
abort("Usage: #{$0} repo_id") unless ARGV[0]
9
10
$stdout.sync = true
11
12
def create_repo_creation_events_for(project)
13
  project.repository_clones.each do |repo|
14
    puts "creating Repository clone event in #{project.slug}/#{repo.name}"
15
   project.events.create({
16
     :action => Action::CLONE_REPOSITORY,
17
     :target => repo,
18
     :user => repo.user,
19
     :data => repo.parent_id,
20
     :created_at => repo.created_at
21
   })
22
  end
23
end
24
25
def create_comment_events_for(repo, project)
26
  repo.comments.each do |comment| 
27
    puts "creating Comment event on #{project.slug}/#{repo.name}"
28
    project.events.create({
29
      :action => Action::COMMENT,
30
      :target => comment,
31
      :user => comment.user,
32
      :created_at => comment.created_at
33
    })
34
  end
35
end
36
37
def create_merge_request_events_for(repo, project)
38
  repo.merge_requests.each do |mr|
39
    puts "creating MergeRequest event on #{project.slug}/#{repo.name}"
40
    project.events.create({
41
      :action => Action::REQUEST_MERGE,
42
      :target => mr,
43
      :user => mr.user,
44
      :created_at => mr.created_at,
45
    })
46
    unless mr.open?
47
      puts "creating MergeRequest resolvement event on #{project.slug}/#{repo.name}"
48
      project.events.create({
49
        :action => Action::RESOLVE_MERGE_REQUEST,
50
        :target => mr,
51
        :user => mr.user,
52
        :data => mr.status_string,
53
        :created_at => mr.created_at,
54
      })
55
    end
56
  end
57
end
58
59
def create_events_for_repository(repo, project)
60
  tag_map = repo.git.tags.inject({}){|hsh, t| hsh[t.commit.id] = t.name;hsh}
61
62
  parsed_commits = {} # Neccesary because of merge
63
  repo.git.heads.each do |head|
64
    users_commits = {}
65
  
66
    Grit::Commit.find_all(repo.git, head.name, {:since => "1 year ago"}).each do |commit|
67
      users_commits[commit.committer.email] ||= []
68
      users_commits[commit.committer.email] << commit
69
    end
70
    
71
    users = User.find(:all, :conditions => ['email in (?)', users_commits.keys] )
72
    users.each do |user|
73
      commits = users_commits[user.email]
74
      puts "\nindexing #{commits.size} commits for #{user.email} in #{project.slug}/#{repo.name}:#{head.name}"
75
      commits.each_index do |i|
76
        commit = commits[i]
77
        previous_commit = commits[i-1]
78
      
79
        newrev = commit.id
80
        next if parsed_commits.has_key?(newrev)
81
        parsed_commits[newrev] = true
82
      
83
        oldrev = previous_commit.id if previous_commit
84
        current_rev = newrev
85
        newtype = oldtype = current_rev_type = "commit"
86
      
87
        type = repo.git.git.name_rev({}, newrev).last.split("/").first
88
        if type != "tags"
89
          type = "heads"
90
        end
91
      
92
        action = :create
93
        if !oldrev
94
          action = :create
95
        else
96
          if commit.id =~ /^0+$/
97
            action = :delete
98
          else
99
            action = :update
100
          end
101
        end
102
103
        if action != :delete
104
          newtype = repo.git.git.cat_file({:t => true}, newrev)
105
        end
106
107
        if action == :update
108
          oldtype = repo.git.git.cat_file({:t => true}, oldrev)
109
        end
110
111
        if action == :delete
112
            current_rev = oldrev
113
            current_rev_type = oldtype
114
        end
115
      
116
117
      
118
        action_id = nil
119
        ref = nil
120
      
121
        if current_rev_type == "commit"
122
          if type == "heads"
123
            case action
124
              when :create
125
                action_id = Action::CREATE_BRANCH
126
                ref = head.name
127
              when :update
128
                action_id = Action::COMMIT
129
                ref = current_rev
130
              when :delete
131
                action_id = Action::DELETE_BRANCH
132
                ref = head.name
133
            end
134
          elsif type == "tags"
135
            if action == :create
136
              action_id = Action::CREATE_TAG
137
              ref = tag_map[commit.id]
138
            elsif action == :delete
139
              action_id = Action::DELETE_TAG
140
              ref = tag_map[commit.id]
141
            end
142
          end
143
        elsif current_rev_type == "tag"
144
          if type == "tags"
145
            if action == :create
146
              action_id = Action::CREATE_TAG
147
              ref = tag_map[commit.id]
148
            elsif action == :delete
149
              action_id = Action::DELETE_TAG
150
              ref = tag_map[commit.id]
151
            end
152
          end
153
        end
154
      
155
        print "." if (i % 10 == 1)
156
        #puts "#{current_rev_type}#{action.inspect} in #{project.slug}/#{repo.name}:#{head.name}: #{commit.short_message}"
157
        project.events.create({
158
          :action => action_id || Action::COMMIT, 
159
          :target => repo, 
160
          :user => user, 
161
          :body => commit.message, 
162
          :data => commit.id,
163
          :created_at => commit.committed_date})
164
      end
165
      commits = nil
166
      puts
167
    end
168
    users_commits = nil
169
  end
170
  parsed_commits = nil
171
end
172
173
def rebuild_project!(project)
174
  puts "Destroying existing events on #{project.slug}"
175
  project.events.destroy_all
176
177
  project.repositories.each do |repo|
178
    create_events_for_repository(repo, project)
179
    create_comment_events_for(repo, project)
180
    create_merge_request_events_for(repo, project)
181
  end
182
  create_repo_creation_events_for(project)
183
end
184
185
case ARGV[0]
186
when "all"
187
  Project.find(:all).each do |project|
188
    puts 
189
    puts "rebuilding #{project.slug}"
190
    puts
191
    begin
192
      rebuild_project!(project)
193
      GC.start
194
    rescue
195
      puts "!!! failed to rebuild #{project.slug} !!!"
196
      puts "#{e.class}:#{e.message} \n#{e.backtrace.join("\n  ")}"
197
      puts
198
      next
199
    end
200
  end
201
else
202
  project = Project.find(ARGV[0])
203
  rebuild_project!(project) if project
204
end