tpope-pickler 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +4 -0
- data/lib/pickler/feature.rb +13 -4
- data/lib/pickler/runner.rb +119 -20
- data/lib/pickler/tracker/iteration.rb +4 -0
- data/lib/pickler/tracker/note.rb +4 -0
- data/lib/pickler/tracker/story.rb +48 -10
- data/lib/pickler.rb +45 -35
- data/pickler.gemspec +3 -1
- metadata +20 -2
    
        data/README.rdoc
    CHANGED
    
    | @@ -2,6 +2,10 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            Synchronize user stories in Pivotal Tracker with Cucumber features.
         | 
| 4 4 |  | 
| 5 | 
            +
            If you aren't using Cucumber, you can still use pickler as a Pivotal Tracker
         | 
| 6 | 
            +
            command line client, provided you humor it with a features/ directory
         | 
| 7 | 
            +
            containing a tracker.yml file.
         | 
| 8 | 
            +
             | 
| 5 9 | 
             
            == Getting started
         | 
| 6 10 |  | 
| 7 11 | 
             
              gem install tpope-pickler --source=http://gems.github.com
         | 
    
        data/lib/pickler/feature.rb
    CHANGED
    
    | @@ -13,6 +13,9 @@ class Pickler | |
| 13 13 | 
             
                    @story = identifier
         | 
| 14 14 | 
             
                    @id = @story.id
         | 
| 15 15 |  | 
| 16 | 
            +
                  when Integer
         | 
| 17 | 
            +
                    @id = identifier
         | 
| 18 | 
            +
             | 
| 16 19 | 
             
                  when /^#{URL_REGEX}$/, /^(\d+)$/
         | 
| 17 20 | 
             
                    @id = $1.to_i
         | 
| 18 21 |  | 
| @@ -54,7 +57,9 @@ class Pickler | |
| 54 57 |  | 
| 55 58 | 
             
                def start(default = nil)
         | 
| 56 59 | 
             
                  story.transition!("started") if story.startable?
         | 
| 57 | 
            -
                   | 
| 60 | 
            +
                  if filename || default
         | 
| 61 | 
            +
                    pull(default)
         | 
| 62 | 
            +
                  end
         | 
| 58 63 | 
             
                end
         | 
| 59 64 |  | 
| 60 65 | 
             
                def push
         | 
| @@ -64,9 +69,13 @@ class Pickler | |
| 64 69 | 
             
                end
         | 
| 65 70 |  | 
| 66 71 | 
             
                def finish
         | 
| 67 | 
            -
                   | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 72 | 
            +
                  if filename
         | 
| 73 | 
            +
                    story.finish
         | 
| 74 | 
            +
                    story.to_s = local_body
         | 
| 75 | 
            +
                    story.save
         | 
| 76 | 
            +
                  else
         | 
| 77 | 
            +
                    story.finish!
         | 
| 78 | 
            +
                  end
         | 
| 70 79 | 
             
                end
         | 
| 71 80 |  | 
| 72 81 | 
             
                def id
         | 
    
        data/lib/pickler/runner.rb
    CHANGED
    
    | @@ -118,20 +118,48 @@ class Pickler | |
| 118 118 | 
             
                    end
         | 
| 119 119 | 
             
                  end
         | 
| 120 120 |  | 
| 121 | 
            +
                  def colorize(code, string)
         | 
| 122 | 
            +
                    if color?
         | 
| 123 | 
            +
                      "\e[#{code}m#{string}\e[00m"
         | 
| 124 | 
            +
                    else
         | 
| 125 | 
            +
                      string.to_s
         | 
| 126 | 
            +
                    end
         | 
| 127 | 
            +
                  end
         | 
| 128 | 
            +
             | 
| 121 129 | 
             
                  def puts_summary(story)
         | 
| 122 130 | 
             
                    summary = "%6d " % story.id
         | 
| 123 131 | 
             
                    type  = story.estimate || TYPE_SYMBOLS[story.story_type]
         | 
| 124 132 | 
             
                    state = STATE_SYMBOLS[story.current_state]
         | 
| 125 | 
            -
                     | 
| 126 | 
            -
             | 
| 127 | 
            -
                      summary << "\e[01;3#{TYPE_COLORS[story.story_type]}m#{type}\e[00m "
         | 
