Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating to new specifications #22

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Metrics/LineLength:
Max: 160

Style/FormatStringToken:
Enabled: false

Metrics/MethodLength:
Enabled: false

Style/MutableConstant:
Enabled: false
41 changes: 41 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
PATH
remote: .
specs:
plusbump (2.0.0.beta)
docopt (~> 0.6.1)
rugged (~> 0.26)
semver (~> 1.0)

GEM
remote: https://rubygems.org/
specs:
diff-lcs (1.3)
docopt (0.6.1)
rake (10.5.0)
rspec (3.7.0)
rspec-core (~> 3.7.0)
rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.7.0)
rspec-core (3.7.1)
rspec-support (~> 3.7.0)
rspec-expectations (3.7.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.7.0)
rspec-mocks (3.7.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.7.0)
rspec-support (3.7.1)
rugged (0.27.4)
semver (1.0.1)

PLATFORMS
ruby

DEPENDENCIES
bundler (~> 1.14)
plusbump!
rake (~> 10.0)
rspec (~> 3.7)

BUNDLED WITH
1.16.2
16 changes: 10 additions & 6 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
require "bundler/gem_tasks"
require "rspec/core/rake_task"
require 'bundler/gem_tasks'
require 'rspec/core/rake_task'

RSpec::Core::RakeTask.new(:spec)

task :default => :spec
task default: :spec

desc "Verbose test output"
task :doc do
desc 'Verbose test output'
task :doc do
puts `rspec --format doc`
end
end

task :lint do
puts `rubocop`
end
6 changes: 3 additions & 3 deletions bin/console
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env ruby

require "bundler/setup"
require "plusbump"
require 'bundler/setup'
require 'plusbump'

# You can add fixtures and/or initialization code here to make experimenting
# with your gem easier. You can also use a different console, if you like.
Expand All @@ -10,5 +10,5 @@ require "plusbump"
# require "pry"
# Pry.start

require "irb"
require 'irb'
IRB.start(__FILE__)
42 changes: 4 additions & 38 deletions bin/plusbump
Original file line number Diff line number Diff line change
@@ -1,49 +1,15 @@
#!/usr/bin/env ruby
#encoding: utf-8
require 'docopt'
require 'plusbump'

doc = <<DOCOPT
Usage:
plusbump -h|--help
plusbump <ref> [options]
plusbump --latest=<tag-glob> [options]
plusbump --version

Arguments:
<ref> A git reference. If specified, PlusBump will search for bumps from HEAD back to this <ref> instead of searching for a tag.

Options:
-h --help Show this screen.

-l --latest=<tag-glob>

Specify a glob pattern to search for last matching tag instead of
providing a specific ref.
Will attempt to use everything after <tag-glob> as the version string
so be sure to provide _entire_ prefix.
E.g. use "R_" if your versions are "R_1.2.3"

--version Shows current version of PlusBump
--debug Debug flag

DOCOPT

# Note: If you are reading the above usage in the source code and not using --help,
# then ignore the double escapes in the usage examples.
# On the command line you have to write --majorpattern='\+major'
# The extra escape is to make it print that way in the usage message.

begin
# Parse Commandline Arguments
input = Docopt::docopt(doc, version: PlusBump::VERSION)
puts input if input['--debug']
input = Docopt.docopt(PlusBump::DOCOPT, version: PlusBump::VERSION)
puts input if input['--debug']
rescue Docopt::Exit => e
puts e.message
exit
end

#TODO: input['--latest'].flatten[0]
puts PlusBump.bump(input['<ref>'], input['--latest'], debug: input['--debug'])


result = PlusBump.bump(input)
PlusBump::Tag.create(result) if input['--create-tag'] && result
221 changes: 146 additions & 75 deletions lib/plusbump.rb
Original file line number Diff line number Diff line change
@@ -1,101 +1,172 @@
require "plusbump/version"
require 'plusbump/version'
require 'plusbump/usage'
require 'plusbump/config'
require 'semver'
require 'rugged'

