Permalink
Cannot retrieve contributors at this time
Fetching contributors…

require 'time' | |
module StepUp | |
module Driver | |
class Git < Base | |
VERSION_MESSAGE_FILE_PATH = ".git/TAG_EDITMSG" | |
NOTE_MESSAGE_FILE_PATH = ".git/NOTE_EDITMSG" | |
include GitExtensions::Notes | |
def unsupported_scm_banner | |
if `git --version`.chomp =~ /\d\.[^\s]+/ | |
v = $& | |
if Gem::Version.correct?(v) | |
if Gem::Version.new("1.7.1") > Gem::Version.new(v) | |
"Unsupported installed GIT version: #{v}\n" + | |
"Please install version 1.7.1 or newer" | |
end | |
else | |
"Installed GIT version unknown: #{v}" | |
end | |
else | |
super | |
end | |
end | |
def self.last_version | |
new.last_version_tag | |
end | |
def empty_repository? | |
`git branch`.empty? | |
end | |
def commit_history(commit_base, *args) | |
return [] if empty_repository? | |
options = args.last.is_a?(Hash) ? args.pop : {} | |
top = args.shift | |
top = "-n#{ top }" unless top.nil? | |
encoding = CONFIG["log_output_encoding"] || "ISO-8859-1" | |
commits = `git log --pretty=oneline --encoding=#{ encoding } --no-color #{ top } #{ commit_base }` | |
commits.force_encoding(encoding) if RUBY_VERSION.to_f >= 1.9 | |
begin | |
if options[:with_messages] | |
commits.scan(/^(\w+)\s+(.*)$/) | |
else | |
commits.scan(/^(\w+)\s/).flatten | |
end | |
rescue ArgumentError => e | |
if e.message.start_with?("invalid byte sequence") | |
puts <<-MSG | |
Could not read information from git-log because of an #{e.message}. | |
To fix this you can insert an attribute "log_output_encoding" on | |
file .stepuprc into your GIT project. Example: | |
\033[30;1m# .stepuprc\033[0m | |
\033[32m+log_output_encoding: "ISO-8859-1"\033[0m | |
notes: | |
after_versioned: | |
strategy: "keep" # Valid options: "keep" or "remove" | |
\033[30;1m# ...\033[0m | |
To see the current encoding from your GIT repository, you may | |
check with the following bash command: | |
`git log --pretty=oneline --no-color > test.txt && file test.txt && rm test.txt` | |
MSG | |
exit 1 | |
end | |
raise | |
end | |
end | |
def commits_between(first_commit, last_commit = "HEAD", *args) | |
commit_base = first_commit.nil? ? last_commit : "#{ first_commit }..#{ last_commit }" | |
commit_history(commit_base, *args) | |
end | |
def tags | |
@tags ||= `git tag -l` | |
end | |
def objects_with_notes_of(ref) | |
`git notes --ref=#{ ref } list`.scan(/\w+$/) | |
end | |
def note_message(ref, commit) | |
`git notes --ref=#{ ref } show #{ commit }` | |
end | |
def all_version_tags | |
@version_tags ||= tags.scan(mask.regex).map{ |tag| tag.collect(&:to_i) }.sort.map{ |tag| mask.format(tag) }.reverse | |
end | |
def version_tag_info(tag) | |
full_message = `git show #{ tag } --pretty=medium --no-decorate --quiet --date=default`.force_encoding('utf-8') | |
tag_pattern = tag.gsub(/\./, '\\.') | |
tag_message = full_message[/^tag\s#{tag_pattern}.*?\n\n(.*?)\n\n(?:tag\s[^\s]+|commit\s\w{40})\n/m, 1] || "" | |
tagger = full_message[/\A.*?\nTagger:\s(.*?)\s</m, 1] | |
date = Time.parse(full_message[/\A.*?\nDate:\s+(.*?)\n/m, 1]) | |
{:message => tag_message, :tagger => tagger, :date => date} | |
end | |
def detached_notes_as_hash(commit_base = "HEAD", notes_sections = nil) | |
tag = all_version_tags.any? ? cached_last_version_tag(commit_base) : nil | |
tag = tag.sub(/\+$/, '') unless tag.nil? | |
RangedNotes.new(self, tag, commit_base, :notes_sections => notes_sections).notes.as_hash | |
end | |
def next_release_level(commit_base) | |
level = CONFIG.versioning.version_levels.last | |
if CONFIG.versioning["auto_increment"].is_a?(Hash) | |
detached_notes = cached_detached_notes_as_hash(commit_base) | |
CONFIG.versioning.version_levels.reverse.each do |name| | |
sections = CONFIG.versioning.auto_increment.sections_level[name] | |
next if sections.nil? | |
level = name if detached_notes.any?{ |section, notes| sections.include?(section) && notes.any? } | |
end | |
end | |
level | |
end | |
def next_version_tag(commit_base, level = nil) | |
level = next_release_level(commit_base) if level.nil? | |
if commit_base && mask.parse(commit_base) | |
mask.increase_version(commit_base, level) | |
else | |
tag = cached_last_version_tag(commit_base) | |
tag =~ /\+/ ? mask.increase_version($`, level) : nil | |
end | |
end | |
def steps_to_increase_version(level, commit_base = "HEAD", message = nil) | |
new_tag = next_version_tag(commit_base, level) | |
if new_tag.nil? or new_tag.empty? | |
STDERR.puts "Current release #{cached_last_version_tag(commit_base)}" | |
exit 0 | |
end | |
notes = cached_detached_notes_as_hash(commit_base) | |
commands = [] | |
commands << "git fetch" if cached_fetched_remotes.any? | |
commands << "git tag -a -m \"#{ (message || notes.to_changelog).gsub(/([\$\\"`])/, '\\\\\1') }\" #{ new_tag } #{ commit_base }" | |
commands << "git push #{cached_fetched_remotes("notes").first} refs/tags/#{new_tag}" if cached_fetched_remotes.any? | |
commands + steps_for_archiving_notes(notes, new_tag) | |
end | |
def last_version_tag(commit_base = "HEAD", count_commits = false) | |
all_versions = all_version_tags | |
unless all_versions.empty? | |
commits = cached_commit_history(commit_base) | |
all_versions.each do |tag| | |
commit_under_the_tag = commit_history(tag, 1).first | |
index = commits.index(commit_under_the_tag) | |
unless index.nil? | |
unless index.zero? | |
count = count_commits == true ? commits_between(tag, commit_base).size : 0 | |
tag = "#{ tag }+#{ count unless count.zero? }" | |
end | |
return tag | |
end | |
end | |
count_commits == true ? zero_version(commit_base, true) : nil | |
else | |
zero_version(commit_base, count_commits) | |
end | |
end | |
def fetched_remotes(refs_type = 'heads') | |
config = `git config --get-regexp 'remote'`.split(/\n/) | |
config.collect{ |line| | |
$1 if line =~ /^remote\.(\w+)\.fetch\s\+refs\/#{ refs_type }/ | |
}.compact.uniq.sort | |
end | |
def editor_name | |
ENV["GIT_EDITOR"] || ENV["EDITOR"] || `git config core.editor`.chomp | |
end | |
def zero_version(commit_base = "HEAD", count_commits = false) | |
"%s+%s" % [mask.blank, "#{ commit_history(commit_base).size if count_commits }"] | |
end | |
end | |
end | |
end |