lib/gitscape/base.rb in gitscape-1.6.6 vs lib/gitscape/base.rb in gitscape-1.7.2
- old
+ new
@@ -2,12 +2,10 @@
class Gitscape::Base
def initialize
- # Use the current directory as our target repository
- @repo = Git.open "."
# Always add a merge commit at the end of a merge
@merge_options = "--no-ff"
# Setup additional merge options based on the version of Git we have
@@ -25,10 +23,11 @@
"qa"
when "live"
"live"
end
end
+
end
def git_working_copy_is_clean puts_changes=true
# Check if the working copy is clean, if not, exit
@@ -41,13 +40,19 @@
end
working_copy_clean
end
+ # Assume the highest branch already merged into live of the form
+ # release/i[\d]+ is the live branch
def live_iteration
live_iteration_tag_regex = /^live\/i(\d+)/
toRet = `git tag`.split("\n").select { |tag| live_iteration_tag_regex.match tag }.map { |tag| tag.scan(live_iteration_tag_regex).flatten[0].to_i }.sort.last
+ # A bit of a chicken-and-egg problem. You might not have any tags for live, so look for something else...
+ if toRet.nil?
+ toRet = `git branch -a --merged origin/live`.split("\n").select{|b| /release\/i(\d+)$/.match b}.map{|b| b.scan(/release\/i(\d+)$/).flatten[0].to_i}.sort.last
+ end
toRet
end
def current_branch_name
toRet = `git branch`.scan(/\* (.*)$/).flatten[0]
@@ -78,86 +83,128 @@
puts conflicts_status if has_conflicts && puts_conflicts
has_conflicts
end
- def hotfix_start hotfix_branch=nil, options={:push=>false}
+ def generic_branch_start branch_type, from_branch, new_branch, options
# option defaults
options[:push] = false if options[:push].nil?
# Check that the working copy is clean
exit 1 unless git_working_copy_is_clean
- puts `git checkout live`
- puts `git pull origin`
+ if new_branch.to_s.length == 0
+ raise "*** Improper Usage ***\nExpected Usage: #{branch_type}_start <#{branch_type}_name> [--[no-]push]"
+ end
- if hotfix_branch.to_s.length == 0
- exception_message = "*** Improper Usage ***\nExpected Usage: hotfix_start <hotfix_name> [--[no-]push]"
- raise exception_message
+ puts `git checkout #{from_branch}`
+ puts `git pull origin #{from_branch}`
+
+ new_branch = "#{branch_type}/#{new_branch}"
+ puts "=== Creating #{branch_type} branch '#{new_branch}' ==="
+
+ puts `git checkout -b #{new_branch}`
+ puts `git push origin #{new_branch}` if options[:push]
+ end
+
+ def hotfix_start new_branch=nil, options={:push=>false}
+ generic_branch_start 'hotfix', 'live', new_branch, options
+ end
+
+ def bugfix_start new_branch=nil, options={:push=>false}
+ name = current_release_branch_name
+ if name.nil?
+ puts 'There is not a current release branch. You cannot use this command.'
+ else
+ generic_branch_start 'bugfix', name, new_branch, options
end
+ end
- hotfix_branch = "hotfix/#{hotfix_branch}"
- puts "=== Creating hotfix branch '#{hotfix_branch}' ==="
+ def feature_start new_branch=nil, options={:push=>false}
+ generic_branch_start 'feature', 'master', new_branch, options
+ end
- puts `git checkout -b #{hotfix_branch}`
- puts `git push origin #{hotfix_branch}` if options[:push]
+ def hotfix_finish branch_name=nil, options={:env_depth=>:staging, :push=>true, :update_env=>false}
+ generic_branch_finish 'hotfix', branch_name, options
end
- def hotfix_finish hotfix_branch=nil, options={:env_depth=>:staging, :push=>true, :update_env=>false}
+ def bugfix_finish branch_name=nil, options={:env_depth=>:staging, :push=>true, :update_env=>false}
+ generic_branch_finish 'bugfix', branch_name, options
+ end
+
+ def feature_finish branch_name=nil, options={:env_depth=>:staging, :push=>true, :update_env=>false}
+ generic_branch_finish 'feature', branch_name, options
+ end
+
+ def generic_branch_finish branch_type, source_name, options
# option defaults
options[:env_depth] = :staging if options[:env_depth].nil?
options[:push] = true if options[:push].nil?
options[:update_env] = false if options[:update_env].nil?
+ if (options[:env_depth] == :qa) && branch_type == 'feature'
+ puts "*** --qa may not be used with feature branches"
+ exit 1
+ end
+ if (options[:env_depth] == :live) && branch_type != 'hotfix'
+ puts "*** --live may only be used with hotfix branches"
+ exit 1
+ end
+
+
# Check that the working copy is clean
exit 1 unless git_working_copy_is_clean
- usage_string = "expected usage: hotfix_finish [<hotfix_branch>]
- hotfix_branch: the name of the hotfix branch to finish.
- if ommitted, you must currently be on a hotfix branch"
-
- hotfix_branch = "hotfix/#{hotfix_branch}"
+ source_branch = "#{branch_type}/#{source_branch}"
previous_branch = current_branch_name
- if previous_branch.to_s.start_with? "hotfix/"
- hotfix_branch = previous_branch
+ if previous_branch.to_s.start_with? "#{branch_type}/"
+ source_branch = previous_branch
end
- if hotfix_branch.to_s.empty?
- puts "!!! Not currently on a hotfix branch, and no branch name was provided as an argument !!!"
- puts usage_string
+ if source_branch.to_s.empty?
+ puts "!!! Not currently on a #{branch_type} branch, and no branch name was provided as an argument !!!"
+ puts finish_usage_string(branch_type)
exit 1
end
# Collect the set of branches we'd like to merge the hotfix into
merge_branches = ["master"]
- merge_branches << current_release_branch_name if [:qa, :live].include?(options[:env_depth])
- merge_branches << "live" if options[:env_depth] == :live
+ if %w{bugfix hotfix}.include?(branch_type)
+ if current_release_branch_name.nil?
+ puts "!!! There is no current release branch: the command will bypass the release and qa branches"
+ else
+ merge_branches << current_release_branch_name if [:qa, :live].include?(options[:env_depth])
+ end
+ end
+ if %w{hotfix}.include?(branch_type)
+ merge_branches << "live" if options[:env_depth] == :live
+ end
- # Merge the hotfix into merge_branches
- puts "=== Merging hotfix into branches #{merge_branches} ==="
+ # Merge the source branch into merge_branches
+ puts "=== Merging #{branch_type} into branches #{merge_branches} ==="
for branch in merge_branches
# Calculate merge_options
merge_options = @merge_options
merge_options += " --log" if branch == "master"
# Attempt merge
puts `git checkout #{branch}`
puts `git pull`
- puts `git merge #{merge_options} #{hotfix_branch}`
+ puts `git merge #{merge_options} #{source_branch}`
# Bail on failures
exit 1 if !$?.success?
raise "Merge failure(s) on #{branch}.\nResolve conflicts, and run the script again." if git_has_conflicts
puts `git push origin #{branch}` if options[:push]
puts `git push origin #{branch}:#{@env_branch_by_dev_branch[branch]}` if options[:update_env]
# If we just merged the live branch, tag this revision, and push that tag to origin
if branch == "live"
- puts `git tag live/i#{live_iteration}/#{hotfix_branch}`
+ puts `git tag live/i#{live_iteration}/#{source_branch}`
puts `git push --tags`
end
end
@@ -255,20 +302,20 @@
# Error and conflict checking
if !$?.success? then exit 4 end
if git_has_conflicts then
puts "Merge conflicts when pulling #{release_branch} into live"
- puts "Please bother Xavier if you see this message :)"
+ puts "Please report a problem if you see this message :)"
exit 2
end
# Ensure there is zero diff between what was tested on origin/qa and the new live
critical_diff = `git diff live origin/qa`
if critical_diff.length > 0
puts "\n!!! This live merge has code that was not on the qa branch !!!\nDiff:"
puts critical_diff
- puts "!!! Run the command 'git reset --hard' to undo the merge, and raise this error with Phil and others involved to determine next step !!!"
+ puts "!!! Run the command 'git reset --hard' to undo the merge, and raise this error with QA and others involved to determine next step !!!"
exit 3
end
# Record the revision of live used for the release tag
live_release_revision = `git log -n1 --oneline`.scan(/(^[^ ]+) .*$/).flatten[0]
@@ -280,11 +327,11 @@
# Error and conflict checking
if !$?.success? then exit 4 end
if git_has_conflicts then
puts "Merge conflicts when pulling #{release_branch} into master"
- puts "Please bother Xavier if you see this message :)"
+ puts "Please report a problem if you see this message :)"
exit 2
end
# Tag the state of live for both release and rollback
puts `git tag rollback-to/i#{current_version_number} live~`
@@ -315,11 +362,11 @@
# Select which tags to keep.
# We currently keep tags which fulfill any of the following
# 1. starts with 'service/'
# 2. starts with 'rollback-to/' or 'live/', and has an iteration number >= the live_iteration number - 3
tags = `git tag`.split "\n"
- tags_to_delete = tags.select { |tag| !(!/^service\//.match(tag).nil? || /^(?:live|rollback-to)\/i(\d+)/.match(tag).to_a[1].to_i >= live_iteration.to_i - 3) }
+ tags_to_delete = tags.select { |tag| !(!/^service\//.match(tag).nil? || /^(?:live|rollback-to)\/i(\d+)/.match(tag).to_a[1].to_i >= live_iteration - 3) }
puts "Deleting the following tags.\nThese changes #{options[:push] ? "will" : "will not"} be pushed to origin.\n"
tags_to_delete.each { |tag| puts `git tag -d #{tag}` }
tags_to_delete.each { |tag| puts `git push origin :refs/tags/#{tag}` } if options[:push]
@@ -333,31 +380,10 @@
else
raise "Invalid commit/ref ID: #{commit_id}"
end
end
- def self.run_script(script, quiet=true)
- IO.popen(script.split("\n").join(" && ")) do |io|
- while (line = io.gets) do
- unless quiet
- puts line
- end
- end
- end
- $?.exitstatus
- end
-
- def promote_branch(head, upstream)
- run_script <<-EOH
- git fetch
- git stash
- git checkout #{head}
- git reset --hard origin/#{head}
- git push -f origin #{head}:#{upstream}
- EOH
- end
-
# Get the system's current git version
def git_version
@git_version ||= `git --version`.strip.split(" ").last
end
@@ -376,67 +402,12 @@
return local_version[i] > min_version[i]
end
true # If you get all the way here, all 4 positions match precisely
end
- def self.result_ok?(result)
- if result.nil? or result == 0
- puts "done"
- return true
- else
- puts "failed"
- puts "Aborting"
- run_script "git checkout master"
- return false
- end
- end
-
- def self.start_iteration(iteration, projects=PROJECTS)
- projects.each do |proj|
- print "Cutting branch #{iteration} for #{proj}..."
- result = run_script <<-EOH
- cd /code/#{proj}/
- git fetch
- git branch #{iteration} origin/master
- git push origin #{iteration}
- git push -f origin #{iteration}:qa
- EOH
- return unless result_ok?(result)
- end
- end
-
- def self.deploy_iteration(iteration, projects=PROJECTS)
- date = `date +%Y%m%d-%H%M`.strip
- tag = "#{iteration}-#{date}"
- puts "Starting deploy of #{iteration}"
- puts "Will tag with '#{tag}'"
- puts
-
- projects.each do |proj|
- print "Tagging #{proj}..."
- result = run_script <<-EOH
- cd /code/#{proj}/
- git stash
- git checkout qa
- git fetch
- git reset --hard origin/qa
- git tag -a #{tag} -m 'Release to live'
- EOH
- return unless result_ok?(result)
- end
-
- projects.each do |proj|
- print "Pushing #{proj}..."
- result = run_script <<-EOH
- cd /code/#{proj}/
- git push -f origin qa:live
- git push --tags
- git checkout master
- EOH
- #return unless result_ok?(result)
- end
-
- puts
- puts "Deploy of #{iteration} completed successfully."
+ def finish_usage_string(branch_type)
+ "expected usage: #{branch_type}_finish [<#{branch_type}_branch>]
+ #{branch_type}_branch: the name of the #{branch_type} branch to finish.
+ if omitted, you must currently be on a #{branch_type} branch"
end
end