139 lines
3.1 KiB
Ruby
139 lines
3.1 KiB
Ruby
|
#!/usr/bin/env ruby
|
||
|
|
||
|
require 'date'
|
||
|
|
||
|
Dir.chdir(File.dirname(__FILE__))
|
||
|
|
||
|
NEWS_HEADER_REGEX = /^(\d+)\.(\d+)\.(\d+) \(\d{4}-\d{2}-\d{2}\)$\n-+/
|
||
|
PARTS = ['major', 'minor', 'patch'].freeze
|
||
|
NEWS_HEADER = <<-NEWS
|
||
|
Development
|
||
|
-----------
|
||
|
|
||
|
### NOTICES
|
||
|
- None yet
|
||
|
|
||
|
### Features
|
||
|
- None yet
|
||
|
|
||
|
### Bug fixes / enhancements
|
||
|
- None yet
|
||
|
|
||
|
NEWS
|
||
|
|
||
|
class Version < Array
|
||
|
def initialize(parts)
|
||
|
raise "Expected three version parts" unless parts.count == 3
|
||
|
super(parts.map(&:to_i))
|
||
|
end
|
||
|
|
||
|
def bump(pos)
|
||
|
self[pos] += 1
|
||
|
(pos + 1..2).each { |p| self[p] = 0 }
|
||
|
end
|
||
|
|
||
|
def to_s
|
||
|
join('.')
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def version_from_tag(tag)
|
||
|
m = tag.match(/^v(\d+)\.(\d+)\.(\d+)$/)
|
||
|
raise "Could not parse tag #{tag}" unless m
|
||
|
|
||
|
Version.new(m[1..3])
|
||
|
end
|
||
|
|
||
|
def version_from_news(news)
|
||
|
m = news.match(NEWS_HEADER_REGEX)
|
||
|
raise "Could not find NEWS version" unless m
|
||
|
|
||
|
Version.new(m[1..3])
|
||
|
end
|
||
|
|
||
|
def updated_news(news, next_version)
|
||
|
NEWS_HEADER + tag_header(next_version) + clean_development(news)
|
||
|
end
|
||
|
|
||
|
def tag_header(next_version)
|
||
|
h = "#{next_version} (#{Date.today})"
|
||
|
h + "\n#{'-' * h.length}\n\n"
|
||
|
end
|
||
|
|
||
|
def clean_development(news)
|
||
|
development, header, rest = news.partition(NEWS_HEADER_REGEX)
|
||
|
development_lines = development.split("\n")
|
||
|
development_lines.delete('Development')
|
||
|
development_lines.delete('-----------')
|
||
|
|
||
|
# Write non-empty sections
|
||
|
news_sections(development_lines).map { |name, lines|
|
||
|
if name && lines.any? { |l| !l.strip.empty? }
|
||
|
"### #{name}\n#{lines.join("\n")}\n"
|
||
|
end
|
||
|
}.compact.join('') + "\n#{header}#{rest}"
|
||
|
end
|
||
|
|
||
|
def news_sections(lines)
|
||
|
sections = []
|
||
|
section_lines = []
|
||
|
section_name = nil
|
||
|
lines.each do |line|
|
||
|
if line.start_with?('###')
|
||
|
if section_name
|
||
|
sections << [section_name, section_lines]
|
||
|
end
|
||
|
section_lines = []
|
||
|
section_name = line[4..-1]
|
||
|
elsif line != '- None yet'
|
||
|
# Replace initial `-` for `*`
|
||
|
section_lines << line.sub(/^(\s*)-/, '\1*')
|
||
|
end
|
||
|
end
|
||
|
sections << [section_name, section_lines] if section_name
|
||
|
|
||
|
sections
|
||
|
end
|
||
|
|
||
|
def help
|
||
|
puts 'Usage: '
|
||
|
puts ' bump.rb [ major | minor | patch ] (defaults to `patch`)'
|
||
|
exit(1)
|
||
|
end
|
||
|
|
||
|
ARGV << 'patch' if ARGV.empty?
|
||
|
help unless ARGV.count == 1
|
||
|
|
||
|
raise 'Not in master branch' unless `git rev-parse --abbrev-ref HEAD`.strip == 'master'
|
||
|
|
||
|
puts 'Pulling and fetching tags...'
|
||
|
`git pull --tags`
|
||
|
|
||
|
news_content = File.read('NEWS.md')
|
||
|
|
||
|
puts 'Calculating current version...'
|
||
|
tag_version = version_from_tag(`git describe --abbrev=0`)
|
||
|
news_version = version_from_news(news_content)
|
||
|
|
||
|
unless tag_version == news_version
|
||
|
raise "Mismatched versions between git tag (#{tag_version}) and NEWS (#{news_version})"
|
||
|
end
|
||
|
|
||
|
part = PARTS.index(ARGV[0])
|
||
|
help unless part
|
||
|
|
||
|
next_version = tag_version.dup
|
||
|
next_version.bump(part)
|
||
|
|
||
|
puts "Bumping from #{tag_version} to #{next_version}. Enter to confirm, Ctrl+C to cancel"
|
||
|
STDIN.getc
|
||
|
|
||
|
puts 'Updating NEWS...'
|
||
|
File.write('NEWS.md', updated_news(news_content, next_version))
|
||
|
|
||
|
puts 'Committing, tagging and pushing...'
|
||
|
`git add NEWS.md`
|
||
|
`git commit -m "Bump to #{next_version}"`
|
||
|
`git tag -a v#{next_version} -m "Version #{next_version}"`
|
||
|
`git push origin master --follow-tags`
|