#!/usr/bin/env perl =pod =head1 NAME git-changelog - generate a Debian changelog based on tags or on all commits =head1 SYNOPSIS git-changeloge [ B<--project=...> B<--distribution=...>] =head1 DESCRIPTION Should produce a Debian changelog, more or less, based on the git commit log and tags for the current directory. The idea here is that each tag represents a version, and should contain bullet points for each commit since the previous version. =head1 CAVEATS Urgency is just hardcoded to "high". I guess it probably ought to be... Sensitive to semver or something? I don't really know. =head1 AUTHOR Brennen Bearnes =head1 COPYING Knock yourself out. To the extent possible under law, Brennen Bearnes has waived all copyright and related or neighboring rights to git-changelog. =cut use warnings; use strict; use 5.10.0; use Getopt::Long; use POSIX qw(strftime); my $project_name = 'project'; my $distribution = 'distribution'; GetOptions( "project:s" => \$project_name, "distribution:s" => \$distribution, ); # See PRETTY FORMATS in git-log(1) for placeholders. # https://git-scm.com/docs/pretty-formats open (my $logstream, "git log --reverse --pretty='format:%H\t%d\t%aD\t%aN\t%aE\t%s' |") or die("$0: Failed to run git\n$!\n"); my @changes; my @changelog_entries; while (my $line = <$logstream>) { chomp($line); my @fields = split "\t", $line; my ($hash, $decoration, $date, $author_name, $author_mail, $subject) = @fields; my $author = "$author_name <$author_mail>"; # Tags come in from the decoration field - placeholder %d - with (tag: foo) # That might or might not be followed with other stuff like (tag: foo, ...) # There's probably a fragile assumption in this, I'm not quite sure what # happens when more than one tag points at the same commit. my $tag; if ($decoration =~ m{^[ ] \( tag:[ ](.*?) \) }x) { $tag = $1; if ($tag =~ m/(.*?),/) { $tag = $1; } } # Accumulate commit subject lines: push @changes, $subject; # Every time we hit a tag, create a changelog entry with the accumulated # bullet points from changes represented by all the preceding commits. if ($tag) { my $bullets = ''; foreach my $change (@changes) { if ($change) { $bullets .= " * $change\n"; } } # Clear out the change list. @changes = (); push @changelog_entries, changelog($tag, $date, $author, $project_name, $bullets, $distribution); } } # Reverse these so they're in the proper new-to-old order: foreach my $entry (reverse @changelog_entries) { say $entry; } # Pretty much just a template. sub changelog { my ($tag, $date, $author, $project_name, $body, $distribution) = @_; return <<"CHANGELOG"; $project_name ($tag) $distribution; urgency=high $body -- $author $date CHANGELOG }