lib/gitscape/base.rb in gitscape-1.1 vs lib/gitscape/base.rb in gitscape-1.2
- old
+ new
@@ -19,47 +19,66 @@
def branch_names
@repo.branches.map { |b| b.full }
end
- # 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
- # 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 }
+ def git_working_copy_is_clean puts_changes=true
+ # Check if the working copy is clean, if not, exit
+ changes = `git status -uno --ignore-submodules=all --porcelain`
+ working_copy_clean = changes.length == 0
+ if !working_copy_clean && puts_changes
+ puts "Your working copy is not clean, either commit, stash, or reset your changes then try again."
+ puts changes
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
+ working_copy_clean
+ end
- 4.times do |i|
- return false unless local_version[i] >= min_version[i]
- end
- true
+ def live_current_version_number
+ current_branch = @repo.current_branch
+ live_branch = @repo.branch "live"
+
+ `git checkout #{live_branch.full}` unless current_branch == live_branch
+
+ version_file = File.new("version", "r")
+ live_current_version_number = version_file.read.delete("i").to_i
+
+ `git checkout #{current_branch}` unless current_branch == live_branch
+
+ live_current_version_number
end
+ def git_has_conflicts puts_conflicts=true
+ conflicts_status = `git status --porcelain | grep UU`
+ has_conflicts = conflicts_status.length > 0
+
+ puts conflicts_status if has_conflicts && puts_conflicts
+
+ has_conflicts
+ end
+
def hotfix_start(hotfix_branch_name=nil)
- checkout "master"
+ checkout "live"
+ if hotfix_branch_name.length == 0
+ exception_message = "*** Improper Usage ***\nExpected Usage: hotfix_start <hotfix_branch_name>"
+ raise exception_message
+ end
+
hotfix_branch_name = "hotfix/#{hotfix_branch_name}"
puts "Creating hotfix branch '#{hotfix_branch_name}'..."
- @repo.checkout(@repo.branch.create(hotfix_branch_name))
+ @repo.checkout(@repo.branch(hotfix_branch_name).create)
end
def hotfix_finish(hotfix_branch_name=nil)
# TODO:
# 1. Tag the new live revision with 'live/<branch_name_without_prefix>'
@@ -106,11 +125,100 @@
# Checkout previous branch for user convenience
`git checkout #{previous_branch}`
end
+ def release_finish new_version_number=0
+ # Check if the working copy is clean, if not, exit
+ exit 1 unless git_working_copy_is_clean
+ # Get the right release_branch_name to merge
+ current_version_number = new_version_number - 1
+ if new_version_number == 0
+ current_version_number = live_current_version_number
+ new_version_number = current_version_number + 1
+ end
+ release_branch_name = "release/i#{new_version_number}"
+ release_branch = @repo.branch release_branch_name
+
+ # Get branch information for checks
+ branch_keys = ["name", "revision", "message"]
+ branch_values = `git branch -av`.scan(/^[ \*]*([^ \*]+) +([^ ]+) +(.*)$/)
+ branches = branch_values.map {|components| Hash[ branch_keys.zip components ] }
+ branch_revisions = Hash[ branches.map {|branch| [branch["name"], branch["revision"]] } ]
+
+ # Check if the required branches in sync
+ required_synced_branches = [ [release_branch_name, "remotes/origin/qa"], ["master", "remotes/origin/master"], ["live", "remotes/origin/live"] ]
+ required_synced_branches.each do |branch_pair|
+ if branch_revisions[ branch_pair[0] ] != branch_revisions[ branch_pair[0] ]
+ puts "*** ERROR: The #{branch_pair[0]} branch is not the same as the #{branch_pair[1]} branch.
+ \tPlease resolve this and try again."
+ exit 3
+ end
+ end
+
+ # Checkout live
+ `git checkout live`
+
+ # Record the revision of live used for the rollback tag
+ live_rollback_revision = `git log -n1 --oneline`.scan(/(^[^ ]+) .*$/).flatten[0]
+
+ merge_options = "--no-ff -s recursive -Xignore-space-change"
+
+ # Merge the release branch into live
+ `git merge #{merge_options} #{release_branch_name}`
+
+ # Error and conflict checking
+ if !$?.success? then exit 4 end
+ if git_has_conflicts then
+ puts "Merge conflicts when pulling #{release_branch_name} into live"
+ puts "Please bother Xavier 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 --stat live origin/qa`
+ if critical_diff.length > 0
+ puts "This live merge has code that was not on the qa branch."
+ 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 whether the release should happen."
+ exit 3
+ end
+
+ # Record the revision of live used for the release tag
+ live_release_revision = `git log -n1 --oneline`.scan(/(^[^ ]+) .*$/).flatten[0]
+
+ # Merge the release branch into master
+ `git checkout master`
+ `git merge #{merge_options} #{release_branch_name}`
+
+ # Error and conflict checking
+ if !$?.success? then exit 4 end
+ if git_has_conflicts then
+ puts "Merge conflicts when pulling #{release_branch_name} into master"
+ puts "Please bother Xavier if you see this message :)"
+ exit 2
+ end
+
+ # Tag the state of live for both release and rollback
+ `git tag rollback-to/i#{current_version_number} #{live_rollback_revision}`
+ if !$?.success? then
+ puts "=== WARNING: Failed to create rollback-to/i#{current_version_number} tag"
+ `git tag -d rollback-to/i#{current_version_number}`
+ end
+
+ `git tag live/i#{new_version_number}/release #{live_release_revision}`
+ if !$?.success? then
+ `git tag -d rollback-to/i#{current_version_number}`
+ `git tag -d live/i#{new_version_number}/release #{live_release_revision}`
+ exit 4
+ end
+
+ `git push origin live --tags`
+ `git push origin master`
+ 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
@@ -136,9 +244,30 @@
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
+
+ # 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 self.result_ok?(result)
if result.nil? or result == 0
puts "done"