Skip to content
Permalink
Browse files

Use the git log to ease release note management.

The release notes are generally a direct reflection of the git log.  So, ease the burden of maintaining the release notes by using the git log to determine what needs to be added.

Currently only non-dev items are required to be matched to a git commit but the goal is to account for all commits.

The git history cache is generated from the git log but can be modified to correct typos and match the release notes as they evolve.  The commit hash is used to identify commits that have already been added to the cache.

There's plenty more to do here.  For instance, links to the commits for each release item should be added to the release notes.
  • Loading branch information...
dwsteele committed May 22, 2019
1 parent 86482c7 commit ec9622cde883c649c1346cbc0b9057e7f3fcb787
@@ -167,8 +167,8 @@ sub new
(
__PACKAGE__ . '->new', \@_,
{name => 'strType'},
{name => 'oManifest'},
{name => 'bExe'},
{name => 'oManifest', required => false},
{name => 'bExe', required => false},
{name => 'strRenderOutKey', required => false}
);

@@ -275,6 +275,20 @@ sub new
);
}

####################################################################################################################################
# Set begin and end values for a tag
####################################################################################################################################
sub tagSet
{
my $self = shift;
my $strTag = shift;
my $strBegin = shift;
my $strEnd = shift;

$oRenderTag->{$self->{strType}}{$strTag}[0] = defined($strBegin) ? $strBegin : '';
$oRenderTag->{$self->{strType}}{$strTag}[1] = defined($strEnd) ? $strEnd : '';
}

####################################################################################################################################
# variableReplace
#
@@ -284,7 +298,7 @@ sub variableReplace
{
my $self = shift;

return $self->{oManifest}->variableReplace(shift, $self->{strType});
return defined($self->{oManifest}) ? $self->{oManifest}->variableReplace(shift, $self->{strType}) : shift;
}

####################################################################################################################################
@@ -7,11 +7,15 @@ use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);

use Cwd qw(abs_path);
use Exporter qw(import);
our @EXPORT = qw();
use File::Basename qw(dirname);

use pgBackRest::Common::Log;
use pgBackRest::Common::String;
use pgBackRest::Version;

use pgBackRestBuild::Config::Data;

use BackRestDoc::Common::DocRender;
@@ -245,6 +249,60 @@ sub contributorTextGet
return $strContributorText;
}

####################################################################################################################################
# Find a commit by subject prefix. Error if the prefix appears more than once.
####################################################################################################################################
sub commitFindSubject
{
my $self = shift;
my $rhyCommit = shift;
my $strSubjectPrefix = shift;
my $bRegExp = shift;

$bRegExp = defined($bRegExp) ? $bRegExp : true;
my $rhResult = undef;

foreach my $rhCommit (@{$rhyCommit})
{
if (($bRegExp && $rhCommit->{subject} =~ /^$strSubjectPrefix/) ||
(!$bRegExp && length($rhCommit->{subject}) >= length($strSubjectPrefix) &&
substr($rhCommit->{subject}, 0, length($strSubjectPrefix)) eq $strSubjectPrefix))
{
if (defined($rhResult))
{
confess &log(ERROR, "subject prefix '${strSubjectPrefix}' already found in commit " . $rhCommit->{commit});
}

$rhResult = $rhCommit;
}
}

return $rhResult;
}

####################################################################################################################################
# Throw an error that includes a list of release commits
####################################################################################################################################
sub commitError
{
my $self = shift;
my $strMessage = shift;
my $rstryCommitRemaining = shift;
my $rhyCommit = shift;

my $strList;

foreach my $strCommit (@{$rstryCommitRemaining})
{
$strList .=
(defined($strList) ? "\n" : '') .
substr($rhyCommit->{$strCommit}{date}, 0, length($rhyCommit->{$strCommit}{date}) - 15) . " $strCommit: " .
$rhyCommit->{$strCommit}{subject};
}

confess &log(ERROR, "${strMessage}:\n${strList}");
}

####################################################################################################################################
# docGet
#
@@ -257,6 +315,15 @@ sub docGet
# Assign function parameters, defaults, and log debug info
my $strOperation = logDebugParam(__PACKAGE__ . '->docGet');

# Load the git history
my $oStorageDoc = new pgBackRest::Storage::Local(
dirname(abs_path($0)), new pgBackRest::Storage::Posix::Driver({bFileSync => false, bPathSync => false}));
my @hyGitLog = @{(JSON::PP->new()->allow_nonref())->decode(${$oStorageDoc->get("resource/git-history.cache")})};

# Get renderer
my $oRender = new BackRestDoc::Common::DocRender('text');
$oRender->tagSet('backrest', PROJECT_NAME);

# Create the doc
my $oDoc = new BackRestDoc::Common::Doc();
$oDoc->paramSet('title', $self->{oDoc}->paramGet('title'));
@@ -277,16 +344,85 @@ sub docGet
my $iStableReleaseTotal = 0;
my $iUnsupportedReleaseTotal = 0;

foreach my $oRelease ($self->{oDoc}->nodeGet('release-list')->nodeList('release'))
my @oyRelease = $self->{oDoc}->nodeGet('release-list')->nodeList('release');