| 128 | 
            -
                    else
         | 
| 129 | 
            -
                      summary << "#{state} #{type} "
         | 
| 130 | 
            -
                    end
         | 
| 133 | 
            +
                    summary << colorize("3#{STATE_COLORS[story.current_state]}", state) << ' '
         | 
| 134 | 
            +
                    summary << colorize("01;3#{TYPE_COLORS[story.story_type]}", type) << ' '
         | 
| 131 135 | 
             
                    summary << story.name
         | 
| 132 136 | 
             
                    puts summary
         | 
| 133 137 | 
             
                  end
         | 
| 134 138 |  | 
| 139 | 
            +
                  def puts_full(story)
         | 
| 140 | 
            +
                    puts colorize("01;3#{TYPE_COLORS[story.story_type]}", story.name)
         | 
| 141 | 
            +
                    puts "Type:      #{story.story_type}".rstrip
         | 
| 142 | 
            +
                    if story.story_type == "release"
         | 
| 143 | 
            +
                      puts "Deadline:  #{story.deadline}".rstrip
         | 
| 144 | 
            +
                    else
         | 
| 145 | 
            +
                      puts "Estimate:  #{story.estimate}".rstrip
         | 
| 146 | 
            +
                    end
         | 
| 147 | 
            +
                    puts "State:     #{story.current_state}".rstrip
         | 
| 148 | 
            +
                    puts "Labels:    #{story.labels.join(', ')}".rstrip
         | 
| 149 | 
            +
                    puts "Requester: #{story.requested_by}".rstrip
         | 
| 150 | 
            +
                    puts "Owner:     #{story.owned_by}".rstrip
         | 
| 151 | 
            +
                    puts "URL:       #{story.url}".rstrip
         | 
| 152 | 
            +
                    puts unless story.description.blank?
         | 
| 153 | 
            +
                    story.description_lines.each do |line|
         | 
| 154 | 
            +
                      puts "  #{line}".rstrip
         | 
| 155 | 
            +
                    end
         | 
| 156 | 
            +
                    story.notes.each do |note|
         | 
| 157 | 
            +
                      puts
         | 
| 158 | 
            +
                      puts "  #{colorize('01', note.author)} (#{note.date})"
         | 
| 159 | 
            +
                      puts *note.lines(72).map {|l| "    #{l}".rstrip}
         | 
| 160 | 
            +
                    end
         | 
| 161 | 
            +
                  end
         | 
| 162 | 
            +
             | 
| 135 163 | 
             
                  def paginated_output
         | 
| 136 164 | 
             
                    stdout = $stdout
         | 
| 137 165 | 
             
                    if @tty && pager = pickler.config["pager"]
         | 
| @@ -144,6 +172,7 @@ class Pickler | |
| 144 172 | 
             
                    else
         | 
| 145 173 | 
             
                      yield
         | 
| 146 174 | 
             
                    end
         | 
| 175 | 
            +
                  rescue Errno::EPIPE
         | 
| 147 176 | 
             
                  ensure
         | 
| 148 177 | 
             
                    $stdout = stdout
         | 
| 149 178 | 
             
                  end
         | 
| @@ -177,9 +206,9 @@ class Pickler | |
| 177 206 | 
             
                    when 0
         | 
| 178 207 | 
             
                      puts "#{pickler.project_id} #{pickler.project.name}"
         | 
| 179 208 | 
             
                    when 1
         | 
| 180 | 
            -
                      story = pickler. | 
| 209 | 
            +
                      story = pickler.story(args.first)
         | 
| 181 210 | 
             
                      paginated_output do
         | 
| 182 | 
            -
                         | 
| 211 | 
            +
                        puts_full story
         | 
| 183 212 | 
             
                      end
         | 
| 184 213 | 
             
                    else
         | 
| 185 214 | 
             
                      too_many
         | 
| @@ -200,17 +229,28 @@ class Pickler | |
| 200 229 | 
             
                    end
         | 
| 201 230 | 
             
                  end
         | 
| 202 231 | 
             
                  [:requester, :owner, :mywork].each do |o|
         | 
| 203 | 
            -
                    on "--#{o} | 
| 204 | 
            -
                      modifications[o] = value
         | 
