1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-14 10:13:05 +02:00
pgbackrest/doc/lib/BackRestDoc/Custom/DocCustomRelease.pm
David Steele 936b8a289c Allow separate paragraphs in release items.
The first paragraph should match the first line of the commit message as closely as possible.  The following paragraphs add more information.

Release items have been updated back to 2.01.
2019-05-21 10:37:30 -04:00

465 lines
18 KiB
Perl

####################################################################################################################################
# DOC RELEASE MODULE
####################################################################################################################################
package BackRestDoc::Custom::DocCustomRelease;
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use Exporter qw(import);
our @EXPORT = qw();
use pgBackRest::Common::Log;
use pgBackRest::Common::String;
use pgBackRestBuild::Config::Data;
use BackRestDoc::Common::DocRender;
####################################################################################################################################
# XML node constants
####################################################################################################################################
use constant XML_PARAM_ID => 'id';
use constant XML_CONTRIBUTOR_LIST => 'contributor-list';
use constant XML_CONTRIBUTOR => 'contributor';
use constant XML_CONTRIBUTOR_NAME_DISPLAY => 'contributor-name-display';
use constant XML_RELEASE_CORE_LIST => 'release-core-list';
use constant XML_RELEASE_DOC_LIST => 'release-doc-list';
use constant XML_RELEASE_TEST_LIST => 'release-test-list';
use constant XML_RELEASE_BUG_LIST => 'release-bug-list';
use constant XML_RELEASE_DEVELOPMENT_LIST => 'release-development-list';
use constant XML_RELEASE_FEATURE_LIST => 'release-feature-list';
use constant XML_RELEASE_IMPROVEMENT_LIST => 'release-improvement-list';
use constant XML_RELEASE_ITEM_CONTRIBUTOR_LIST => 'release-item-contributor-list';
use constant XML_RELEASE_ITEM_CONTRIBUTOR => 'release-item-contributor';
use constant XML_RELEASE_ITEM_IDEATOR => 'release-item-ideator';
use constant XML_RELEASE_ITEM_REVIEWER => 'release-item-reviewer';
####################################################################################################################################
# Contributor text constants
####################################################################################################################################
use constant TEXT_CONTRIBUTED => 'Contributed';
use constant TEXT_FIXED => 'Fixed';
use constant TEXT_FOUND => 'Reported';
use constant TEXT_REVIEWED => 'Reviewed';
use constant TEXT_SUGGESTED => 'Suggested';
####################################################################################################################################
# CONSTRUCTOR
####################################################################################################################################
sub new
{
my $class = shift; # Class name
# Create the class hash
my $self = {};
bless $self, $class;
# Assign function parameters, defaults, and log debug info
(
my $strOperation,
$self->{oDoc},
$self->{bDev},
) =
logDebugParam
(
__PACKAGE__ . '->new', \@_,
{name => 'oDoc'},
{name => 'bDev', required => false, default => false},
);
# Get contributor list
foreach my $oContributor ($self->{oDoc}->nodeGet(XML_CONTRIBUTOR_LIST)->nodeList(XML_CONTRIBUTOR))
{
my $strContributorId = $oContributor->paramGet(XML_PARAM_ID);
if (!defined($self->{hContributor}))
{
$self->{hContributor} = {};
$self->{strContributorDefault} = $strContributorId;
}
${$self->{hContributor}}{$strContributorId}{name} = $oContributor->fieldGet(XML_CONTRIBUTOR_NAME_DISPLAY);
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'self', value => $self}
);
}
####################################################################################################################################
# currentStableVersion
#
# Return the current stable version.
####################################################################################################################################
sub currentStableVersion
{
my $self = shift;
my $oDoc = $self->{oDoc};
foreach my $oRelease ($oDoc->nodeGet('release-list')->nodeList('release'))
{
my $strVersion = $oRelease->paramGet('version');
if ($strVersion !~ /dev$/)
{
return $strVersion;
}
}
confess &log(ERROR, "unable to find non-development version");
}
####################################################################################################################################
# releaseLast
#
# Get the last release.
####################################################################################################################################
sub releaseLast
{
my $self = shift;
my $oDoc = $self->{oDoc};
foreach my $oRelease ($oDoc->nodeGet('release-list')->nodeList('release'))
{
return $oRelease;
}
}
####################################################################################################################################
# contributorTextGet
#
# Get a list of contributors for an item in text format.
####################################################################################################################################
sub contributorTextGet
{
my $self = shift;
my $oReleaseItem = shift;
my $strItemType = shift;
my $strContributorText;
my $hItemContributorType = {};
# Create a the list of contributors
foreach my $strContributorType (XML_RELEASE_ITEM_IDEATOR, XML_RELEASE_ITEM_CONTRIBUTOR, XML_RELEASE_ITEM_REVIEWER)
{
my $stryItemContributor = [];
if ($oReleaseItem->nodeTest(XML_RELEASE_ITEM_CONTRIBUTOR_LIST))
{
foreach my $oContributor ($oReleaseItem->nodeGet(XML_RELEASE_ITEM_CONTRIBUTOR_LIST)->
nodeList($strContributorType, false))
{
push @{$stryItemContributor}, $oContributor->paramGet(XML_PARAM_ID);
}
}
if (@$stryItemContributor == 0 && $strContributorType eq XML_RELEASE_ITEM_CONTRIBUTOR)
{
push @{$stryItemContributor}, $self->{strContributorDefault}
}
$$hItemContributorType{$strContributorType} = $stryItemContributor;
}
# Error if a reviewer is also a contributor
foreach my $strReviewer (@{$$hItemContributorType{&XML_RELEASE_ITEM_REVIEWER}})
{
foreach my $strContributor (@{$$hItemContributorType{&XML_RELEASE_ITEM_CONTRIBUTOR}})
{
if ($strReviewer eq $strContributor)
{
confess &log(ERROR, "${strReviewer} cannot be both a contributor and a reviewer");
}
}
}
# Error if the ideator list is the same as the contributor list
if (join(',', @{$$hItemContributorType{&XML_RELEASE_ITEM_IDEATOR}}) eq
join(',', @{$$hItemContributorType{&XML_RELEASE_ITEM_CONTRIBUTOR}}))
{
confess &log(ERROR, 'cannot have same contributor and ideator list: ' .
join(', ', @{$$hItemContributorType{&XML_RELEASE_ITEM_CONTRIBUTOR}}));
}
# Remove the default user if they are the only one in a group (to prevent the entire page from being splattered with one name)
foreach my $strContributorType (XML_RELEASE_ITEM_IDEATOR, XML_RELEASE_ITEM_CONTRIBUTOR, XML_RELEASE_ITEM_REVIEWER)
{
if (@{$$hItemContributorType{$strContributorType}} == 1 &&
@{$$hItemContributorType{$strContributorType}}[0] eq $self->{strContributorDefault})
{
$$hItemContributorType{$strContributorType} = [];
}
}
# Render the string
foreach my $strContributorType (XML_RELEASE_ITEM_CONTRIBUTOR, XML_RELEASE_ITEM_REVIEWER, XML_RELEASE_ITEM_IDEATOR)
{
my $stryItemContributor = $$hItemContributorType{$strContributorType};
my $strContributorTypeText;
foreach my $strContributor (@{$stryItemContributor})
{
my $hContributor = ${$self->{hContributor}}{$strContributor};
if (!defined($hContributor))
{
confess &log(ERROR, "contributor ${strContributor} does not exist");
}
$strContributorTypeText .= (defined($strContributorTypeText) ? ', ' : '') . $$hContributor{name};
}
if (defined($strContributorTypeText))
{
$strContributorTypeText = ' by ' . $strContributorTypeText . '.';
if ($strContributorType eq XML_RELEASE_ITEM_CONTRIBUTOR)
{
$strContributorTypeText = ($strItemType eq 'bug' ? TEXT_FIXED : TEXT_CONTRIBUTED) . $strContributorTypeText;
}
elsif ($strContributorType eq XML_RELEASE_ITEM_IDEATOR)
{
$strContributorTypeText = ($strItemType eq 'bug' ? TEXT_FOUND : TEXT_SUGGESTED) . $strContributorTypeText;
}
elsif ($strContributorType eq XML_RELEASE_ITEM_REVIEWER)
{
$strContributorTypeText = TEXT_REVIEWED . $strContributorTypeText;
}
$strContributorText .= (defined($strContributorText) ? ' ' : '') . $strContributorTypeText;
}
}
return $strContributorText;
}
####################################################################################################################################
# docGet
#
# Get the xml for release.
####################################################################################################################################
sub docGet
{
my $self = shift;
# Assign function parameters, defaults, and log debug info
my $strOperation = logDebugParam(__PACKAGE__ . '->docGet');
# Create the doc
my $oDoc = new BackRestDoc::Common::Doc();
$oDoc->paramSet('title', $self->{oDoc}->paramGet('title'));
$oDoc->paramSet('toc-number', $self->{oDoc}->paramGet('toc-number'));
# Set the description for use as a meta tag
$oDoc->fieldSet('description', $self->{oDoc}->fieldGet('description'));
# Add the introduction
my $oIntroSectionDoc = $oDoc->nodeAdd('section', undef, {id => 'introduction'});
$oIntroSectionDoc->nodeAdd('title')->textSet('Introduction');
$oIntroSectionDoc->textSet($self->{oDoc}->nodeGet('intro')->textGet());
# Add each release section
my $oSection;
my $iDevReleaseTotal = 0;
my $iCurrentReleaseTotal = 0;
my $iStableReleaseTotal = 0;
my $iUnsupportedReleaseTotal = 0;
foreach my $oRelease ($self->{oDoc}->nodeGet('release-list')->nodeList('release'))
{
# Get the release version
my $strVersion = $oRelease->paramGet('version');
# Display versions in TOC?
my $bTOC = true;
# Create a release section
if ($strVersion =~ /dev$/)
{
if ($iDevReleaseTotal > 1)
{
confess &log(ERROR, 'only one development release is allowed');
}
$oSection = $oDoc->nodeAdd('section', undef, {id => 'development', if => "'{[dev]}' eq 'y'"});
$oSection->nodeAdd('title')->textSet("Development Notes");
$iDevReleaseTotal++;
}
elsif ($iCurrentReleaseTotal == 0)
{
$oSection = $oDoc->nodeAdd('section', undef, {id => 'current'});
$oSection->nodeAdd('title')->textSet("Current Stable Release");
$iCurrentReleaseTotal++;
}
elsif ($strVersion ge '1.00')
{
if ($iStableReleaseTotal == 0)
{
$oSection = $oDoc->nodeAdd('section', undef, {id => 'supported'});
$oSection->nodeAdd('title')->textSet("Stable Releases");
}
$iStableReleaseTotal++;
$bTOC = false;
}
else
{
if ($iUnsupportedReleaseTotal == 0)
{
$oSection = $oDoc->nodeAdd('section', undef, {id => 'unsupported'});
$oSection->nodeAdd('title')->textSet("Pre-Stable Releases");
}
$iUnsupportedReleaseTotal++;
$bTOC = false;
}
# Format the date
my $strDate = $oRelease->paramGet('date');
my $strDateOut = "";
my @stryMonth = ('January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December');
if ($strDate =~ /^X/)
{
$strDateOut .= 'No Release Date Set';
}
else
{
if ($strDate !~ /^(XXXX-XX-XX)|([0-9]{4}-[0-9]{2}-[0-9]{2})$/)
{
confess &log(ASSERT, "invalid date ${strDate} for release {$strVersion}");
}
$strDateOut .= 'Released ' . $stryMonth[(substr($strDate, 5, 2) - 1)] . ' ' .
(substr($strDate, 8, 2) + 0) . ', ' . substr($strDate, 0, 4);
}
# Add section and titles
my $oReleaseSection = $oSection->nodeAdd('section', undef, {id => $strVersion, toc => !$bTOC ? 'n' : undef});
$oReleaseSection->paramSet(XML_SECTION_PARAM_ANCHOR, XML_SECTION_PARAM_ANCHOR_VALUE_NOINHERIT);
$oReleaseSection->nodeAdd('title')->textSet(
"v${strVersion} " . ($strVersion =~ /dev$/ ? '' : 'Release ') . 'Notes');
$oReleaseSection->nodeAdd('subtitle')->textSet($oRelease->paramGet('title'));
$oReleaseSection->nodeAdd('subsubtitle')->textSet($strDateOut);
# Add release sections
my $bAdditionalNotes = false;
my $bReleaseNote = false;
my $hSectionType =
{
&XML_RELEASE_CORE_LIST => {title => 'Core', type => 'core'},
&XML_RELEASE_DOC_LIST => {title => 'Documentation', type => 'doc'},
&XML_RELEASE_TEST_LIST => {title => 'Test Suite', type => 'test'},
};
foreach my $strSectionType (XML_RELEASE_CORE_LIST, XML_RELEASE_DOC_LIST, XML_RELEASE_TEST_LIST)
{
if ($oRelease->nodeTest($strSectionType))
{
# Add release item types
my $hItemType =
{
&XML_RELEASE_BUG_LIST => {title => 'Bug Fixes', type => 'bug'},
&XML_RELEASE_FEATURE_LIST => {title => 'Features', type => 'feature'},
&XML_RELEASE_IMPROVEMENT_LIST => {title => 'Improvements', type => 'improvement'},
&XML_RELEASE_DEVELOPMENT_LIST => {title => 'Development', type => 'development'},
};
foreach my $strItemType (
XML_RELEASE_BUG_LIST, XML_RELEASE_FEATURE_LIST, XML_RELEASE_IMPROVEMENT_LIST, XML_RELEASE_DEVELOPMENT_LIST)
{
next if (!$self->{bDev} && $strItemType eq XML_RELEASE_DEVELOPMENT_LIST);
if ($oRelease->nodeGet($strSectionType)->nodeTest($strItemType))
{
if ($strSectionType ne XML_RELEASE_CORE_LIST && !$bAdditionalNotes)
{
$oReleaseSection->nodeAdd('subtitle')->textSet('Additional Notes');
$bAdditionalNotes = true;
}
# Add release note if present
if (!$bReleaseNote && $oRelease->nodeGet($strSectionType)->nodeTest('p'))
{
$oReleaseSection->nodeAdd('p')->textSet($oRelease->nodeGet($strSectionType)->nodeGet('p')->textGet());
$bReleaseNote = true;
}
my $strTypeText =
($strSectionType eq XML_RELEASE_CORE_LIST ? '' : $$hSectionType{$strSectionType}{title}) . ' ' .
$$hItemType{$strItemType}{title} . ':';
$oReleaseSection->
nodeAdd('p')->textSet(
{name => 'text', children=> [{name => 'b', value => $strTypeText}]});
my $oList = $oReleaseSection->nodeAdd('list');
# Add release items
foreach my $oReleaseFeature ($oRelease->nodeGet($strSectionType)->
nodeGet($strItemType)->nodeList('release-item'))
{
my @rhyReleaseItemP = $oReleaseFeature->nodeList('p');
my $oReleaseItemText = $rhyReleaseItemP[0]->textGet();
# Append the rest of the text
if (@rhyReleaseItemP > 1)
{
shift(@rhyReleaseItemP);
push(@{$oReleaseItemText->{oDoc}{children}}, ' ');
foreach my $rhReleaseItemP (@rhyReleaseItemP)
{
push(@{$oReleaseItemText->{oDoc}{children}}, @{$rhReleaseItemP->textGet()->{oDoc}{children}});
}
}
# Append contributor info
my $strContributorText = $self->contributorTextGet($oReleaseFeature, $$hItemType{$strItemType}{type});
if (defined($strContributorText))
{
push(@{$oReleaseItemText->{oDoc}{children}}, ' (');
push(@{$oReleaseItemText->{oDoc}{children}},
{name => 'i', value => $strContributorText});
push(@{$oReleaseItemText->{oDoc}{children}}, ')');
}
# Add the list item
$oList->nodeAdd('list-item')->textSet($oReleaseItemText);
}
}
}
}
}
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'oDoc', value => $oDoc}
);
}
1;