App-Changelog
view release on metacpan or search on metacpan
lib/App/Changelog.pm view on Meta::CPAN
package App::Changelog;
use strict;
use warnings;
use feature 'say';
our $VERSION = '1.0.2';
sub new {
my ( $class, %args ) = @_;
my $self = {
output_file => $args{output_file} || 'CHANGELOG.md',
compact => $args{compact} // 1,
filter_tag => $args{filter_tag} || '',
conventional => $args{conventional} // 0,
};
bless $self, $class;
return $self;
}
sub generate_changelog {
my ($self) = @_;
say "Generating changelog from Git history...";
my $git_log_format =
$self->{compact} ? '--pretty=format:"%h %s"' : '--pretty=fuller';
if ( $self->{conventional} ) {
$git_log_format = '--pretty=format:"%h %s (%an)"';
}
my $git_log =
$self->_run_git_command("git log $git_log_format --abbrev-commit");
if ( !$git_log ) {
die
"Error: Could not retrieve Git history. Are you in a Git repository?\n";
}
my @tags = $self->_get_tags();
my $changelog_content =
$self->_build_changelog_content( \@tags, $git_log_format );
$self->_write_to_file($changelog_content);
say "Changelog generated successfully in $self->{output_file}.";
}
sub _build_changelog_content {
my ( $self, $tags, $format ) = @_;
my $content = "# Changelog\n\n";
for my $i ( 0 .. $#$tags ) {
my $current_tag = $tags->[$i];
my $previous_tag = $i == $#$tags ? '' : $tags->[ $i + 1 ];
my $log_command =
$previous_tag
? "git log $previous_tag..$current_tag $format"
: "git log $current_tag $format";
my $logs = $self->_run_git_command($log_command);
$logs = $self->_filter_conventional_commits($logs)
if $self->{conventional};
my $date =
$self->_run_git_command("git log -1 --format=%ai $current_tag");
$date =~ s/\s.*$//;
$content .= "## [$current_tag] - $date\n\n";
unless ( $self->{conventional} ) {
$content .= "$logs\n" if $logs;
}
else {
my %grouped_commits;
my @log_lines = split( "\n", $logs );
for my $log (@log_lines) {
if ( $log =~ /^[a-f0-9]+\s([a-z]+):\s*(.*)$/ ) {
my $type = $1;
my $message = $2;
push @{ $grouped_commits{$type} }, $message;
}
}
for my $type ( sort keys %grouped_commits ) {
$content .= "### " . ucfirst($type) . "\n";
for my $message ( @{ $grouped_commits{$type} } ) {
$content .= "- $type: $message\n";
}
$content .= "\n";
}
}
}
return $content;
}
sub _filter_conventional_commits {
my ( $self, $logs ) = @_;
my @lines = split( /\n/, $logs );
my @filtered;
foreach my $line (@lines) {
( run in 2.440 seconds using v1.01-cache-2.11-cpan-364913b4093 )