Class: PivoFlow::Pivotal

Inherits:
Base
  • Object
show all
Defined in:
lib/pivo_flow/pivotal.rb

Constant Summary

Constants inherited from Base

Base::GIT_DIR, Base::KEYS_AND_QUESTIONS

Instance Attribute Summary

Attributes inherited from Base

#options

Instance Method Summary collapse

Methods inherited from Base

#git_directory_present?, #git_hook_needed?, #initialize, #install_git_hook, #pf_git_hook_valid?, #reconfig, #user_name

Constructor Details

This class inherits a constructor from PivoFlow::Base

Instance Method Details

#create_branch(story_id) ⇒ Object



229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/pivo_flow/pivotal.rb', line 229

def create_branch story_id
  story = find_story(story_id)
  if story.nil?
    puts "Sorry, this story is not found (#{story_id})"
    return
  end

  ticket_name = story.name.tr('^A-Za-z0-9 ', '').tr(' ', '-')
  branch_name = [story.id, ticket_name].join("-")

  git_create_branch(branch_name)
end

#current_story(force = false) ⇒ Object



44
45
46
47
48
49
50
# File 'lib/pivo_flow/pivotal.rb', line 44

def current_story force = false
  if (@options[:current_story] && !force)
    @options[:current_story]
  else
    @options[:current_story] = user_stories.count.zero? ? nil : user_stories.first
  end
end

#deliverObject



69
70
71
# File 'lib/pivo_flow/pivotal.rb', line 69

def deliver
  list_stories_to_output finished_stories, "deliver"
end

#deliver_story(story_id) ⇒ Object



250
251
252
# File 'lib/pivo_flow/pivotal.rb', line 250

def deliver_story story_id
  update_story(story_id, :delivered)
end

#ensure_project(&block) ⇒ Object



13
14
15
16
17
18
19
20
21
22
# File 'lib/pivo_flow/pivotal.rb', line 13

def ensure_project(&block)
  begin
    @options[:project] ||= PivotalTracker::Project.find(@options["project-id"])
    block.call
  rescue Exception => e
    message = "Pivotal Tracker: #{e.message}\n" +
    "[TIPS] It means that your configuration is wrong. You can reset your settings by running:\n\tpf reconfig"
    raise PivoFlow::Errors::UnsuccessfulPivotalConnection, message
  end
end

#estimate_points(story) ⇒ Object



200
201
202
203
204
205
206
# File 'lib/pivo_flow/pivotal.rb', line 200

def estimate_points story
  unless story.estimate.nil?
    story.estimate < 0 ? "?" : story.estimate
  else
    "-"
  end
end

#fetch_stories(count = 100, state = "unstarted,started,unscheduled,rejected", story_type = "feature,chore,bug") ⇒ Object



268
269
270
271
272
273
# File 'lib/pivo_flow/pivotal.rb', line 268

def fetch_stories(count = 100, state = "unstarted,started,unscheduled,rejected", story_type = "feature,chore,bug")
  ensure_project do
    conditions = { current_state: state, limit: count, story_type: story_type }
    @options[:stories] = @options[:project].stories.all(conditions)
  end
end

#find_story(story_id) ⇒ Object



99
100
101
102
# File 'lib/pivo_flow/pivotal.rb', line 99

def find_story story_id
  story = project_stories.find { |p| p.id == story_id.to_i }
  story.nil? ? @options[:project].stories.find(story_id) : story
end

#finish_story(story_id) ⇒ Object



246
247
248
# File 'lib/pivo_flow/pivotal.rb', line 246

def finish_story story_id
  remove_story_id_file if story_id.nil? or update_story(story_id, :finished)
end

#finished_storiesObject



40
41
42
# File 'lib/pivo_flow/pivotal.rb', line 40

def finished_stories
  fetch_stories(10, "finished").select{ |story| story.owned_by == user_name }
end

#git_create_branch(name) ⇒ Object



275
276
277
# File 'lib/pivo_flow/pivotal.rb', line 275

def git_create_branch(name)
  system("git checkout -b #{name}")
end

#initials(name) ⇒ Object



196
197
198
# File 'lib/pivo_flow/pivotal.rb', line 196

def initials name
  name.split.map{ |n| n[0] }.join