| 232 | 
            +
                    on "--#{o}[=USERNAME]" do |value|
         | 
| 233 | 
            +
                      modifications[o] = value || pickler.real_name
         | 
| 205 234 | 
             
                    end
         | 
| 206 235 | 
             
                  end
         | 
| 207 236 | 
             
                  on "--[no-]includedone", "include accepted stories" do |value|
         | 
| 208 237 | 
             
                    modifications[:includedone] = value
         | 
| 238 | 
            +
                    @iterations ||= []
         | 
| 239 | 
            +
                    @iterations << :done?
         | 
| 240 | 
            +
                  end
         | 
| 241 | 
            +
             | 
| 242 | 
            +
                  on "-b", "--backlog", "filter results to future iterations" do |c|
         | 
| 243 | 
            +
                    @iterations ||= []
         | 
| 244 | 
            +
                    @iterations << :backlog?
         | 
| 209 245 | 
             
                  end
         | 
| 210 246 |  | 
| 211 | 
            -
                  attr_writer :current
         | 
| 212 247 | 
             
                  on "-c", "--current", "filter results to current iteration" do |b|
         | 
| 213 | 
            -
                     | 
| 248 | 
            +
                    @iterations ||= []
         | 
| 249 | 
            +
                    @iterations << :current?
         | 
| 250 | 
            +
                  end
         | 
| 251 | 
            +
             | 
| 252 | 
            +
                  on "--[no-]full", "show full story, not a summary line" do |b|
         | 
| 253 | 
            +
                    @full = b
         | 
| 214 254 | 
             
                  end
         | 
| 215 255 |  | 
| 216 256 | 
             
                  process do |*argv|
         | 
| @@ -221,10 +261,19 @@ class Pickler | |
| 221 261 | 
             
                    else
         | 
| 222 262 | 
             
                      stories = pickler.project.stories(*argv)
         | 
| 223 263 | 
             
                    end
         | 
| 224 | 
            -
                     | 
| 264 | 
            +
                    if @iterations && @iterations != [:done?]
         | 
| 265 | 
            +
                      stories.reject! {|s| !@iterations.any? {|i| s.send(i)}}
         | 
| 266 | 
            +
                    end
         | 
| 225 267 | 
             
                    paginated_output do
         | 
| 268 | 
            +
                      first = true
         | 
| 226 269 | 
             
                      stories.each do |story|
         | 
| 227 | 
            -
                         | 
| 270 | 
            +
                        if @full
         | 
| 271 | 
            +
                          puts unless first
         | 
| 272 | 
            +
                          puts_full story
         | 
| 273 | 
            +
                        else
         | 
| 274 | 
            +
                          puts_summary story
         | 
| 275 | 
            +
                        end
         | 
| 276 | 
            +
                        first = false
         | 
| 228 277 | 
             
                      end
         | 
| 229 278 | 
             
                    end
         | 
| 230 279 | 
             
                  end
         | 
| @@ -237,6 +286,13 @@ class Pickler | |
| 237 286 | 
             
            Upload the given story or all features with a tracker url in a comment on the
         | 
| 238 287 | 
             
            first line.
         | 
| 239 288 | 
             
                  EOF
         | 
| 289 | 
            +
             | 
| 290 | 
            +
                  process do |*args|
         | 
| 291 | 
            +
                    args.replace(pickler.local_features) if args.empty?
         | 
| 292 | 
            +
                    args.each do |arg|
         | 
| 293 | 
            +
                      pickler.feature(arg).push
         | 
| 294 | 
            +
                    end
         | 
| 295 | 
            +
                  end
         | 
| 240 296 | 
             
                end
         | 
| 241 297 |  | 
| 242 298 | 
             
                command :pull do
         | 
| @@ -247,6 +303,13 @@ Download the given story or all well formed stories to the features/ directory. | |
| 247 303 | 
             
            Previously unseen stories will be given a numeric filename that you are
         | 
| 248 304 | 
             
            encouraged to change.
         | 
| 249 305 | 
             
                  EOF
         | 
| 306 | 
            +
             | 
| 307 | 
            +
                  process do |*args|
         | 
| 308 | 
            +
                    args.replace(pickler.scenario_features) if args.empty?
         | 
