lib/octobox/changelog.rb
module Octobox
class Changelog
BASE = /Bump (?<name>.+?) from (?<from>.+?) to (?<to>.+?)/
BUMP_DEP_REGEX = /#{BASE}$/
BUMP_DEP_WITH_PR_REGEX = /#{BASE} \((?<pr>#\d+)\)/
def generate
puts "Updating the repository"
system("git fetch origin master 2>&1 > /dev/null")
puts "=" * 80
puts "We will be be basing this release on:"
puts " Current Commit: #{current_sha[0..6]}"
puts " Previous Release: #{previous_release}"
if current_sha[0..6] == previous_release
puts "=" * 80
puts "We have already released #{current_sha}. Exiting"
exit 1
end
changes = { dependencies: {}, other: [] }
messages.each do |message|
next if message.include?('Merge pull request') || message == 'Update dependencies'
case message
when /^Bump/
has_pr = message.include?('(#')
message_match = has_pr ? message.match(BUMP_DEP_WITH_PR_REGEX) : message.match(BUMP_DEP_REGEX)
curr = changes[:dependencies][message_match[:name]] || {}
# Between the last "to" and the current "to", we want the maximum version we updated to
to = [curr[:to], message_match[:to]].compact.max_by { |t| Gem::Version.new(t) }
# Between the last "from" and the current "from", we want the minimum version we updated from
from = [curr[:from], message_match[:from]].compact.min_by { |t| Gem::Version.new(t) }
# Combine the PRs
prs = [curr[:prs], has_pr ? message_match[:pr] : nil].flatten.compact.sort
changes[:dependencies][message_match[:name]] = { to: to, from: from, prs: prs }
else
changes[:other] << message
end
end
output_final_message(changes)
end
def previous_release
@previous_release ||= `git tag --sort=committerdate 2> /dev/null`.split("\n").last.chomp
end
def actual_sha
@actual_sha ||= `git rev-list -n 1 #{previous_release} 2> /dev/null`.lines.last.chomp
end
def current_sha
@current_sha ||= `git rev-parse --verify HEAD 2> /dev/null`.chomp
end
def messages
@messages = begin
msgs = `git log --oneline --pretty=format:"%s" --abbrev-commit #{previous_release}..#{current_sha} 2> /dev/null`
msgs.lines.map(&:chomp)
end
end
def output_final_message(changes)
puts "=" * 80
puts <<~EOF
The following release message was auto generated based on the above information.
Please make sure it is correct.
EOF
puts "=" * 80
deps = changes[:dependencies].sort_by { |k, _| k }.map.with_object([]) do |(dep, change), acc|
acc << "Updated #{dep} from #{change[:from]} to #{change[:to]} (#{change[:prs].join(', ')})"
end
final_message = <<~EOF
Dependency Updates
---
- #{deps.join("\n- ")}
Other
---
- #{changes[:other].join("\n- ")}
---
Full diff: https://github.com/octobox/octobox/compare/#{actual_sha[0..6]}...#{current_sha[0..6]}
EOF
puts final_message
end
end
end