Skip to content

Instantly share code, notes, and snippets.

@anibalardid
Forked from dennisreimann/changelog
Created November 26, 2021 19:12
Show Gist options
  • Save anibalardid/1836dfa4e819eb33430b5d7c37d9015d to your computer and use it in GitHub Desktop.
Save anibalardid/1836dfa4e819eb33430b5d7c37d9015d to your computer and use it in GitHub Desktop.
CHANGELOG generator
#!/usr/bin/env ruby
#
# CHANGELOG generator
#
# Usage:
#
# $ changelog [SINCE UNTIL]
#
# This script collects git commits from a given range (SINCE and UNTIL
# are optional refs, SINCE defaults to the last tag, UNTIL to HEAD).
#
# It looks for markers which indictate that a commit should show up in
# the changelog. In this case it searches for tags inside brackets,
# e.g. [addition, change] which correspond to the according sections.
#
# Your milage may vary, but it should be easy to adapt.
#
# Example Output:
#
# Additions
# * Create changelog generator script (2h3gnm4r5t)
# * Write some documentation (89uyt3fze5)
#
# Changes
# * Yay, never again have to do this by hand (r64rtaq2ke)
#
require 'date'
# config
markers = {
addition: "Additions",
change: "Changes",
bugfix: "Bugfixes" }
pattern = "\\[.*(#{markers.keys.join('|')}).*\\]"
# take commit range from arguments, default to latest git tag and HEAD
_since = ARGV[0] || `git describe --tags --always`.strip
_until = ARGV[1] || 'HEAD'
range = "#{_since}..#{_until}"
# extract commits
log = `git log #{range} --grep="#{pattern}" -i -E --no-decorate`.strip
commits = log.split(/^commit /)[1..-1] || []
# collect output
marks = {}
commits.each do |commit|
lines = commit.lines
info = {
sha: lines[0].strip,
email: lines[1][/<(.*)>/, 1],
author: lines[1][/Author:\s+(.*) </, 1],
message: lines[4].strip,
extended: lines[6..-1].join(' ').strip,
date: DateTime.parse(lines[2][/Date:\s+(.*)/, 1])
}
commit_marks = commit.match(pattern)[0].gsub(/\[|\]/, '').split(/,\s*/)
commit_marks.each do |mark|
mark = mark.to_sym
marks[mark] ||= []
marks[mark] << info
end
end
# generate output
markers.each do |marker, title|
commits = marks[marker]
next unless commits
puts "#{title}\n\n"
commits.each { |commit| puts "* #{commit[:message]} (#{commit[:sha][0..9]})"}
puts ''
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment