Class: Ditz::Issue

Inherits:
ModelObject show all
Defined in:
lib/ditz/plugins/issue-labeling.rb,
lib/ditz/plugins/git.rb,
lib/ditz/model-objects.rb,
lib/ditz/plugins/mercurial.rb,
lib/ditz/plugins/issue-claiming.rb,
lib/ditz/plugins/issue-timetracker.rb

Overview

class Project

Defined Under Namespace

Classes: Error

Constant Summary collapse

INTERPOLATED_FIELDS =

these are the fields we interpolate issue names on INTERPOLATED_FIELDS = [:title, :desc, :log_events]

[]
STATUS_SORT_ORDER =
{ :unstarted => 2, :paused => 1, :in_progress => 0, :closed => 3 }
STATUS_WIDGET =
{ :unstarted => "_", :in_progress => ">", :paused => "=", :closed => "x" }
DISPOSITIONS =
[ :fixed, :wontfix, :reorg ]
TYPES =
[ :bugfix, :feature, :task ]
TYPE_ORDER =
{ :bugfix => 0, :feature => 1, :task => 2 }
TYPE_LETTER =
{ 'b' => :bugfix, 'f' => :feature, 't' => :task }
STATUSES =
STATUS_WIDGET.keys
STATUS_STRINGS =
{ :in_progress => "in progress", :wontfix => "won't fix" }
DISPOSITION_STRINGS =
{ :wontfix => "won't fix", :reorg => "reorganized" }

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from ModelObject

#changed!, #changed?, changes_are_logged, create, create_interactively, #each_modelobject, field, field_names, from, inherited, #initialize, #inspect, #save!, #to_s, #to_yaml, #to_yaml_type, #unchanged!, yaml_domain, yaml_other_thing

Constructor Details

This class inherits a constructor from Ditz::ModelObject

Instance Attribute Details

#nameObject

Returns the value of attribute name.



166
167
168
# File 'lib/ditz/model-objects.rb', line 166

def name
  @name
end

#pathnameObject

Returns the value of attribute pathname.



166
167
168
# File 'lib/ditz/model-objects.rb', line 166

def pathname
  @pathname
end

#projectObject

Returns the value of attribute project.



166
167
168
# File 'lib/ditz/model-objects.rb', line 166

def project
  @project
end

Instance Method Details

#apply_labels(new_labels, who, comment) ⇒ Object



62
63
64
65
# File 'lib/ditz/plugins/issue-labeling.rb', line 62

def apply_labels new_labels, who, comment
  new_labels.each { |l| add_label l }
  log "issue labeled", who, comment
end

#assign_to_component(component, who, comment) ⇒ Object



293
294
295
296
# File 'lib/ditz/model-objects.rb', line 293

def assign_to_component component, who, comment
  log "assigned to component #{component.name} from #{self.component}", who, comment
  self.component = component.name
end

#assign_to_release(release, who, comment) ⇒ Object



288
289
290
291
# File 'lib/ditz/model-objects.rb', line 288

def assign_to_release release, who, comment
  log "assigned to release #{release.name} from #{self.release || 'unassigned'}", who, comment
  self.release = release.name
end

#assigned?Boolean

Returns:

  • (Boolean)


239
# File 'lib/ditz/model-objects.rb', line 239

def assigned?; !unassigned? end

#bug?Boolean

Returns:

  • (Boolean)


236
# File 'lib/ditz/model-objects.rb', line 236

def bug?; type == :bugfix end

#change(hash, who, comment, silent) ⇒ Object



263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/ditz/model-objects.rb', line 263

def change hash, who, comment, silent
  what = []
  if title != hash[:title]
    what << "title"
    self.title = hash[:title]
  end

  if desc != hash[:description]
    what << "description"
    self.desc = hash[:description]
  end

  if reporter != hash[:reporter]
    what << "reporter"
    self.reporter = hash[:reporter]
  end

  unless what.empty? || silent
    log "edited " + what.join(", "), who, comment
    true
  end

  !what.empty?
end

#claim(who, comment, force = false) ⇒ Object

Raises:



35
36
37
38
39
# File 'lib/ditz/plugins/issue-claiming.rb', line 35

def claim who, comment, force=false
  raise Error, "already claimed by #{claimer}" if claimer && !force
  log "issue claimed", who, comment
  self.claimer = who
end

#claimed?Boolean

Returns:

  • (Boolean)


52
# File 'lib/ditz/plugins/issue-claiming.rb', line 52

def claimed?; claimer end

#close(disp, who, comment) ⇒ Object

Raises:



248
249
250
251
252
253
# File 'lib/ditz/model-objects.rb', line 248

def close disp, who, comment
  raise Error, "unknown disposition #{disp}" unless DISPOSITIONS.member? disp
  log "closed with disposition #{disp}", who, comment
  self.status = :closed
  self.disposition = disp
end

#closed?Boolean

Returns:

  • (Boolean)


232
# File 'lib/ditz/model-objects.rb', line 232

def closed?; status == :closed end

#deserialized_form_of(field, value) ⇒ Object



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/ditz/model-objects.rb', line 200

def deserialized_form_of field, value
  return super unless INTERPOLATED_FIELDS.member? field

  if field == :log_events
    value.map do |time, who, what, comment|
      comment = @project.issues.inject(comment) do |s, i|
        s.gsub(/\{issue #{i.id}\}/, i.name)
      end.gsub(/\{issue \w+\}/, "[unknown issue]")
      [time, who, what, comment]
    end
  else
    @project.issues.inject(value) do |s, i|
      s.gsub(/\{issue #{i.id}\}/, i.name)
    end.gsub(/\{issue \w+\}/, "[unknown issue]")
  end
end

#disposition_stringObject



230
# File 'lib/ditz/model-objects.rb', line 230

def disposition_string; DISPOSITION_STRINGS[disposition] || disposition.to_s end

#feature?Boolean

Returns:

  • (Boolean)


237
# File 'lib/ditz/model-objects.rb', line 237

def feature?; type == :feature end

#get_component(config, project) ⇒ Object



309
310
311
312
313
314
315
# File 'lib/ditz/model-objects.rb', line 309

def get_component config, project
  if project.components.size == 1
    project.components.first
  else
    ask_for_selection project.components, "component", :name
  end.name
end

#get_labels(config, project) ⇒ Object



58
59
60
# File 'lib/ditz/plugins/issue-labeling.rb', line 58

def get_labels config, project
  ask_for_selection(project.labels, "label", :name, true).map {|x|x}
end

#get_mark_time(config, project) ⇒ Object



11
12
13
# File 'lib/ditz/plugins/issue-timetracker.rb', line 11

def get_mark_time(config, project)
  self.mark_time || 0
end

#get_release(config, project) ⇒ Object



317
318
319
320
321
322
323
324
325
326
327
328
# File 'lib/ditz/model-objects.rb', line 317

def get_release config, project
  releases = project.releases.select { |r| r.unreleased? }
  if !releases.empty? && ask_yon("Assign to a release now?")
    if releases.size == 1
      r = releases.first
      puts "Assigning to release #{r.name}."
      r
    else
      ask_for_selection releases, "release", :name
    end.name
  end
end

#get_reporter(config, project) ⇒ Object



330
331
332
# File 'lib/ditz/model-objects.rb', line 330

def get_reporter config, project
  reporter = ask "Creator", :default => config.user
end

#get_time_spent(config, project) ⇒ Object



8
9
10
# File 'lib/ditz/plugins/issue-timetracker.rb', line 8

def get_time_spent(config, project)
  time_spent || 0
end

#get_type(config, project) ⇒ Object



304
305
306
307
# File 'lib/ditz/model-objects.rb', line 304

def get_type config, project
  type = ask "Is this a (b)ugfix, a (f)eature, or a (t)ask?", :restrict => /^[bft]$/
  TYPE_LETTER[type]
end

#git_commitsObject



35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/ditz/plugins/git.rb', line 35

def git_commits
  return @git_commits if @git_commits

  filters = ["--grep=\"Ditz-issue: #{id}\""]
  filters << "master..#{git_branch}" if git_branch

  output = filters.map do |f|
    `git log --pretty=format:\"%aD\t%an <%ae>\t%h\t%s\" #{f} 2> /dev/null`
  end.join

  @git_commits = output.split(/\n/).map { |l| l.split("\t") }.
    map { |date, email, hash, msg| [Time.parse(date).utc, email, hash, msg] }
end

#hg_commitsObject



5
6
7
8
9
10
11
12
13
# File 'lib/ditz/plugins/mercurial.rb', line 5

def hg_commits
  return @hg_commits if @hg_commits
  output = `hg log --template '{date|rfc822date}\t{author}\t{node|short}\t{desc|firstline}\n' --keyword '#{id}'`

  @hg_commits = output.split("\n").map {|line|
    date, *vals = line.split("\t")
    [Time.parse(date), *vals]
  }
end

#in_progress?Boolean

Returns:

  • (Boolean)


234
# File 'lib/ditz/model-objects.rb', line 234

def in_progress?; status == :in_progress end

#labeled?(label = nil) ⇒ Boolean

Returns:

  • (Boolean)


76
# File 'lib/ditz/plugins/issue-labeling.rb', line 76

def labeled? label=nil; (label.nil?)? !labels.empty? : labels.include?(label) end

#make_id(config, project) ⇒ Object

make a unique id



218
219
220
221
222
223
224
# File 'lib/ditz/model-objects.rb', line 218

def make_id config, project
  if RUBY_VERSION >= '1.9.0'
    Digest::SHA1.hexdigest [Time.now, rand, creation_time, reporter, title, desc].join("\n")
  else
    SHA1.hexdigest [Time.now, rand, creation_time, reporter, title, desc].join("\n")
  end
end

#old_start_workObject



4
# File 'lib/ditz/plugins/issue-timetracker.rb', line 4

def start_work who, comment; change_status :in_progress, who, comment end

#old_stop_workObject

Raises:



5
6
7
8
# File 'lib/ditz/plugins/issue-timetracker.rb', line 5

def stop_work who, comment
  raise Error, "unstarted" unless self.status == :in_progress
  change_status :paused, who, comment
end

#open?Boolean

Returns:

  • (Boolean)


233
# File 'lib/ditz/model-objects.rb', line 233

def open?; !closed? end

#paused?Boolean

Returns:

  • (Boolean)


240
# File 'lib/ditz/model-objects.rb', line 240

def paused?; status == :paused end

#remove_labels(labels_to_remove, who, comment) ⇒ Object



67
68
69
70
71
72
73
74
# File 'lib/ditz/plugins/issue-labeling.rb', line 67

def remove_labels labels_to_remove, who, comment
  log "issue unlabeled", who, comment
  if labels_to_remove.nil?
    self.labels = []
  else
    labels_to_remove.each { |l| drop_label l }
  end
end

#serialized_form_of(field, value) ⇒ Object



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/ditz/model-objects.rb', line 183

def serialized_form_of field, value
  return super unless INTERPOLATED_FIELDS.member? field

  if field == :log_events
    value.map do |time, who, what, comment|
      comment = @project.issues.inject(comment || '') do |s, i|
        s.gsub(/\b#{i.name}\b/, "{issue #{i.id}}")
      end
      [time, who, what, comment]
    end
  else
    @project.issues.inject(value || '') do |s, i|
      s.gsub(/\b#{i.name}\b/, "{issue #{i.id}}")
    end
  end
end

#sort_orderObject



226
# File 'lib/ditz/model-objects.rb', line 226

def sort_order; [STATUS_SORT_ORDER[status], creation_time] end

#start_work(who, comment) ⇒ Object



242
# File 'lib/ditz/model-objects.rb', line 242

def start_work who, comment; change_status :in_progress, who, comment end

#status_stringObject



229
# File 'lib/ditz/model-objects.rb', line 229

def status_string; STATUS_STRINGS[status] || status.to_s end

#status_widgetObject



227
# File 'lib/ditz/model-objects.rb', line 227

def status_widget; STATUS_WIDGET[status] end

#stop_work(who, comment) ⇒ Object

Raises:



243
244
245
246
# File 'lib/ditz/model-objects.rb', line 243

def stop_work who, comment
  raise Error, "unstarted" unless self.status == :in_progress
  change_status :paused, who, comment
end

#unassign(who, comment) ⇒ Object

Raises:



298
299
300
301
302
# File 'lib/ditz/model-objects.rb', line 298

def unassign who, comment
  raise Error, "not assigned to a release" unless release
  log "unassigned from release #{release}", who, comment
  self.release = nil
end

#unassigned?Boolean

Returns:

  • (Boolean)


238
# File 'lib/ditz/model-objects.rb', line 238

def unassigned?; release.nil? end

#unclaim(who, comment, force = false) ⇒ Object

Raises:



41
42
43
44
45
46
47
48
49
50
# File 'lib/ditz/plugins/issue-claiming.rb', line 41

def unclaim who, comment, force=false
  raise Error, "not claimed" unless claimer
  raise Error, "can only be unclaimed by #{claimer}" unless claimer == who || force
  if claimer == who
    log "issue unclaimed", who, comment
  else
    log "unclaimed from #{claimer}", who, comment
  end
  self.claimer = nil
end

#unclaimed?Boolean

Returns:

  • (Boolean)


53
# File 'lib/ditz/plugins/issue-claiming.rb', line 53

def unclaimed?; !claimed? end

#unlabeled?(label = nil) ⇒ Boolean

Returns:

  • (Boolean)


77
# File 'lib/ditz/plugins/issue-labeling.rb', line 77

def unlabeled? label=nil; !labeled?(label) end

#unstarted?Boolean

Returns:

  • (Boolean)


235
# File 'lib/ditz/model-objects.rb', line 235

def unstarted?; !in_progress? end

#validate!(whence, context) ⇒ Object

we only have to check beyond what ModelObject.create already checks



156
157
158
159
160
161
162
163
164
# File 'lib/ditz/model-objects.rb', line 156

def validate! whence, context
  config, project = context
  if whence == :create
    raise ModelError, "title is empty" unless title =~ /\S/
    raise ModelError, "invalid type #{type.inspect}" unless TYPES.member?(type)
    raise ModelError, "invalid status #{status.inspect}" unless STATUSES.member?(status)
    raise ModelError, "#{type}s can't be added to already-released releases" if release && [:feature, :task].include?(type) && project.release_for(release).released?
  end
end