desc "generate a release note from the important commits" task "release_note:generate", :from, :to do |t, args| from = args[:from] || `git describe --tags --abbrev=0`.strip to = args[:to] || "HEAD" bug_fixes = Set.new new_features = Set.new ux_changes = Set.new sec_changes = Set.new perf_changes = Set.new `git log #{from}..#{to}`.each_line do |comment| next if comment =~ /^\s*Revert/ split_comments(comment).each do |line| if line =~ /^FIX:/ bug_fixes << better(line) elsif line =~ /^FEATURE:/ new_features << better(line) elsif line =~ /^UX:/ ux_changes << better(line) elsif line =~ /^SECURITY:/ sec_changes << better(line) elsif line =~ /^PERF:/ perf_changes << better(line) end end end print_changes("NEW FEATURES", new_features) print_changes("BUG FIXES", bug_fixes) print_changes("UX CHANGES", ux_changes) print_changes("SECURITY CHANGES", sec_changes) print_changes("PERFORMANCE", perf_changes) end def print_changes(heading, changes) return if changes.length == 0 puts heading puts "-" * heading.length, "" puts changes.to_a, "" end def better(line) line = remove_prefix(line) line = escape_brackets(line) line[0] = '\#' if line[0] == '#' line[0] = line[0].capitalize "- " + line end def remove_prefix(line) line.gsub(/^(FIX|FEATURE|UX|SECURITY|PERF):/, "").strip end def escape_brackets(line) line.gsub("<", "`<") .gsub(">", ">`") .gsub("[", "`[") .gsub("]", "]`") end def split_comments(text) text = normalize_terms(text) terms = ["FIX:", "FEATURE:", "UX:", "SECURITY:" , "PERF:"] terms.each do |term| text = newlines_at_term(text, term) end text.split("\n") end def normalize_terms(text) text = text.gsub(/(BUGFIX|FIX|BUG):/i, "FIX:") text = text.gsub(/FEATURE:/i, "FEATURE:") text = text.gsub(/UX:/i, "UX:") text = text.gsub(/(SECURITY):/i, "SECURITY:") text = text.gsub(/(PERF):/i, "PERF:") end def newlines_at_term(text, term) if text.include?(term) text = text.split(term).map { |l| l.strip }.join("\n#{term} ") end text end