# PlusBump main module
module PlusBump
def self.bump(ref, latest, debug: false)

# Defaults
major = /\+major/
minor = /\+minor/
patch = /\+patch/
base = '0.0.0'
prefix = ''

# Init Repo from current directory
repository = Rugged::Repository.new(Dir.pwd)
tagcollection = Rugged::TagCollection.new(repository)
@repo = nil

def self.repo
@repo ||= Rugged::Repository.new(Dir.pwd)
@repo
end

class Tag
def self.create(tag_name)
target = PlusBump.repo.head.target
ref = PlusBump.repo.tags.create(tag_name, target)
puts "Created tag #{tag_name}" if ref
end

def self.delete(tag_name)
tag_to_delete = PlusBump.repo.tags[tag_name]
PlusBump.repo.references.delete(tag_to_delete) if tag_to_delete
end
end

def self.extract_number(partial)
/\d+/.match(partial)[0] if /\d+/ =~ partial
end

def self.extract_prefix(partial)
/\D+/.match(partial)[0] if /\D+/ =~ partial
end

def self.transform(input)
Hash.new( input.map { |k,v|
[k.replace('-','').to_s,v]
})
end

def self.bump(input)
if input['--from-tag']
bump_by_tag(glob: input['--from-tag'],
base: input['--base-version'],
prefix: input['--new-prefix'] || '',
tag_replacement: input['--base-version-from-tag'],
major_pattern: input['--major-pattern'],
minor_pattern: input['--minor-pattern'],
patch_pattern: input['--patch-pattern'],
debug: input['--debug'])
elsif input['--from-ref']
bump_by_ref(ref: input['--from-ref'],
semver: input['--base-version'],
prefix: input['--new-prefix'] || '',
major_pattern: input['--major-pattern'],
minor_pattern: input['--minor-pattern'],
patch_pattern: input['--patch-pattern'],
debug: input['--debug'])
end
end

def self.create_walker(repository)
w = Rugged::Walker.new(repository)
# Initialise the walker to start at current HEAD
head = repository.lookup(repository.head.target.oid)
w.push(head)
w
end

if latest.nil?
tail = repository.rev_parse(ref)
w.hide(tail)
else
candidates = []
puts "Searching for at tag that matches the glob pattern: " + latest if debug
tagcollection.each(latest+'*') do |tag|
unless repository.merge_base(tag.target, head).nil?
puts "Found matching tag on correct branch: " + tag.name if debug
candidates << tag
end
end
# TODO: Need fixing!
def self.current_semver()

if candidates.empty?
puts "No matching tag found for "+latest
else
candidates.sort! {|a,b| a.target.time <=> b.target.time }
latest_match = candidates.last
puts "Newest matching tag: #{latest_match.name}" if debug
puts "Newest matching tag sha: #{latest_match.target.oid}" if debug
#set target of matching commit as the tail of our walker
w.hide(latest_match.target)
#unless input['<semver_version_string>']
base = latest_match.name.sub(latest,'')
puts "latest: #{latest}" if debug
puts "match.Name: #{latest_match.name}" if debug
puts "Base: #{base}" if debug
#end

end
end

def self.bump_by_ref(args = {})
semver_string = args[:semver] || PlusBump::BASE
w = create_walker(PlusBump.repo)
tail = PlusBump.repo.rev_parse(args[:ref])
w.hide(tail)

v_number = semver_string.split('.')
v_special = semver_string.split('-').size > 1 ? semver_string.split('-')[-1] : ''

# Current semver string
result = SemVer.new(extract_number(v_number[0]).to_i, v_number[1].to_i, v_number[2].to_i, v_special) # TODO: Fix special

# Logic bump
bump_action(w, result, major_p: args[:major_pattern], minor_p: args[:minor_pattern], patch_p: args[:patch_pattern])
final_res = extract_prefix(v_number[0]) || '' + (result.format "%M.%m.%p%s")
end

