bugmail.rb

Carl Nygard, 2008-04-25 20:31

Download (6.29 KB)

 
1
#!/usr/bin/env ruby
2

    
3
RAILS_ENV = 'test'
4
REDMINE_ROOT = '/var/www/html/redmine/'
5
# This does _NOT_ work. I looked back 3 revisions and found the correct line
6
#require File.dirname(__FILE__) + '/../config/boot'
7
require REDMINE_ROOT + 'config/environment'
8

    
9
require 'getoptlong'
10

    
11
class BugMail
12

    
13
  attr_accessor :issue, :desc, :subject, :category, :project, :status, 
14
      :tracker, :priority, :author, :email, :allow_override, 
15
      :use_email_header, :input, :debug
16

    
17
  def initialize
18

    
19
    @issue = nil
20
    @desc = nil
21
    @subject = nil
22
    @category = nil
23
    @project = nil
24
    @status = nil
25
    @tracker = 'Bug'
26
    @priority = nil
27
    @author = nil
28
    @email = nil
29
    @allow_override = false
30
    @use_email_header = false
31
    @debug = false
32
  end
33

    
34
  def process(msg)
35
    @issue = line_match(msg, "Issue", @issue)
36
    @subject = line_match(msg, "Subject", @subject)
37
# we can generalize via mail-aliases setup to be <project>@<fqdn>
38
    @project = match(msg, /^To:.*?(\w+)@.*$/, @project) if(@use_email_header)
39
    @project = line_match(msg, "Project", @project)
40
    @status = line_match(msg, "Status", @status)
41
    @tracker = line_match(msg, "Tracker", @racker)
42
    @priority = line_match(msg, "Priority", @priority)
43
    @category = line_match(msg, "Category", @category)
44
    @email = match(msg, /^From:.*?(\w+@[A-Za-z0-9.-]+).*?$/, @email) if(@use_email_header)
45
    @author = line_match(msg, "Author", @author)
46

    
47
    @desc = block_match(msg, "Description", @desc)
48

    
49
    puts "Issue: [#{@issue}]" if @debug
50
    puts "Project: [#{@project}]" if @debug
51
    puts "Subject: [#{@subject}]" if @debug
52
    puts "Tracker: [#{@tracker}]" if @debug
53
    puts "Priority: [#{@priority}]" if @debug
54
    puts "Category: [#{@category}]" if @debug
55
    puts "Status: [#{@status}]" if @debug
56
    puts "Author/email: [#{@author}/#{@email}]" if @debug
57
    puts "Desc: [#{@desc}]" if @debug
58

    
59
    ic = Iconv.new('UTF-8', 'UTF-8')
60

    
61
    p = Project.find_by_identifier(@project)
62
    if(! p) 
63
      puts 'Unable to find project [#{@project}]'
64
      return false
65
    end
66

    
67
    priorities = Enumeration.get_values('IPRI')
68
    @DEFAULT_PRIORITY = priorities[0]
69
    @DEFAULT_TRACKER = p.trackers.find_by_position(1) || Tracker.find_by_position(1)
70
    @PRIORITY_MAPPING = {}
71
    priorities.each { |prio| @PRIORITY_MAPPING[prio.name] = prio }
72

    
73
    puts "Searching for user [#{author}/#{email}]" if debug
74

    
75
    u = User.find_by_login(@author)
76
    if(! u && @use_email_header)
77
      puts "Searching for user via email: [#{@email}]" if @debug
78
      u = User.find_by_mail(@email)
79
    end
80

    
81
    if(!u)
82
      puts "Unable to find user"
83
      return false
84
    else
85
      puts "Found user [#{u.login}/#{u.mail}]"
86
    end
87

    
88
    puts "Searching for issue [#{@issue}]" if @debug
89
    i = Issue.find_by_id(@issue)
90

    
91
    if(i == nil) 
92
      prio = @PRIORITY_MAPPING[@priority] || @DEFAULT_PRIORITY
93
      st = IssueStatus.find_by_name(@status) || IssueStatus.default
94
      t = p.trackers.find_by_name(@tracker) || @DEFAULT_TRACKER
95
      c = p.issue_categories.find_by_name(@category)
