lib/gitscape/base.rb in gitscape-0.2 vs lib/gitscape/base.rb in gitscape-1.1
- old
+ new
@@ -1,34 +1,126 @@
-class GitScape
- # Returns true if the supplied Git commit hash or reference exists
- def self.commit_exists?(commit_id)
- `git rev-parse #{commit_id}`
- if $? == 0
- true
+require "git"
+
+
+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
+ if git_version_at_least "1.7.4.0"
+ @merge_options += "-s recursive -Xignore-space-change"
else
- raise "Invalid commit/ref ID: #{commit_id}"
+ warn "Ignoring whitespace changes in merges is only available on Git 1.7.4+"
end
end
+ def branch_names
+ @repo.branches.map { |b| b.full }
+ end
- def self.abort!
+ # Get the system's current git version
+ def git_version
+ @git_version ||= `git --version`.strip.split(" ").last
+ end
+ def checkout(branch_name)
+ begin
+ @repo.revparse(branch_name)
+ rescue
+ raise Exception.new "No branch '#{branch_name}' found"
+ end
+ puts "Switching to branch '#{branch_name}'..."
+ @repo.checkout(branch_name)
end
- def self.compare(upstream, head)
- puts "#" * 80
- puts "# Commits on #{head} not on #{upstream}"
- puts "#" * 80
- puts
- `git cherry #{upstream} #{head}`.split("\n").select { |x| x.start_with? "+" }.each do |x|
- puts `git show -s --format=medium #{x.split(" ").last}`
- puts
- puts "-" * 80
- puts
+ # Check if the system's git version is at least as recent as the version specified
+ def git_version_at_least(min_version)
+ def split_version(v)
+ v.split(".").map { |x| x.to_i }
end
+ local_version = split_version(git_version)
+ min_version = split_version(min_version)
+
+ raise "Git version string must have 4 parts" if min_version.size != 4
+
+ 4.times do |i|
+ return false unless local_version[i] >= min_version[i]
+ end
+ true
end
+ def hotfix_start(hotfix_branch_name=nil)
+ checkout "master"
+
+ hotfix_branch_name = "hotfix/#{hotfix_branch_name}"
+ puts "Creating hotfix branch '#{hotfix_branch_name}'..."
+ @repo.checkout(@repo.branch.create(hotfix_branch_name))
+ end
+
+ def hotfix_finish(hotfix_branch_name=nil)
+ # TODO:
+ # 1. Tag the new live revision with 'live/<branch_name_without_prefix>'
+
+ usage_string = "expected usage: hotfix_finish [<hotfix_branch_name>]
+ hotfix_branch_name: the name of the hotfix branch to finish.
+ if ommitted, you must currently be on a hotfix branch"
+
+ previous_branch = @repo.current_branch
+
+ if previous_branch.start_with? "hotfix"
+ hotfix_branch_name ||= previous_branch
+ end
+
+ unless @repo.branches.include? hotfix_branch_name
+ end
+
+ merge_master = true
+
+ if hotfix_branch_name.empty?
+ puts "!!! not currently on a hotfix branch, and no branch name was provided as an argument !!!"
+ puts usage_string
+ exit 1
+ end
+
+ hotfix_branch = @repo.branch hotfix_branch_name
+ development_branch = @repo.branches.select {|branch| branch.full.start_with? "release/"}.sort.last
+ development_branch = @repo.branch "master" if development_branch == nil
+ live_branch = @repo.branch "live"
+
+ # Collect the set of branches we'd like to merge the hotfix into
+ merge_branches = [development_branch, live_branch]
+
+ # Merge the hotfix into branches
+ for branch in merge_branches
+ merge_options = @merge_options
+ merge_options += " --log" if branch == "master"
+
+ `git checkout #{branch.full}`
+ `git merge #{merge_options} #{hotfix_branch.full}`
+ exit 1 if !$?.success?
+ raise "Merge on #{branch.full} has failed.\nResolve the conflicts and run the script again." if git_has_conflicts
+ end
+
+ # Checkout previous branch for user convenience
+ `git checkout #{previous_branch}`
+ end
+
+
+ # Returns true if the supplied Git commit hash or reference exists
+ def self.commit_exists?(commit_id)
+ `git rev-parse #{commit_id}`
+ if $? == 0
+ true
+ 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
@@ -36,34 +128,20 @@
end
end
$?.exitstatus
end
- def promote_commit(commit_id, upstream)
- commit_exists? commit_id
- run_script <<-EOH
- git stash
- git checkout master
- git pull
- git checkout staging
- git reset --hard origin/staging
- git cherry-pick #{commit_id}
- git push origin staging
- EOH
- 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}
+ git fetch
+ git stash
+ git checkout #{head}
+ git reset --hard origin/#{head}
+ git push -f origin #{head}:#{upstream}
EOH
end
-
def self.result_ok?(result)
if result.nil? or result == 0
puts "done"
return true
else
@@ -72,11 +150,24 @@
run_script "git checkout master"
return false
end
end
- def self.deploy_iteration(iteration, projects=%w{android-client builder ios-client rails3 web-client})
+ 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