2016-07-02 17:08:25 +02:00
|
|
|
#!/usr/bin/perl
|
|
|
|
####################################################################################################################################
|
|
|
|
# release.pl - PgBackRest Release Manager
|
|
|
|
####################################################################################################################################
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# Perl includes
|
|
|
|
####################################################################################################################################
|
|
|
|
use strict;
|
|
|
|
use warnings FATAL => qw(all);
|
|
|
|
use Carp qw(confess);
|
2016-09-06 15:44:50 +02:00
|
|
|
use English '-no_match_vars';
|
2016-07-02 17:08:25 +02:00
|
|
|
|
|
|
|
$SIG{__DIE__} = sub { Carp::confess @_ };
|
|
|
|
|
|
|
|
use Cwd qw(abs_path);
|
|
|
|
use File::Basename qw(dirname);
|
|
|
|
use Getopt::Long qw(GetOptions);
|
|
|
|
use Pod::Usage qw(pod2usage);
|
|
|
|
use Storable;
|
|
|
|
|
|
|
|
use lib dirname($0) . '/lib';
|
2017-08-25 22:47:47 +02:00
|
|
|
use lib dirname(dirname($0)) . '/build/lib';
|
|
|
|
use lib dirname(dirname($0)) . '/lib';
|
|
|
|
use lib dirname(dirname($0)) . '/test/lib';
|
2016-11-04 13:56:26 +02:00
|
|
|
|
2016-07-02 17:08:25 +02:00
|
|
|
use BackRestDoc::Common::Doc;
|
|
|
|
use BackRestDoc::Common::DocConfig;
|
|
|
|
use BackRestDoc::Common::DocManifest;
|
|
|
|
use BackRestDoc::Common::DocRender;
|
|
|
|
use BackRestDoc::Html::DocHtmlSite;
|
|
|
|
use BackRestDoc::Latex::DocLatex;
|
|
|
|
use BackRestDoc::Markdown::DocMarkdown;
|
|
|
|
|
2016-09-06 15:44:50 +02:00
|
|
|
use pgBackRest::Common::Exception;
|
2016-07-02 17:08:25 +02:00
|
|
|
use pgBackRest::Common::Log;
|
|
|
|
use pgBackRest::Common::String;
|
|
|
|
use pgBackRest::Version;
|
|
|
|
|
|
|
|
use pgBackRestTest::Common::ExecuteTest;
|
2019-06-17 15:16:44 +02:00
|
|
|
use pgBackRestTest::Common::Storage;
|
|
|
|
use pgBackRestTest::Common::StoragePosix;
|
2019-10-08 18:06:30 +02:00
|
|
|
use pgBackRestTest::Common::VmTest;
|
2016-07-02 17:08:25 +02:00
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# Usage
|
|
|
|
####################################################################################################################################
|
|
|
|
|
|
|
|
=head1 NAME
|
|
|
|
|
|
|
|
release.pl - pgBackRest Release Manager
|
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
|
|
|
|
release.pl [options]
|
|
|
|
|
|
|
|
General Options:
|
|
|
|
--help Display usage and exit
|
|
|
|
--version Display pgBackRest version
|
|
|
|
--quiet Sets log level to ERROR
|
|
|
|
--log-level Log level for execution (e.g. ERROR, WARN, INFO, DEBUG)
|
|
|
|
|
|
|
|
Release Options:
|
|
|
|
--build Build the cache before release (should be included in the release commit)
|
|
|
|
--deploy Deploy documentation to website (can be done as docs are updated)
|
2019-05-23 00:54:49 +02:00
|
|
|
--no-gen Don't auto-generate
|
2019-10-08 18:06:30 +02:00
|
|
|
--vm vm to build documentation for
|
2016-07-02 17:08:25 +02:00
|
|
|
=cut
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# Load command line parameters and config (see usage above for details)
|
|
|
|
####################################################################################################################################
|
|
|
|
my $bHelp = false;
|
|
|
|
my $bVersion = false;
|
|
|
|
my $bQuiet = false;
|
|
|
|
my $strLogLevel = 'info';
|
|
|
|
my $bBuild = false;
|
|
|
|
my $bDeploy = false;
|
2019-05-23 00:54:49 +02:00
|
|
|
my $bNoGen = false;
|
2019-10-08 18:06:30 +02:00
|
|
|
my $strVm = undef;
|
2016-07-02 17:08:25 +02:00
|
|
|
|
|
|
|
GetOptions ('help' => \$bHelp,
|
|
|
|
'version' => \$bVersion,
|
|
|
|
'quiet' => \$bQuiet,
|
|
|
|
'log-level=s' => \$strLogLevel,
|
|
|
|
'build' => \$bBuild,
|
2019-05-15 19:04:56 +02:00
|
|
|
'deploy' => \$bDeploy,
|
2019-10-08 18:06:30 +02:00
|
|
|
'no-gen' => \$bNoGen,
|
|
|
|
'vm=s' => \$strVm)
|
2016-07-02 17:08:25 +02:00
|
|
|
or pod2usage(2);
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# Run in eval block to catch errors
|
|
|
|
####################################################################################################################################
|
|
|
|
eval
|
|
|
|
{
|
|
|
|
# Display version and exit if requested
|
|
|
|
if ($bHelp || $bVersion)
|
|
|
|
{
|
2018-11-25 02:05:03 +02:00
|
|
|
print PROJECT_NAME . ' ' . PROJECT_VERSION . " Release Manager\n";
|
2016-07-02 17:08:25 +02:00
|
|
|
|
|
|
|
if ($bHelp)
|
|
|
|
{
|
|
|
|
print "\n";
|
|
|
|
pod2usage();
|
|
|
|
}
|
|
|
|
|
|
|
|
exit 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
# If neither build nor deploy is requested then error
|
|
|
|
if (!$bBuild && !$bDeploy)
|
|
|
|
{
|
|
|
|
confess &log(ERROR, 'neither --build nor --deploy requested, nothing to do');
|
|
|
|
}
|
|
|
|
|
|
|
|
# Set console log level
|
|
|
|
if ($bQuiet)
|
|
|
|
{
|
|
|
|
$strLogLevel = 'error';
|
|
|
|
}
|
|
|
|
|
2016-10-05 15:09:30 +02:00
|
|
|
logLevelSet(undef, uc($strLogLevel), OFF);
|
2016-07-02 17:08:25 +02:00
|
|
|
|
|
|
|
# Set the paths
|
|
|
|
my $strDocPath = dirname(abs_path($0));
|
|
|
|
my $strDocHtml = "${strDocPath}/output/html";
|
|
|
|
my $strDocExe = "${strDocPath}/doc.pl";
|
2019-05-15 19:04:56 +02:00
|
|
|
my $strTestExe = dirname($strDocPath) . "/test/test.pl";
|
2016-07-02 17:08:25 +02:00
|
|
|
|
2019-06-17 15:16:44 +02:00
|
|
|
my $oStorageDoc = new pgBackRestTest::Common::Storage(
|
|
|
|
$strDocPath, new pgBackRestTest::Common::StoragePosix({bFileSync => false, bPathSync => false}));
|
2017-06-09 23:51:41 +02:00
|
|
|
|
2016-07-02 17:08:25 +02:00
|
|
|
# Determine if this is a dev release
|
2018-11-25 02:05:03 +02:00
|
|
|
my $bDev = PROJECT_VERSION =~ /dev$/;
|
|
|
|
my $strVersion = $bDev ? 'dev' : PROJECT_VERSION;
|
2016-07-02 17:08:25 +02:00
|
|
|
|
|
|
|
if ($bBuild)
|
|
|
|
{
|
2019-05-23 00:54:49 +02:00
|
|
|
if (!$bNoGen)
|
2019-05-15 19:04:56 +02:00
|
|
|
{
|
2019-05-23 00:54:49 +02:00
|
|
|
# Update git history
|
|
|
|
my $strGitCommand =
|
|
|
|
'git -C ' . $strDocPath .
|
|
|
|
' log --pretty=format:\'{^^^^commit^^^^:^^^^%H^^^^,^^^^date^^^^:^^^^%ci^^^^,^^^^subject^^^^:^^^^%s^^^^,^^^^body^^^^:^^^^%b^^^^},\'';
|
|
|
|
my $strGitLog = qx($strGitCommand);
|
|
|
|
$strGitLog =~ s/\^\^\^\^\}\,\n/\#\#\#\#/mg;
|
|
|
|
$strGitLog =~ s/\\/\\\\/g;
|
|
|
|
$strGitLog =~ s/\n/\\n/mg;
|
|
|
|
$strGitLog =~ s/\r/\\r/mg;
|
|
|
|
$strGitLog =~ s/\t/\\t/mg;
|
|
|
|
$strGitLog =~ s/\"/\\\"/g;
|
|
|
|
$strGitLog =~ s/\^\^\^\^/\"/g;
|
|
|
|
$strGitLog =~ s/\#\#\#\#/\"\}\,\n/mg;
|
|
|
|
$strGitLog = '[' . substr($strGitLog, 0, length($strGitLog) - 1) . ']';
|
|
|
|
my @hyGitLog = @{(JSON::PP->new()->allow_nonref())->decode($strGitLog)};
|
|
|
|
|
|
|
|
# Load prior history
|
|
|
|
my @hyGitLogPrior = @{(JSON::PP->new()->allow_nonref())->decode(
|
|
|
|
${$oStorageDoc->get("${strDocPath}/resource/git-history.cache")})};
|
|
|
|
|
|
|
|
# Add new commits
|
|
|
|
for (my $iGitLogIdx = @hyGitLog - 1; $iGitLogIdx >= 0; $iGitLogIdx--)
|
|
|
|
{
|
|
|
|
my $rhGitLog = $hyGitLog[$iGitLogIdx];
|
|
|
|
my $bFound = false;
|
|
|
|
|
|
|
|
foreach my $rhGitLogPrior (@hyGitLogPrior)
|
|
|
|
{
|
|
|
|
if ($rhGitLog->{commit} eq $rhGitLogPrior->{commit})
|
|
|
|
{
|
|
|
|
$bFound = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
next if $bFound;
|
|
|
|
|
|
|
|
$rhGitLog->{body} = trim($rhGitLog->{body});
|
|
|
|
|
|
|
|
if ($rhGitLog->{body} eq '')
|
|
|
|
{
|
|
|
|
delete($rhGitLog->{body});
|
|
|
|
}
|
|
|
|
|
|
|
|
unshift(@hyGitLogPrior, $rhGitLog);
|
|
|
|
}
|
|
|
|
|
|
|
|
# Write git log
|
|
|
|
$strGitLog = undef;
|
|
|
|
|
|
|
|
foreach my $rhGitLog (@hyGitLogPrior)
|
|
|
|
{
|
|
|
|
$strGitLog .=
|
|
|
|
(defined($strGitLog) ? ",\n" : '') .
|
|
|
|
" {\n" .
|
|
|
|
' "commit": ' . trim((JSON::PP->new()->allow_nonref()->pretty())->encode($rhGitLog->{commit})) . ",\n" .
|
|
|
|
' "date": ' . trim((JSON::PP->new()->allow_nonref()->pretty())->encode($rhGitLog->{date})) . ",\n" .
|
|
|
|
' "subject": ' . trim((JSON::PP->new()->allow_nonref()->pretty())->encode($rhGitLog->{subject}));
|
|
|
|
|
|
|
|
# Skip the body if it is empty or a release (since we already have the release note content)
|
|
|
|
if ($rhGitLog->{subject} !~ /^v[0-9]{1,2}\.[0-9]{1,2}\: /g && defined($rhGitLog->{body}))
|
|
|
|
{
|
|
|
|
$strGitLog .=
|
|
|
|
",\n" .
|
|
|
|
' "body": ' . trim((JSON::PP->new()->allow_nonref()->pretty())->encode($rhGitLog->{body}));
|
|
|
|
}
|
|
|
|
|
|
|
|
$strGitLog .=
|
|
|
|
"\n" .
|
|
|
|
" }";
|
|
|
|
}
|
|
|
|
|
|
|
|
$oStorageDoc->put("${strDocPath}/resource/git-history.cache", "[\n${strGitLog}\n]\n");
|
|
|
|
|
2019-08-26 18:05:36 +02:00
|
|
|
# Generate coverage summary
|
2019-05-15 19:04:56 +02:00
|
|
|
&log(INFO, "Generate Coverage Summary");
|
|
|
|
executeTest(
|
2019-11-12 22:51:28 +02:00
|
|
|
"${strTestExe} --vm=u19 --no-package --no-valgrind --no-optimize --vm-max=3 --coverage-summary",
|
2019-05-15 19:04:56 +02:00
|
|
|
{bShowOutputAsync => true});
|
|
|
|
}
|
|
|
|
|
2019-05-23 00:54:49 +02:00
|
|
|
# Remove permanent cache file
|
|
|
|
$oStorageDoc->remove("${strDocPath}/resource/exe.cache", {bIgnoreMissing => true});
|
|
|
|
|
|
|
|
# Remove all docker containers to get consistent IP address assignments
|
|
|
|
executeTest('docker rm -f $(docker ps -a -q)', {bSuppressError => true});
|
|
|
|
|
2018-12-05 14:12:28 +02:00
|
|
|
# Generate deployment docs for RHEL/Centos 7
|
2019-10-08 18:06:30 +02:00
|
|
|
if (!defined($strVm) || $strVm eq VM_CO7)
|
|
|
|
{
|
|
|
|
&log(INFO, "Generate RHEL/CentOS 7 documentation");
|
|
|
|
|
|
|
|
executeTest("${strDocExe} --deploy --key-var=os-type=centos7 --out=pdf", {bShowOutputAsync => true});
|
2018-12-12 18:15:09 +02:00
|
|
|
|
2019-10-08 18:06:30 +02:00
|
|
|
if (!defined($strVm))
|
|
|
|
{
|
|
|
|
executeTest("${strDocExe} --deploy --cache-only --key-var=os-type=centos7 --out=pdf");
|
|
|
|
}
|
|
|
|
}
|
2018-12-05 14:12:28 +02:00
|
|
|
|
2016-07-02 17:08:25 +02:00
|
|
|
# Generate deployment docs for RHEL/Centos 6
|
2019-10-08 18:06:30 +02:00
|
|
|
if (!defined($strVm) || $strVm eq VM_CO6)
|
|
|
|
{
|
|
|
|
&log(INFO, "Generate RHEL/CentOS 6 documentation");
|
2016-07-02 17:08:25 +02:00
|
|
|
|
2019-10-08 18:06:30 +02:00
|
|
|
executeTest("${strDocExe} --deploy --key-var=os-type=centos6 --out=html", {bShowOutputAsync => true});
|
|
|
|
|
|
|
|
if (!defined($strVm))
|
|
|
|
{
|
|
|
|
executeTest("${strDocExe} --deploy --cache-only --key-var=os-type=centos6 --out=html");
|
|
|
|
}
|
|
|
|
}
|
2016-07-02 17:08:25 +02:00
|
|
|
|
|
|
|
# Generate deployment docs for Debian
|
2019-10-08 18:06:30 +02:00
|
|
|
if (!defined($strVm) || $strVm eq VM_U18)
|
|
|
|
{
|
|
|
|
&log(INFO, "Generate Debian/Ubuntu documentation");
|
2016-07-02 17:08:25 +02:00
|
|
|
|
2019-10-08 18:06:30 +02:00
|
|
|
executeTest("${strDocExe} --deploy --out=man --out=html --out=markdown", {bShowOutputAsync => true});
|
|
|
|
}
|
2019-05-16 14:32:02 +02:00
|
|
|
|
|
|
|
# Generate a full copy of the docs for review
|
2019-10-08 18:06:30 +02:00
|
|
|
if (!defined($strVm))
|
|
|
|
{
|
|
|
|
&log(INFO, "Generate full documentation for review");
|
2019-05-16 14:32:02 +02:00
|
|
|
|
2019-10-08 18:06:30 +02:00
|
|
|
executeTest(
|
|
|
|
"${strDocExe} --deploy --cache-only --key-var=os-type=centos7 --out=html --var=project-url-root=index.html");
|
|
|
|
$oStorageDoc->move("$strDocHtml/user-guide.html", "$strDocHtml/user-guide-centos7.html");
|
|
|
|
executeTest(
|
|
|
|
"${strDocExe} --deploy --out-preserve --cache-only --key-var=os-type=centos6 --out=html" .
|
|
|
|
" --var=project-url-root=index.html");
|
|
|
|
$oStorageDoc->move("$strDocHtml/user-guide.html", "$strDocHtml/user-guide-centos6.html");
|
2019-05-16 14:32:02 +02:00
|
|
|
|
2019-10-08 18:06:30 +02:00
|
|
|
executeTest(
|
|
|
|
"${strDocExe} --deploy --out-preserve --cache-only --out=man --out=html --var=project-url-root=index.html");
|
|
|
|
}
|
2016-07-02 17:08:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($bDeploy)
|
|
|
|
{
|
2017-11-22 00:59:30 +02:00
|
|
|
my $strDeployPath = "${strDocPath}/site";
|
|
|
|
|
2017-12-20 02:14:16 +02:00
|
|
|
# Generate docs for the website history
|
2016-07-02 17:08:25 +02:00
|
|
|
&log(INFO, 'Generate website ' . ($bDev ? 'dev' : 'history') . ' documentation');
|
|
|
|
|
2019-05-16 14:32:02 +02:00
|
|
|
my $strDocExeVersion =
|
|
|
|
${strDocExe} . ($bDev ? ' --dev' : ' --deploy --cache-only') . ' --var=project-url-root=index.html --out=html';
|
|
|
|
|
2019-05-24 13:45:03 +02:00
|
|
|
executeTest("${strDocExeVersion} --key-var=os-type=centos7");
|
2019-05-16 14:32:02 +02:00
|
|
|
$oStorageDoc->move("$strDocHtml/user-guide.html", "$strDocHtml/user-guide-centos7.html");
|
2019-05-24 13:45:03 +02:00
|
|
|
executeTest("${strDocExeVersion} --out-preserve --key-var=os-type=centos6");
|
2019-05-16 14:32:02 +02:00
|
|
|
$oStorageDoc->move("$strDocHtml/user-guide.html", "$strDocHtml/user-guide-centos6.html");
|
|
|
|
|
|
|
|
$oStorageDoc->remove("$strDocHtml/release.html");
|
|
|
|
executeTest("${strDocExeVersion} --out-preserve --exclude=release");
|
2016-07-02 17:08:25 +02:00
|
|
|
|
2017-12-20 02:14:16 +02:00
|
|
|
# Deploy to repository
|
2017-11-22 00:59:30 +02:00
|
|
|
&log(INFO, '...Deploy to repository');
|
2017-12-20 02:14:16 +02:00
|
|
|
executeTest("rm -rf ${strDeployPath}/prior/${strVersion}");
|
|
|
|
executeTest("mkdir ${strDeployPath}/prior/${strVersion}");
|
|
|
|
executeTest("cp ${strDocHtml}/* ${strDeployPath}/prior/${strVersion}");
|
2016-07-02 17:08:25 +02:00
|
|
|
|
2017-12-20 02:14:16 +02:00
|
|
|
# Generate docs for the main website
|
2016-07-02 17:08:25 +02:00
|
|
|
if (!$bDev)
|
|
|
|
{
|
|
|
|
&log(INFO, "Generate website documentation");
|
|
|
|
|
2019-05-24 13:45:03 +02:00
|
|
|
executeTest("${strDocExe} --deploy --cache-only --key-var=os-type=centos7 --out=html");
|
2019-05-16 14:32:02 +02:00
|
|
|
$oStorageDoc->move("$strDocHtml/user-guide.html", "$strDocHtml/user-guide-centos7.html");
|
2019-05-24 13:45:03 +02:00
|
|
|
executeTest("${strDocExe} --deploy --out-preserve --cache-only --key-var=os-type=centos6 --out=html");
|
2019-05-16 14:32:02 +02:00
|
|
|
$oStorageDoc->move("$strDocHtml/user-guide.html", "$strDocHtml/user-guide-centos6.html");
|
|
|
|
executeTest("${strDocExe} --deploy --out-preserve --cache-only --out=html");
|
2016-07-02 17:08:25 +02:00
|
|
|
|
2017-12-20 02:14:16 +02:00
|
|
|
# Deploy to repository
|
2017-11-22 00:59:30 +02:00
|
|
|
&log(INFO, '...Deploy to repository');
|
|
|
|
executeTest("rm -rf ${strDeployPath}/dev");
|
|
|
|
executeTest("find ${strDeployPath} -maxdepth 1 -type f -exec rm {} +");
|
|
|
|
executeTest("cp ${strDocHtml}/* ${strDeployPath}");
|
|
|
|
executeTest("cp ${strDocPath}/../README.md ${strDeployPath}");
|
|
|
|
executeTest("cp ${strDocPath}/../LICENSE ${strDeployPath}");
|
2016-07-02 17:08:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# Update permissions
|
2017-11-22 02:52:56 +02:00
|
|
|
executeTest("find ${strDeployPath} -type d -exec chmod 750 {} +");
|
|
|
|
executeTest("find ${strDeployPath} -type f -exec chmod 640 {} +");
|
2016-07-02 17:08:25 +02:00
|
|
|
}
|
2016-09-06 15:44:50 +02:00
|
|
|
|
|
|
|
# Exit with success
|
|
|
|
exit 0;
|
|
|
|
}
|
2016-07-02 17:08:25 +02:00
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# Check for errors
|
|
|
|
####################################################################################################################################
|
2016-09-06 15:44:50 +02:00
|
|
|
or do
|
2016-07-02 17:08:25 +02:00
|
|
|
{
|
2016-09-06 15:44:50 +02:00
|
|
|
# If a backrest exception then return the code
|
2017-10-16 16:47:31 +02:00
|
|
|
exit $EVAL_ERROR->code() if (isException(\$EVAL_ERROR));
|
2016-07-02 17:08:25 +02:00
|
|
|
|
2016-09-06 15:44:50 +02:00
|
|
|
# Else output the unhandled error
|
|
|
|
print $EVAL_ERROR;
|
|
|
|
exit ERROR_UNHANDLED;
|
|
|
|
};
|
2016-07-02 17:08:25 +02:00
|
|
|
|
2016-09-06 15:44:50 +02:00
|
|
|
# It shouldn't be possible to get here
|
|
|
|
&log(ASSERT, 'execution reached invalid location in ' . __FILE__ . ', line ' . __LINE__);
|
|
|
|
exit ERROR_ASSERT;
|