96
      i = Issue.create( :priority => prio,
97
                        :status => st,
98
                        :tracker => t,
99
                        :project => p,
100
                        :category => c,
101
                        :start_date => Date.today,
102
                        :author => u,
103
                        :description => ic.iconv(@desc),
104
                        :subject => ic.iconv(@subject) )
105
      puts "Created issue [#{i.id}] [#{i.to_yaml}]" if @debug
106

    
107
      if(!i.save)
108
        puts "Failed to save new issue"
109
        exit 1 
110
      end
111
    else
112
      puts "Issue exists, adding comment..."
113
      n = Journal.new(:notes => ic.iconv(@desc),
114
                      :journalized => i,
115
                      :user => u);
116
      if(!n.save)
117
        puts "Failed to add comment"
118
        return false
119
      end
120
    end
121

    
122
    return true
123
  end
124

    
125
private
126
  def match(msg, regex, default)
127
    if((@allow_override || default == nil) && (msg =~ regex))
128
      return $1
129
    end
130
    return default
131
  end
132

    
133

    
134
  def line_match(msg, label, default)
135
    return match(msg, /^#{label}:[ \t]*(.*)$/, default)
136
  end
137

    
138
  def block_match(msg, label, default)
139
    return match(msg, /^#{label}:[ \t]*(.*)$/m, default)
140
  end
141

    
142
end
143

    
144
opts = GetoptLong.new(
145
      [ '--help', '-h', GetoptLong::NO_ARGUMENT ],
146
      [ '--debug', GetoptLong::NO_ARGUMENT ],
147
      [ '--issue', '-i', GetoptLong::REQUIRED_ARGUMENT ],
148
      [ '--desc', '-d', GetoptLong::REQUIRED_ARGUMENT ],
149
      [ '--subject', '-s', GetoptLong::REQUIRED_ARGUMENT ],
150
      [ '--category', '-c', GetoptLong::REQUIRED_ARGUMENT ],
151
      [ '--project', '-p', GetoptLong::REQUIRED_ARGUMENT ],
152
      [ '--tracker', '-t', GetoptLong::REQUIRED_ARGUMENT ],
153
      [ '--status', GetoptLong::REQUIRED_ARGUMENT ],
154
      [ '--priority', GetoptLong::REQUIRED_ARGUMENT ],
155
      [ '--author', '-a',  GetoptLong::REQUIRED_ARGUMENT ],
156
      [ '--file', '-f',  GetoptLong::REQUIRED_ARGUMENT ],
157
      [ '--allow-override',  GetoptLong::NO_ARGUMENT ],
158
      [ '--use-email-header',  GetoptLong::NO_ARGUMENT ]
159
    )
160

    
161
def usage
162
  puts "Usage: [--help] [--debug] [--allow-override] [--use-email-header] [--file <filename> ] [--<param> <value> ...]"
163
  puts " --help  show this help"
164
  puts " --debug show extra debug information"
165
  puts " --allow-override   allow message contents to override cmd line args"
166
  puts " --use-email-header search in email header for user, subject and project"
167
  puts " --file      get input from a file instead of STDIN"
168
  puts " --<param>   set a parameter's value.  Parameter is one of:"
169
  puts "             issue, project, subject, desc, status, tracker, priority"
170
  puts "             category, author"
171
  exit
172
end
173

    
174
input = $stdin
175
mailer = BugMail.new
176

    
177
opts.each do |opt, arg|
178
  case opt
179
  when '--help'
180
    usage
181
  when '--issue'
182
    mailer.issue = arg.to_i
183
  when '--project'
184
    mailer.project = arg
185
  when '--subject'
186
    mailer.subject = arg
187
  when '--desc'
188
    mailer.desc = arg
189
  when '--status'
190
    mailer.status = arg
191
  when '--tracker'
192
    mailer.tracker = arg
193
  when '--priority'
194
    mailer.priority = arg
195
  when '--category'
196
    mailer.category = arg
197
  when '--author'
198
    mailer.author = arg
199
  when '--file'
200
    input = FILE.open(arg, "r")
201
  when '--debug'
202
    mailer.debug = true
203
  when '--allow-override'
204
    mailer.allow_override = true
205
  when '--use-email-header'
206
    mailer.use_email_header = true
207
  end
208
end
209

    
210
msg = input.read
211

    
212
mailer.process(msg)
213