for (my $iReleaseIdx = 0; $iReleaseIdx < @oyRelease; $iReleaseIdx++)
{
# Get the release version
my $oRelease = $oyRelease[$iReleaseIdx];

# Get the release version and dev flag
my $strVersion = $oRelease->paramGet('version');
my $bReleaseDev = $strVersion =~ /dev$/ ? true : false;

# Get a list of commits that apply to this release
my @rhyReleaseCommit;
my $rhReleaseCommitRemaining;
my @stryReleaseCommitRemaining;
my $bReleaseCheckCommit = false;

if ($strVersion ge '2.01')
{
# Should commits in the release be checked?
$bReleaseCheckCommit = !$bReleaseDev ? true : false;

# Get the begin commit
my $rhReleaseCommitBegin = $self->commitFindSubject(\@hyGitLog, "Begin v${strVersion} development\\.");
my $strReleaseCommitBegin = defined($rhReleaseCommitBegin) ? $rhReleaseCommitBegin->{commit} : undef;

# Get the end commit of the last release
my $strReleaseLastVersion = $oyRelease[$iReleaseIdx + 1]->paramGet('version');
my $rhReleaseLastCommitEnd = $self->commitFindSubject(\@hyGitLog, "v${strReleaseLastVersion}\\: .+");

if (!defined($rhReleaseLastCommitEnd))
{
confess &log(ERROR, "release ${strReleaseLastVersion} must have an end commit");
}

my $strReleaseLastCommitEnd = $rhReleaseLastCommitEnd->{commit};

# Get the end commit
my $rhReleaseCommitEnd = $self->commitFindSubject(\@hyGitLog, "v${strVersion}\\: .+");
my $strReleaseCommitEnd = defined($rhReleaseCommitEnd) ? $rhReleaseCommitEnd->{commit} : undef;

if ($bReleaseCheckCommit && !defined($rhReleaseCommitEnd) && $iReleaseIdx != 0)
{
confess &log(ERROR, "release ${strVersion} must have an end commit");
}

# Make a list of commits for this release
while ($hyGitLog[0]->{commit} ne $strReleaseLastCommitEnd)
{
# Don't add begin/end commits to the list since they are already accounted for
if ((defined($strReleaseCommitEnd) && $hyGitLog[0]->{commit} eq $strReleaseCommitEnd) ||
(defined($strReleaseCommitBegin) && $hyGitLog[0]->{commit} eq $strReleaseCommitBegin))
{
shift(@hyGitLog);
}
# Else add the commit to this releases' list
else
{
push(@stryReleaseCommitRemaining, $hyGitLog[0]->{commit});
push(@rhyReleaseCommit, $hyGitLog[0]);

$rhReleaseCommitRemaining->{$hyGitLog[0]->{commit}}{date} = $hyGitLog[0]->{date};
$rhReleaseCommitRemaining->{$hyGitLog[0]->{commit}}{subject} = $hyGitLog[0]->{subject};

shift(@hyGitLog);
}
}

# At least one commit is required for non-dev releases
if ($bReleaseCheckCommit && @stryReleaseCommitRemaining == 0)
{
confess &log(ERROR, "no commits found for release ${strVersion}");
}
}

# Display versions in TOC?
my $bTOC = true;

# Create a release section
if ($strVersion =~ /dev$/)
if ($bReleaseDev)
{
if ($iDevReleaseTotal > 1)
{
@@ -354,7 +490,7 @@ sub docGet
$oReleaseSection->paramSet(XML_SECTION_PARAM_ANCHOR, XML_SECTION_PARAM_ANCHOR_VALUE_NOINHERIT);

$oReleaseSection->nodeAdd('title')->textSet(
"v${strVersion} " . ($strVersion =~ /dev$/ ? '' : 'Release ') . 'Notes');
"v${strVersion} " . ($bReleaseDev ? '' : 'Release ') . 'Notes');

$oReleaseSection->nodeAdd('subtitle')->textSet($oRelease->paramGet('title'));
$oReleaseSection->nodeAdd('subsubtitle')->textSet($strDateOut);
@@ -420,6 +556,49 @@ sub docGet
my @rhyReleaseItemP = $oReleaseFeature->nodeList('p');
my $oReleaseItemText = $rhyReleaseItemP[0]->textGet();

# Check release item commits
if ($bReleaseCheckCommit && $strItemType ne XML_RELEASE_DEVELOPMENT_LIST)
{
my @oyCommit = $oReleaseFeature->nodeList('commit', false);

# If no commits found then try to use the description as the commit subject
if (@oyCommit == 0)
{
my $strSubject = $oRender->processText($oReleaseItemText);
my $rhCommit = $self->commitFindSubject(\@rhyReleaseCommit, $strSubject, false);

if (!defined($rhCommit))
{
$self->commitError(
"unable to find commit or no subject match for release ${strVersion} item" .
" '${strSubject}'",
\@stryReleaseCommitRemaining, $rhReleaseCommitRemaining);

my $strCommit = $rhCommit->{commit};
@stryReleaseCommitRemaining = grep(!/$strCommit/, @stryReleaseCommitRemaining);
}
}

# Check the rest of the commits to ensure they exist
foreach my $oCommit (@oyCommit)
{
my $strSubject = $oCommit->paramGet('subject');
my $rhCommit = $self->commitFindSubject(\@rhyReleaseCommit, $strSubject, false);

if (defined($rhCommit))
{
my $strCommit = $rhCommit->{commit};
@stryReleaseCommitRemaining = grep(!/$strCommit/, @stryReleaseCommitRemaining);
}
else
{
$self->commitError(
"unable to find release ${strVersion} commit subject '${strSubject}' in list",
\@stryReleaseCommitRemaining, $rhReleaseCommitRemaining);
}
}
}

# Append the rest of the text
if (@rhyReleaseItemP > 1)
{
@@ -451,6 +630,13 @@ sub docGet
}
}
}

# Error if there are commits left over
# if ($bReleaseCheckCommit && @stryReleaseCommitRemaining != 0)
# {
# $self->commitError(
# "unassigned commits for release ${strVersion}", \@stryReleaseCommitRemaining, $rhReleaseCommitRemaining);
# }
}

# Return from function and log return values if any

0 comments on commit ec9622c

Please sign in to comment.
You can’t perform that action at this time.