| 309 | 
            +
                    args.each do |arg|
         | 
| 310 | 
            +
                      pickler.feature(arg).pull
         | 
| 311 | 
            +
                    end
         | 
| 312 | 
            +
                  end
         | 
| 250 313 | 
             
                end
         | 
| 251 314 |  | 
| 252 315 | 
             
                command :start do
         | 
| @@ -254,12 +317,11 @@ encouraged to change. | |
| 254 317 | 
             
                  summary "Pull a story and mark it started"
         | 
| 255 318 | 
             
                  description <<-EOF
         | 
| 256 319 | 
             
            Pull a given story and change its state to started.  If basename is given
         | 
| 257 | 
            -
            and no local file exists, features/basename.feature will be created | 
| 258 | 
            -
            of features/id.feature.
         | 
| 320 | 
            +
            and no local file exists, features/basename.feature will be created.
         | 
| 259 321 | 
             
                  EOF
         | 
| 260 322 |  | 
| 261 | 
            -
                  process do | | 
| 262 | 
            -
                    pickler.start( | 
| 323 | 
            +
                  process do |story, *args|
         | 
| 324 | 
            +
                    pickler.feature(story).start(args.first)
         | 
| 263 325 | 
             
                  end
         | 
| 264 326 | 
             
                end
         | 
| 265 327 |  | 
| @@ -267,8 +329,8 @@ of features/id.feature. | |
| 267 329 | 
             
                  banner_arguments "<story>"
         | 
| 268 330 | 
             
                  summary "Push a story and mark it finished"
         | 
| 269 331 |  | 
| 270 | 
            -
                  process do | | 
| 271 | 
            -
                     | 
| 332 | 
            +
                  process do |story|
         | 
| 333 | 
            +
                    pickler.feature(story).finish
         | 
| 272 334 | 
             
                  end
         | 
| 273 335 | 
             
                end
         | 
| 274 336 |  | 
| @@ -288,6 +350,34 @@ of features/id.feature. | |
| 288 350 | 
             
                  end
         | 
| 289 351 | 
             
                end
         | 
| 290 352 |  | 
| 353 | 
            +
                command :unstart do
         | 
| 354 | 
            +
                  banner_arguments "[story] ..."
         | 
| 355 | 
            +
                  summary "Mark stories unstarted"
         | 
| 356 | 
            +
                  on "--all-started", "unstart all started stories" do
         | 
| 357 | 
            +
                    @all = true
         | 
| 358 | 
            +
                  end
         | 
| 359 | 
            +
                  process do |*args|
         | 
| 360 | 
            +
                    if @all
         | 
| 361 | 
            +
                      pickler.project.stories(:state => "started").each do |story|
         | 
| 362 | 
            +
                        story.transition!('unstarted')
         | 
| 363 | 
            +
                      end
         | 
| 364 | 
            +
                    end
         | 
| 365 | 
            +
                    args.each do |arg|
         | 
| 366 | 
            +
                      pickler.story(arg).transition!('unstarted')
         | 
| 367 | 
            +
                    end
         | 
| 368 | 
            +
                  end
         | 
| 369 | 
            +
                end
         | 
| 370 | 
            +
             | 
| 371 | 
            +
                command :unschedule do
         | 
| 372 | 
            +
                  banner_arguments "[story] ..."
         | 
| 373 | 
            +
                  summary "Move stories to icebox"
         | 
| 374 | 
            +
                  process do |*args|
         | 
| 375 | 
            +
                    args.each do |arg|
         | 
| 376 | 
            +
                      pickler.story(arg).transition!('unscheduled')
         | 
| 377 | 
            +
                    end
         | 
| 378 | 
            +
                  end
         | 
| 379 | 
            +
                end
         | 
| 380 | 
            +
             | 
| 291 381 | 
             
                command :browse do
         | 
| 292 382 | 
             
                  banner_arguments "[story]"
         | 
| 293 383 | 
             
                  summary "Open a story in the web browser"
         | 
| @@ -324,6 +414,15 @@ Requires launchy (gem install launchy). | |
| 324 414 | 
             
                  end
         | 
| 325 415 | 
             
                end
         | 
| 326 416 |  | 
| 417 | 
            +
                command :comment do
         | 
| 418 | 
            +
                  banner_arguments "<story> <paragraph> ..."
         | 
| 419 | 
            +
                  summary "Post a comment to a story"
         | 
| 420 | 
            +
             | 
| 421 | 
            +
                  process do |story, *paragraphs|
         | 
| 422 | 
            +
                    pickler.story(story).comment!(paragraphs.join("\n\n"))
         | 
| 423 | 
            +
                  end
         | 
| 424 | 
            +
                end
         | 
| 425 | 
            +
             | 
| 327 426 | 
             
                def initialize(argv)
         | 
| 328 427 | 
             
                  @argv = argv
         | 
| 329 428 | 
             
                end
         | 
    
        data/lib/pickler/tracker/note.rb
    CHANGED
    
    | @@ -18,6 +18,10 @@ class Pickler | |
| 18 18 | 
             
                    "#<#{self.class.inspect}:#{id.inspect}, story_id: #{story.id.inspect}, date: #{date.inspect}, author: #{author.inspect}, text: #{text.inspect}>"
         | 
| 19 19 | 
             
                  end
         | 
| 20 20 |  | 
| 21 | 
            +
                  def lines(width = 79)
         | 
| 22 | 
            +
                    text.scan(/(?:.{0,#{width}}|\S+?)(?:\s|$)/).map! {|line| line.strip}[0..-2]
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
             | 
| 21 25 | 
             
                end
         | 
| 22 26 | 
             
              end
         | 
| 23 27 | 
             
            end
         | 
| @@ -5,22 +5,27 @@ class Pickler | |
| 5 5 | 
             
                  TYPES = %w(bug feature chore release)
         | 
| 6 6 | 
             
                  STATES = %w(unscheduled unstarted started finished delivered rejected accepted)
         | 
| 7 7 |  | 
| 8 | 
            -
                  attr_reader :project, :iteration
         | 
| 9 | 
            -
                  reader :url | 
| 8 | 
            +
                  attr_reader :project, :iteration, :labels
         | 
| 9 | 
            +
                  reader :url
         | 
| 10 10 | 
             
                  date_reader :created_at, :accepted_at, :deadline
         | 
| 11 11 | 
             
                  accessor :current_state, :name, :description, :owned_by, :requested_by, :story_type
         | 
| 12 12 |  | 
| 13 13 | 
             
                  def initialize(project, attributes = {})
         | 
| 14 14 | 
             
                    @project = project
         | 
| 15 | 
            -
                    @iteration = Iteration.new(project, attributes["iteration"]) if attributes["iteration"]
         | 
| 16 15 | 
             
                    super(attributes)
         | 
| 16 | 
            +
                    @iteration = Iteration.new(project, @attributes["iteration"]) if @attributes["iteration"]
         | 
| 17 | 
            +
                    @labels = normalize_labels(@attributes["labels"])
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  def labels=(value)
         | 
| 21 | 
            +
                    @labels = normalize_labels(value)
         | 
| 17 22 | 
             
                  end
         | 
| 18 23 |  | 
| 19 24 | 
             
                  def transition!(state)
         | 
| 20 25 | 
             
                    raise Pickler::Tracker::Error, "Invalid state #{state}", caller unless STATES.include?(state)
         | 
| 21 26 | 
             
                    self.current_state = state
         | 
| 22 27 | 
             
                    if id
         | 
| 23 | 
            -
                      xml = "<story>< | 
| 28 | 
            +
                      xml = "<story><current_state>#{state}</current_state></story>"
         | 
| 24 29 | 
             
                      error = tracker.request_xml(:put, resource_url, xml).fetch("errors",{})["error"] || true
         | 
| 25 30 | 
             
                    else
         | 
| 26 31 | 
             
                      error = save
         | 
| @@ -28,10 +33,33 @@ class Pickler | |
| 28 33 | 
             
                    raise Pickler::Tracker::Error, Array(error).join("\n"), caller unless error == true
         | 
| 29 34 | 
             
                  end
         | 
| 30 35 |  | 
| 36 | 
            +
                  def finish
         | 
| 37 | 
            +
                    case story_type
         | 
| 38 | 
            +
                    when "bug", "feature"
         | 
| 39 | 
            +
                      self.current_state = "finished" unless complete?
         | 
| 40 | 
            +
                    when "chore", "release"
         | 
| 41 | 
            +
                      self.current_state = "accepted"
         | 
| 42 | 
            +
                    end
         | 
| 43 | 
            +
                    current_state
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  def finish!
         | 
| 47 | 
            +
                    transition!(finish)
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  def backlog?(as_of = Date.today)
         | 
| 51 | 
            +
                    iteration && iteration.start >= as_of
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
             | 
| 31 54 | 
             
                  def current?(as_of = Date.today)
         | 
| 32 55 | 
             
                    iteration && iteration.include?(as_of)
         | 
| 33 56 | 
             
                  end
         | 
| 34 57 |  | 
| 58 | 
            +
                  # In a previous iteration
         | 
| 59 | 
            +
                  def done?(as_of = Date.today)
         | 
| 60 | 
            +
                    iteration && iteration.finish <= as_of
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
             | 
| 35 63 | 
             
                  def complete?
         | 
| 36 64 | 
             
                    %w(finished delivered accepted).include?(current_state)
         | 
| 37 65 | 
             
                  end
         | 
| @@ -87,22 +115,27 @@ class Pickler | |
| 87 115 | 
             
                  end
         | 
| 88 116 |  | 
| 89 117 | 
             
                  def comment!(body)
         | 
| 90 | 
            -
                    raise ArgumentError if body.strip.empty? || body.size > 5000
         | 
| 91 118 | 
             
                    response = tracker.request_xml(:post, "#{resource_url}/notes",{:text => body}.to_xml(:dasherize => false, :root => 'note'))
         | 
| 92 | 
            -
                     | 
| 119 | 
            +
                    if response["note"]
         | 
| 120 | 
            +
                      Note.new(self, response["note"])
         | 
| 121 | 
            +
                    else
         | 
| 122 | 
            +
                      raise Pickler::Tracker::Error, Array(response["errors"]["error"]).join("\n"), caller
         | 
| 123 | 
            +
                    end
         | 
| 93 124 | 
             
                  end
         | 
| 94 125 |  | 
| 95 | 
            -
                  def to_xml
         | 
| 126 | 
            +
                  def to_xml(force_labels = true)
         | 
| 96 127 | 
             
                    hash = @attributes.reject do |k,v|
         | 
| 97 128 | 
             
                      !%w(current_state deadline description estimate name owned_by requested_by story_type).include?(k)
         | 
| 98 129 | 
             
                    end
         | 
| 99 | 
            -
                     | 
| 130 | 
            +
                    if force_labels || !id || normalize_labels(@attributes["labels"]) != labels
         | 
| 131 | 
            +
                      hash["labels"] = labels.join(", ")
         | 
| 132 | 
            +
                    end
         | 
| 100 133 | 
             
                    hash.to_xml(:dasherize => false, :root => "story")
         | 
| 101 134 | 
             
                  end
         | 
| 102 135 |  | 
| 103 136 | 
             
                  def destroy
         | 
| 104 137 | 
             
                    if id
         | 
| 105 | 
            -
                      response = tracker.request_xml(:delete, "/projects/#{project.id}/stories/#{id}",  | 
| 138 | 
            +
                      response = tracker.request_xml(:delete, "/projects/#{project.id}/stories/#{id}", "")
         | 
| 106 139 | 
             
                      raise Error, response["message"], caller if response["success"] != "true"
         | 
| 107 140 | 
             
                      @attributes["id"] = nil
         | 
| 108 141 | 
             
                      self
         | 
| @@ -114,7 +147,7 @@ class Pickler | |
| 114 147 | 
             
                  end
         | 
| 115 148 |  | 
| 116 149 | 
             
                  def save
         | 
| 117 | 
            -
                    response = tracker.request_xml(id ? :put : :post,  resource_url, to_xml)
         | 
| 150 | 
            +
                    response = tracker.request_xml(id ? :put : :post,  resource_url, to_xml(false))
         | 
| 118 151 | 
             
                    if response["success"] == "true"
         | 
| 119 152 | 
             
                      initialize(project, response["story"])
         | 
| 120 153 | 
             
                      true
         | 
| @@ -123,6 +156,11 @@ class Pickler | |
| 123 156 | 
             
                    end
         | 
| 124 157 | 
             
                  end
         | 
| 125 158 |  | 
| 159 | 
            +
                  private
         | 
| 160 | 
            +
                  def normalize_labels(value)
         | 
| 161 | 
            +
                    Array(value).join(", ").strip.split(/\s*,\s*/)
         | 
| 162 | 
            +
                  end
         | 
| 163 | 
            +
             | 
| 126 164 | 
             
                end
         | 
| 127 165 | 
             
              end
         | 
| 128 166 | 
             
            end
         | 
    
        data/lib/pickler.rb
    CHANGED
    
    | @@ -47,6 +47,41 @@ class Pickler | |
| 47 47 | 
             
                self.class.config.merge(@config)
         | 
| 48 48 | 
             
              end
         | 
| 49 49 |  | 
| 50 | 
            +
              def real_name
         | 
| 51 | 
            +
                config["real_name"] || (require 'etc'; Etc.getpwuid.gecos.split(',').first)
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              def new_story(attributes = {}, &block)
         | 
| 55 | 
            +
                attributes = attributes.inject('requested_by' => real_name) do |h,(k,v)|
         | 
| 56 | 
            +
                  h.update(k.to_s => v)
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
                project.new_story(attributes, &block)
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              def stories(*args)
         | 
| 62 | 
            +
                project.stories(*args)
         | 
| 63 | 
            +
              end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
              def name
         | 
| 66 | 
            +
                project.name
         | 
| 67 | 
            +
              end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
              def iteration_length
         | 
| 70 | 
            +
                project.iteration_length
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              def point_scale
         | 
| 74 | 
            +
                project.point_scale
         | 
| 75 | 
            +
              end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
              def week_start_day
         | 
| 78 | 
            +
                project.week_start_day
         | 
| 79 | 
            +
              end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
              def deliver_all_finished_stories
         | 
| 82 | 
            +
                project.deliver_all_finished_stories
         | 
| 83 | 
            +
              end
         | 
| 84 | 
            +
             | 
| 50 85 | 
             
              def parser
         | 
| 51 86 | 
             
                require 'cucumber'
         | 
| 52 87 | 
             
                require "cucumber/treetop_parser/feature_#@lang"
         | 
| @@ -75,51 +110,26 @@ class Pickler | |
| 75 110 | 
             
                Cucumber.language['scenario']
         | 
| 76 111 | 
             
              end
         | 
| 77 112 |  | 
| 78 | 
            -
              def  | 
| 79 | 
            -
                 | 
| 80 | 
            -
             | 
| 81 | 
            -
             | 
| 82 | 
            -
             | 
| 113 | 
            +
              def local_features
         | 
| 114 | 
            +
                Dir[features_path('**','*.feature')].map {|f|feature(f)}.select {|f|f.id}
         | 
| 115 | 
            +
              end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
              def scenario_features
         | 
| 118 | 
            +
                project.stories(scenario_word, :includedone => true).reject do |s|
         | 
| 119 | 
            +
                  %(unscheduled unstarted).include?(s.current_state)
         | 
| 120 | 
            +
                end.select do |s|
         | 
| 121 | 
            +
                  s.to_s =~ /^\s*#{Regexp.escape(scenario_word)}:/ && parser.parse(s.to_s)
         | 
| 83 122 | 
             
                end
         | 
| 84 123 | 
             
              end
         | 
| 85 124 |  | 
| 86 125 | 
             
              def feature(string)
         | 
| 87 | 
            -
                Feature.new(self,string)
         | 
| 126 | 
            +
                string.kind_of?(Feature) ? string : Feature.new(self,string)
         | 
| 88 127 | 
             
              end
         | 
| 89 128 |  | 
| 90 129 | 
             
              def story(string)
         | 
| 91 130 | 
             
                feature(string).story
         | 
| 92 131 | 
             
              end
         | 
| 93 132 |  | 
| 94 | 
            -
              def pull(*args)
         | 
| 95 | 
            -
                if args.empty?
         | 
| 96 | 
            -
                  args = project.stories(scenario_word, :includedone => true).reject do |s|
         | 
| 97 | 
            -
                    %(unscheduled unstarted).include?(s.current_state)
         | 
| 98 | 
            -
                  end.select do |s|
         | 
| 99 | 
            -
                    s.to_s =~ /^\s*#{Regexp.escape(scenario_word)}:/ && parser.parse(s.to_s)
         | 
| 100 | 
            -
                  end
         | 
| 101 | 
            -
                end
         | 
| 102 | 
            -
                args.each do |arg|
         | 
| 103 | 
            -
                  feature(arg).pull
         | 
| 104 | 
            -
                end
         | 
| 105 | 
            -
              end
         | 
| 106 | 
            -
             | 
| 107 | 
            -
              def start(arg, default = nil)
         | 
| 108 | 
            -
                feature(arg).start(default)
         | 
| 109 | 
            -
              end
         | 
| 110 | 
            -
             | 
| 111 | 
            -
              def push(*args)
         | 
| 112 | 
            -
                features(*args).each do |feature|
         | 
| 113 | 
            -
                  feature.push
         | 
| 114 | 
            -
                end
         | 
| 115 | 
            -
              end
         | 
| 116 | 
            -
             | 
| 117 | 
            -
              def finish(*args)
         | 
| 118 | 
            -
                features(*args).each do |feature|
         | 
| 119 | 
            -
                  feature.finish
         | 
| 120 | 
            -
                end
         | 
| 121 | 
            -
              end
         | 
| 122 | 
            -
             | 
| 123 133 | 
             
              protected
         | 
| 124 134 |  | 
| 125 135 | 
             
            end
         | 
    
        data/pickler.gemspec
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            Gem::Specification.new do |s|
         | 
| 2 2 | 
             
              s.name                = "pickler"
         | 
| 3 | 
            -
              s.version             = "0.0. | 
| 3 | 
            +
              s.version             = "0.0.6"
         | 
| 4 4 |  | 
| 5 5 | 
             
              s.summary             = "PIvotal traCKer Liaison to cucumbER"
         | 
| 6 6 | 
             
              s.description         = "Synchronize between Cucumber and Pivotal Tracker"
         | 
| @@ -25,4 +25,6 @@ Gem::Specification.new do |s| | |
| 25 25 | 
             
              ]
         | 
| 26 26 | 
             
              s.add_dependency("activesupport", [">= 2.0.0"])
         | 
| 27 27 | 
             
              s.add_dependency("cucumber", [">= 0.1.9"])
         | 
| 28 | 
            +
              s.add_dependency("builder")
         | 
| 29 | 
            +
              s.add_dependency("xml-simple")
         | 
| 28 30 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: tpope-pickler
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
              version: 0.0. | 
| 4 | 
            +
              version: 0.0.6
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors: 
         | 
| 7 7 | 
             
            - Tim Pope
         | 
| @@ -9,7 +9,7 @@ autorequire: | |
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 11 |  | 
| 12 | 
            -
            date: 2008- | 
| 12 | 
            +
            date: 2008-12-15 00:00:00 -08:00
         | 
| 13 13 | 
             
            default_executable: pickler
         | 
| 14 14 | 
             
            dependencies: 
         | 
| 15 15 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| @@ -30,6 +30,24 @@ dependencies: | |
| 30 30 | 
             
                  - !ruby/object:Gem::Version 
         | 
| 31 31 | 
             
                    version: 0.1.9
         | 
| 32 32 | 
             
                version: 
         | 
| 33 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 34 | 
            +
              name: builder
         | 
| 35 | 
            +
              version_requirement: 
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement 
         | 
| 37 | 
            +
                requirements: 
         | 
| 38 | 
            +
                - - ">="
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 40 | 
            +
                    version: "0"
         | 
| 41 | 
            +
                version: 
         | 
| 42 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 43 | 
            +
              name: xml-simple
         | 
| 44 | 
            +
              version_requirement: 
         | 
| 45 | 
            +
              version_requirements: !ruby/object:Gem::Requirement 
         | 
| 46 | 
            +
                requirements: 
         | 
| 47 | 
            +
                - - ">="
         | 
| 48 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 49 | 
            +
                    version: "0"
         | 
| 50 | 
            +
                version: 
         | 
| 33 51 | 
             
            description: Synchronize between Cucumber and Pivotal Tracker
         | 
| 34 52 | 
             
            email: ruby@tpope.info
         | 
| 35 53 | 
             
            executables: 
         |