class GitPivotalTrackerIntegration::Command::Deliver

The class that encapsulates starting a Pivotal Tracker Story

Public Instance Methods

check_branch() click to toggle source
# File lib/git-pivotal-tracker-integration/command/deliver.rb, line 100
def check_branch

  current_branch    = Util::Git.branch_name
  suggested_branch  = "develop"

  if !suggested_branch.nil? && suggested_branch.length !=0 && current_branch != suggested_branch
    should_change_branch = ask("Your currently checked out branch is '#{current_branch}'. \n\n Do you want to checkout '#{suggested_branch}' before starting?(Y/n)")
    if should_change_branch != "n"
      print "Checking out branch '#{suggested_branch}'...\n\n"
      Util::Shell.exec "git checkout #{suggested_branch}"
      Util::Shell.exec 'git pull'
    end
  end
end
run(filter) click to toggle source

Starts a Pivotal Tracker story by doing the following steps:

  • Create a branch

  • Add default commit hook

  • Start the story on Pivotal Tracker

@param [String, nil] filter a filter for selecting the story to start. This

filter can be either:
* a story id
* a story type (feature, bug, chore)
* +nil+

@return [void]

# File lib/git-pivotal-tracker-integration/command/deliver.rb, line 32
def run(filter)
  $LOG.debug("#{self.class} in project:#{@project.name} pwd:#{pwd} branch:#{Util::Git.branch_name}")
  self.check_branch
  story = Util::Story.select_release @project
  $LOG.debug("Release Story:#{story.name}")
  #sort_for_deliver story
  Util::Story.pretty_print story

  current_branch = Util::Git.branch_name

  if current_branch == 'develop'
    puts "Merging from orgin develop..."
    Util::Shell.exec "git pull"

    # checkout QA branch
    # Merge develop into QA
    Util::Shell.exec "git checkout QA"
    Util::Shell.exec "git reset --hard origin/QA"
    Util::Shell.exec "git pull"
    if (Util::Shell.exec "git merge -s recursive --strategy-option theirs develop")
      puts "Merged 'develop' in to 'QA'"
    else
      abort "FAILED to merge 'develop' in to 'QA'"
    end
  else # we might be on a feature branch. So create a seperate branch for qa.
    qa_current_branch = "qa-#{current_branch}"
    print "Creating and Checking out new qa branch #{qa_current_branch}"
    Util::Shell.exec "git checkout --quiet -b #{qa_current_branch}"
    Util::Shell.exec "git push -u origin #{qa_current_branch}"
  end

  # retrieve build number from story name
  build_number      = story.name.slice(1..-1)
  working_directory = pwd

  puts "Story Name:         #{story.name}"
  puts "Build Number:       #{build_number}"
  puts "Working Directory:  #{working_directory}*"
  puts ""

  if (OS.mac? && @platform.downcase == "ios")
    project_directory = @configuration.xcode_project_path
    project_directory ||= ((Util::Shell.exec 'find . -name "*.xcodeproj" 2>/dev/null').split /\/(?=[^\/]*$)/)[0]

    # cd to the project_directory
    Dir.chdir(project_directory)

    # set build number and project number in project file
    pwd
    puts Util::Shell.exec "xcrun agvtool new-version -all #{build_number}", false
    puts Util::Shell.exec "xcrun agvtool new-marketing-version SNAPSHOT"

    # cd back to the working_directory
    Dir.chdir(working_directory)
  elsif @platform == 'android'
    updater = VersionUpdate::Gradle.new(@repository_root)
    updater.update_qa_version(build_number)
  end

  # Create a new build commit, push to QA, checkout develop
  Util::Git.create_commit( "Update build number to #{build_number} for delivery to QA", story)
  puts Util::Shell.exec "git push"
  puts Util::Shell.exec "git checkout #{current_branch}"

  i_stories = included_stories @project, story
  deliver_stories i_stories, story
end

Private Instance Methods

deliver_stories(stories, build_story) click to toggle source
# File lib/git-pivotal-tracker-integration/command/deliver.rb, line 117
def deliver_stories(stories, build_story)
  all_stories = stories.dup
  all_stories << build_story

  all_stories.each do |story|

    story.add_label(build_story.name)

    case story.story_type
    when 'feature', 'bug'
      story.current_state = 'delivered'
    when 'chore'
      story.current_state = 'accepted'
    end
    story.save
  end
end
included_stories(project, build_story) click to toggle source
# File lib/git-pivotal-tracker-integration/command/deliver.rb, line 135
def included_stories(project, build_story)

  stories_finished = project.stories(filter: "current_state:finished  type:bug,chore,feature -id:#{build_story.id}", limit: 1000)
  story_ids_finished = stories_finished.map { |e| e.id }
  story_ids_merged = `git log | grep \"\\[Completes\" | egrep -o \"\\d{9}\"`.split("\n").map(&:to_i)

  story_ids_intersection = story_ids_finished & story_ids_merged
  stories = stories_finished.map { |e| e if story_ids_intersection.include? e.id }.compact
 
    #puts "story IDs finished:\n#{story_ids_finished}"
    #puts "story IDs merged:\n#{story_ids_merged}"
    #puts "story IDs intersection:\n#{story_ids_intersection}"
    #puts "story IDs:\n#{stories.map { |e| e.id }}"
    #puts "stories count:#{stories.count}"
    #abort "abort"


  # capture story details in a file as well as to stdout
  FileUtils.mkdir_p 'release_notes'
  notes_file = File.join("release_notes", "#{project.name}-#{build_story.name}.txt")

  File.open(notes_file, 'w') do |file|
    puts "Included Stories"
    file.puts "Included Stories"

    stories.each do |story|
      file.puts "#{story.id} - #{story.name}"
      puts "#{story.id} - #{story.name}"
    end
  end

  stories
end
sort_for_deliver(release_story) click to toggle source
# File lib/git-pivotal-tracker-integration/command/deliver.rb, line 169
def sort_for_deliver(release_story)
  last_release  = Util::Story.last_release_story(@project, "b")
  stories       = included_stories(@project, release_story)
  last_release  = stories.shift if last_release.nil?

  abort "\nThere are no last release stories or finished stories to deliver" if last_release.nil?
  stories << release_story
  previous_story = last_release.dup

  puts "Last release:#{previous_story.name}"
  last_accepted_release_story = @project.stories(filter: "current_state:accepted type:release").last
  not_accepted_releases       = @project.stories(filter: "current_state:unstarted type:release")
  stories.reverse!

  stories.each do |story|
    if not_accepted_releases.size == 1 && !last_accepted_release_story.nil?
      story.after_id = last_accepted_release_story.id
    elsif previous_story.current_state == 'accepted'
      story.after_id = not_accepted_releases[not_accepted_releases.size - 2].id
    else
      story.after_id = previous_story.id
    end
    story.save
  end
end