# Should return a Rugged::Tag object
def self.find_newest_matching_tag(candidates)
candidates.sort! { |a,b| a.target.time <=> b.target.time }
candidates.last
end

# The justification for this method is to split a semver tag into it's composite parts. Major.Minor.Patch[+-]....
# We need these parts to construct the SemVer object
def self.parse_semver_parts(base)
main = base.split(/[\+\-]/) # Should split something like Release_1.2.3-beta1+001 into two parts.
version_part = main[0].split('.')
# Clean up the version part...extract all numbers excluding non-numerical characters
version_part.map! { |elem| extract_number(elem) }
special_part = main[1..-1] || ''
return { :version_part => version_part, :special_part => special_part.join('') }
end

def self.bump_by_tag(args = {})
base = '0.0.0'
# Init Repo from current directory
tagcollection = Rugged::TagCollection.new(PlusBump.repo)
w = create_walker(PlusBump.repo)
head = PlusBump.repo.lookup(PlusBump.repo.head.target.oid)
candidates = []
tagcollection.each(args[:glob] + '*') do |tag|
candidates << tag if !PlusBump.repo.merge_base(tag.target, head).nil?
end

# Handle X.Y.Z-SPECIAL by saving SPECIAL part for later
split = base.split('-')
v_number = split[0].split('.')
special = ''
if candidates.empty?
puts 'No matching tag found for ' + args[:glob]
else
latest_match = find_newest_matching_tag(candidates)
# Set target of matching commit as the tail of our walker
w.hide(latest_match.target)
base = latest_match.name
puts "Found matching tag #{latest_match.name}" if args[:debug]
end

#TODO: Above could probably be re-written to use the semver gem for parsing.
# Current semver string
unless args[:tag_replacement].nil?
replacer = args[:tag_replacement] || ''
parts = parse_semver_parts(base)
result = SemVer.new(parts[:version_part][0].sub(replacer, '').to_i, parts[:version_part][1].to_i, parts[:version_part][2].to_i, parts[:special_part])
else
parts = parse_semver_parts(args[:base])
result = SemVer.new(parts[:version_part][0].to_i, parts[:version_part][1].to_i, parts[:version_part][2].to_i, parts[:special_part]) # TODO: FIX SPECIAL
end
# Logic bumps
bump_action(w, result, major_p: args[:major_pattern], minor_p: args[:minor_pattern], patch_p: args[:patch_pattern])
args[:prefix] + (result.format "%M.%m.%p%s")
end

major_bump = false
def self.bump_action(walker, semver, **args)
# Defaults
major = Regexp.new(Regexp.quote(args[:major_p] || PlusBump::MAJOR))
minor = Regexp.new(Regexp.quote(args[:minor_p] || PlusBump::MINOR))
patch = Regexp.new(Regexp.quote(args[:patch_p] || PlusBump::PATCH))
minor_bump = false
patch_bump = false

#walk through all commits looking for version bump requests
w.each do |commit|
puts "Commit: " + commit.oid if debug
walker.each do |commit|
if major =~ commit.message
puts "bumps major" if debug
major_bump = true
elsif minor =~ commit.message
puts "bump minor" if debug
minor_bump = true
else
patch_bump = true
semver.major += 1
semver.minor = 0
semver.patch = 0
return :major
end
minor_bump = true if minor =~ commit.message
end

result = SemVer.new(v_number[0].to_i, v_number[1].to_i, v_number[2].to_i, special)

if major_bump
result.major += 1
result.minor = 0
result.patch = 0
elsif minor_bump
result.minor += 1
result.patch = 0
elsif patch_bump
result.patch += 1
if minor_bump
semver.minor += 1
semver.patch = 0
return :minor
else
puts "No version increment"
semver.patch += 1
return :patch
end

final_res = prefix + (result.format "%M.%m.%p%s")

return final_res
end
end
Loading