end

#list_stories_to_output(stories, activity = "start") ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/pivo_flow/pivotal.rb', line 52

def list_stories_to_output stories, activity="start"
  if (stories.nil? || stories.empty?)
    puts "No stories to show"
    return 1
  end

  HighLine.new.choose do |menu|
    menu.header = "\n--- STORIES FROM PIVOTAL TRACKER ---\nWhich one would you like to #{activity}?   "
    menu.prompt = "story no.? "
    menu.select_by = :index
    stories.each do |story|
      menu.choice(story_string(story).fix_encoding) { |answer| show_story(answer.match(/\[#(?<id>\d+)\]/)[:id])}
    end
    menu.choice("Show all") { show_stories(100) }
  end
end

#note_string(note) ⇒ Object



164
165
166
# File 'lib/pivo_flow/pivotal.rb', line 164

def note_string note
  "\t[#{note.noted_at.to_time}] (#{note.author}) #{note.text}"
end

#other_users_storiesObject



32
33
34
# File 'lib/pivo_flow/pivotal.rb', line 32

def other_users_stories
  project_stories.select{ |story| story.owned_by != user_name }
end

#pick_up_story(story_id) ⇒ Object



208
209
210
# File 'lib/pivo_flow/pivotal.rb', line 208

def pick_up_story story_id
  save_story_id_to_file(story_id) if start_story(story_id)
end


160
161
162
# File 'lib/pivo_flow/pivotal.rb', line 160

def print_notes notes
  notes.each { |note| puts note_string(note) }
end


156
157
158
# File 'lib/pivo_flow/pivotal.rb', line 156

def print_tasks tasks
  tasks.each { |task| puts task_string(task) }
end

#project_storiesObject



28
29
30
# File 'lib/pivo_flow/pivotal.rb', line 28

def project_stories
  @options[:stories] ||= fetch_stories
end

#remove_story_id_fileObject



254
255
256
# File 'lib/pivo_flow/pivotal.rb', line 254

def remove_story_id_file
  FileUtils.remove_file(@story_id_file_path)
end

#runObject



4
5
6
7
8
9
10
11
# File 'lib/pivo_flow/pivotal.rb', line 4

def run
  @story_id_file_name = ".pivotal_story_id"
  @story_id_tmp_path = File.join(@current_dir, "/tmp")
  @story_id_file_path = File.join(@story_id_tmp_path, @story_id_file_name)

  PivotalTracker::Client.token = @options["api-token"]
  PivotalTracker::Client.use_ssl = true
end

#save_story_id_to_file(story_id) ⇒ Object



258
259
260
261
# File 'lib/pivo_flow/pivotal.rb', line 258

def save_story_id_to_file story_id
  FileUtils.mkdir_p(@story_id_tmp_path)
  File.open(@story_id_file_path, 'w') { |f| f.write(story_id) }
end

#show_info(story = nil) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/pivo_flow/pivotal.rb', line 86

def show_info story=nil
  story = story || current_story
  if story.nil?
    puts "No story, no worry..."
    return 1
  end
  puts story_string(story, true)
  puts "\n[TASKS]"
  story.tasks.all.count.zero? ? puts("        no tasks") : print_tasks(story.tasks.all)
  puts "\n[NOTES]"
  story_notes(story).count.zero? ? puts("        no notes") : print_notes(story_notes(story))
end

#show_stories(count = 9) ⇒ Object



263
264
265
266
# File 'lib/pivo_flow/pivotal.rb', line 263

def show_stories count=9
  stories = user_stories + other_users_stories
  list_stories_to_output stories.first(count)
end

#show_story(story_id) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/pivo_flow/pivotal.rb', line 73

def show_story story_id
  story = find_story(story_id)
  show_info story
  ask_for = story.current_state == "finished" ? "deliver" : "start"
  proceed = ask_question "Do you want to #{ask_for} this story?"
  accepted_answers = %w[yes y sure ofc jup yep yup ja tak]
  if accepted_answers.include?(proceed.downcase)
    story.current_state == "finished" ? deliver_story(story_id) : pick_up_story(story_id)
  else
    show_stories
  end
end

#start_story(story_id) ⇒ Object



242
243
244
# File 'lib/pivo_flow/pivotal.rb', line 242

def start_story story_id
  update_story(story_id, :started)
end

#story_color(story) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/pivo_flow/pivotal.rb', line 138

def story_color story
  if users_story?(story)
    case story.story_type
      when "feature" then :green
      when "bug" then :red
      when "chore" then :yellow
      else :white
    end
  else
    case story.story_type
      when "feature" then :light_green
      when "bug" then :light_red
      when "chore" then :ligh_yellow
      else :light_white
    end
  end
end

#story_labels(story) ⇒ Object



187
188
189
# File 'lib/pivo_flow/pivotal.rb', line 187

def  story
  story.labels.nil? ? "" : story.labels.split(",").map{ |l| "##{l}" }.join(", ")
end

#story_notes(story, exclude_commits = true) ⇒ Object



104
105
106
107
# File 'lib/pivo_flow/pivotal.rb', line 104

def story_notes story, exclude_commits=true
  return story.notes.all unless exclude_commits
  story.notes.all.select { |n| n.text !~ /Commit by/ }
end

#story_owner(story) ⇒ Object



183
184
185
# File 'lib/pivo_flow/pivotal.rb', line 183

def story_owner story
  story.owned_by.nil? ? "(--)" : "(#{initials(story.owned_by)})"
end

#story_state_sign(story) ⇒ Object



191
192
193
194
# File 'lib/pivo_flow/pivotal.rb', line 191

def story_state_sign story
  return "*" if story.current_state == "unstarted"
  story.current_state[0].capitalize
end

#story_string(story, long = false) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/pivo_flow/pivotal.rb', line 109

def story_string story, long=false
  vars = {
    story_id: story.id,
    requested_by: story.requested_by,
    name: truncate(story.name),
    story_type: story_type_icon(story),
    estimate: estimate_points(story),
    owner: story_owner(story),
    description: story.description,
    labels: (story).colorize(:blue),
    started: story_state_sign(story)
  }
  if long
    "STORY %{started} %{story_type} [#%{story_id}]
    Name:         %{name}
    Labels:       %{labels}
    Owned by:     %{owner}
    Requested by: %{requested_by}
    Description:  %{description}
    Estimate:     %{estimate}" % vars
  else
    "[#%{story_id}] (%{started}) %{story_type} [%{estimate} pts.] %{owner} %{name} %{labels}".colorize(story_color(story)) % vars
  end
end

#story_type_icon(story) ⇒ Object



173
174
175
176
177
# File 'lib/pivo_flow/pivotal.rb', line 173

def story_type_icon story
  type = story.story_type
  space_count = 7 - type.length
  type + " " * space_count
end

#task_string(task) ⇒ Object



168
169
170
171
# File 'lib/pivo_flow/pivotal.rb', line 168

def task_string task
  complete = task.complete ? "x" : " "
  "\t[#{complete}] #{task.description}"
end

#truncate(string) ⇒ Object



179
180
181
# File 'lib/pivo_flow/pivotal.rb', line 179

def truncate string
  string.length > 80 ? "#{string[0..80]}..." : string
end

#unasigned_storiesObject



36
37
38
# File 'lib/pivo_flow/pivotal.rb', line 36

def unasigned_stories
  project_stories.select{ |story| story.owned_by == nil }
end

#update_story(story_id, state) ⇒ Object



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/pivo_flow/pivotal.rb', line 212

def update_story story_id, state
  story = find_story(story_id)
  if story.nil?
    puts "Story not found, sorry."
    return
  end
  state = :accepted if story.story_type == "chore" && state == :finished
  if story.update(owned_by: user_name, current_state: state).errors.count.zero?
    puts "Story updated in Pivotal Tracker"
    true
  else
    error_message = "ERROR"
    error_message += ": #{story.errors.first}"
    puts error_message
  end
end

#user_storiesObject



24
25
26
# File 'lib/pivo_flow/pivotal.rb', line 24

def user_stories
  project_stories.select{ |story| story.owned_by == user_name }
end

#users_story?(story) ⇒ Boolean

Returns:

  • (Boolean)


134
135
136
# File 'lib/pivo_flow/pivotal.rb', line 134

def users_story?(story)
  story.owned_by == user_name
end