blob: 27c6bcbca04ca39fcf6ae364143c48215645f024 [file] [log] [blame] [edit]
#!/usr/bin/env perl
use strict;
use Getopt::Long;
use DBI;
# We use an in-memory SQLite database as SQL is good for doing queries
# of differences between data sets, and doing that in perl is annoying.
my $db = "dbi:SQLite:dbname=release-notes.sqlite";
#my $dbh = DBI->connect("dbi:SQLite:dbname=:memory:","","");
my $dbh = DBI->connect($db,undef,undef, {AutoCommit => 1, RaiseError=>1});
my $repos =
{
'op-build' => { REPO => "https://github.com/open-power/op-build" },
'hcode' => { REPO => "https://github.com/open-power/hcode" ,
DIR => "openpower/package/hcode" },
'hostboot' => { REPO => "https://github.com/open-power/hostboot" ,
DIR => "openpower/package/hostboot" },
'sbe' => { REPO => "https://github.com/open-power/sbe" ,
DIR => "openpower/package/sbe"},
'skiboot' => { REPO => "https://github.com/open-power/skiboot" ,
DIR => "openpower/package/skiboot"},
'occ' => { REPO => "https://github.com/open-power/occ" ,
DIR => "openpower/package/occ"},
'pnor' => { REPO => "https://github.com/open-power/pnor" ,
DIR => "openpower/package/openpower-pnor"},
'petitboot' => { REPO => "https://github.com/open-power/petitboot" ,
DIR => "openpower/package/petitboot"},
};
my $begin_release;
my $end_release;
my $begin_worktree;
my $end_worktree;
my $platform;
GetOptions("begin-release=s" => \$begin_release,
"end-release=s" => \$end_release,
"begin-worktree=s" => \$begin_worktree,
"platform=s" => \$platform,
"end-worktree=s" => \$end_worktree)
or die("Error in command line arguments");
die "Required argument missing" unless ($begin_release and $end_release and $begin_worktree and $end_worktree);
open(OUTPUT, "> RELEASE.md") || die "Failed to open RELEASE.md";
print OUTPUT "# Release Notes for OpenPower Firmware $end_release \n";
if (-e $begin_worktree) {
system("cd $begin_worktree && git checkout $begin_release && git submodule update --reference ../buildroot && git submodule update") and die "Could not update $begin_worktree";
} else {
system("git worktree add $begin_worktree $begin_release && cd $begin_worktree&& git submodule update --reference ../buildroot && git submodule update && rm -rf dl && ln -s ../dl dl") and die "Couldn't init $begin_worktree";
}
if (-e $end_worktree) {
system("cd $end_worktree && git checkout $end_release && git submodule update --reference ../buildroot && git submodule update") and die "Could not update $end_worktree";
} else {
system("git worktree add $end_worktree $end_release && cd $end_worktree && git submodule update --reference ../buildroot && git submodule update && rm -rf dl && ln -s ../dl dl") and die "Couldn't init $end_worktree";
}
opendir (my $dh, "$begin_worktree/openpower/configs")
or die "can't scan $begin_worktree defconfigs";
my @begin_platforms = grep { /.*_defconfig/ } readdir($dh);
closedir $dh;
opendir (my $dh, "$end_worktree/openpower/configs")
or die "can't scan $end_worktree defconfigs";
my @end_platforms = grep { /.*_defconfig/ } readdir($dh);
closedir $dh;
s/_defconfig// foreach (@begin_platforms);
s/_defconfig// foreach (@end_platforms);
my $witherspoon_insanity;
# If both witherspoon and witherspoon-sequoia exist we've switched back
# to a single witherspoon platform and the -sequoia platform is just to
# keep Jenkins happy - ignore it.
if ("witherspoon" ~~ @begin_platforms
&& "witherspoon-sequoia" ~~ @begin_platforms) {
my $index = 0;
$index++ until @begin_platforms[$index] eq "witherspoon-sequoia";
splice(@begin_platforms, $index, 1);
}
if ("witherspoon" ~~ @end_platforms
&& "witherspoon-sequoia" ~~ @end_platforms) {
my $index = 0;
$index++ until @end_platforms[$index] eq "witherspoon-sequoia";
splice(@end_platforms, $index, 1);
}
if (($platform && $platform eq 'witherspoon')
&& -f "$end_worktree/openpower/configs/witherspoon-sequoia_defconfig") {
@begin_platforms = ('witherspoon');
@end_platforms = ('witherspoon-sequoia', 'witherspoon-redbud');
$witherspoon_insanity = 1;
} elsif ($platform) {
@begin_platforms = ($platform);
@end_platforms = ($platform);
}
$dbh->do("CREATE TABLE platforms (platform TEXT, version TEXT);") or die "$!";
{
my $q = "INSERT INTO platforms (platform,version) VALUES (?,?)";
my $sth = $dbh->prepare($q) or die "$!";
$sth->execute($_, $begin_release) foreach (@begin_platforms);
$sth->execute($_, $end_release) foreach (@end_platforms);
}
{
my $q = "SELECT platform as p FROM platforms WHERE version is ? AND platform NOT IN (SELECT platform FROM platforms WHERE version is ? and platform=p)";
my $sth = $dbh->prepare($q) or die $!;
$sth->execute($begin_release, $end_release);
my $r;
print OUTPUT "\n## Removed platforms\n\n- ".$r->{p}."\n" if $r = $sth->fetchrow_hashref;
print OUTPUT "- ".$r->{p}." \n" while ($r = $sth->fetchrow_hashref);
$sth->execute($end_release, $begin_release);
print OUTPUT "\n## New platforms\n\n- ".$r->{p}."\n" if $r = $sth->fetchrow_hashref;
print OUTPUT "- ".$r->{p}." \n" while($r = $sth->fetchrow_hashref);
}
my @common_platforms;
{
my $q = "SELECT platform as p FROM platforms WHERE version is ? AND EXISTS (select platform from platforms where version is ? and platform=p)";
my $sth = $dbh->prepare($q) or die $!;
$sth->execute($begin_release, $end_release);
my $r;
push @common_platforms, $r->{p} while ($r = $sth->fetchrow_hashref);
}
use Data::Dumper;
print "# COMMON PLATFORMS\n";
print Dumper(\@common_platforms);
foreach my $p (@common_platforms) {
next if $p =~ /firenze/;
next if $p =~ /^zz$/;
next if $p =~ /mambo/;
next if $p =~ /opal/;
next if $p =~ /redbud/;
next if $p =~ /pseries/;
next if $p =~ /witherspoon-redbud/;
if ($p =~ /witherspoon-sequoia/) {
$p = "witherspoon";
$witherspoon_insanity = 1;
}
next if ($p =~ /witherspoon_dev/);
$repos->{"$p-xml"} = { REPO => "https://github.com/open-power/$p-xml" ,
DIR => "openpower/package/$p-xml" };
}
foreach my $p (@begin_platforms) {
system("bash -c '(cd $begin_worktree && . op-build-env && op-build ".$p."_defconfig && op-build legal-info)'");
# Work-around bug in op-build v1.17, fixed 2 commits later
system('sed -e \'s/,""\([^",]\)/,"\1/; s/\([^,]\)"",/\1",/; s/machine-xml-"\(.*\)".tar/machine-xml-\1.tar/\' -i '. $begin_worktree .'/output/legal-info/manifest.csv');
# Forgive me for this....
system("sqlite3 release-notes.sqlite \".mode csv\" \".import $begin_worktree/output/legal-info/manifest.csv i\"");
$dbh->do("ALTER TABLE i RENAME to 'begin_".$p."_manifest'") or die $!;
}
foreach my $p (@end_platforms) {
print "# END PLATFORMS LEGAL-INFO $p\n";
system("bash -c '(cd $end_worktree && . op-build-env && op-build ".$p."_defconfig && op-build legal-info)'");
# Forgive me for this....
print "# loading manifest\n";
system("sqlite3 release-notes.sqlite \".mode csv\" \".import $end_worktree/output/legal-info/manifest.csv i\"");
$dbh->do("ALTER TABLE i RENAME to 'end_".$p."_manifest'") or die $!;
}
if ($witherspoon_insanity) {
$dbh->do("ALTER TABLE 'end_witherspoon-sequoia_manifest' RENAME to end_witherspoon_manifest");
$dbh->do("ALTER TABLE 'begin_witherspoon-sequoia_manifest' RENAME to begin_witherspoon_manifest");
@end_platforms = grep { $_ != 'witherspoon-sequoia' } @end_platforms;
@begin_platforms = grep { $_ != 'witherspoon-sequoia' } @begin_platforms;
push @end_platforms, 'witherspoon';
push @begin_platforms, 'witherspoon';
push @common_platforms, 'witherspoon';
}
$dbh->do(<<'SQL') or die "$!";
CREATE TABLE package_upgrades (
PACKAGE TEXT,
OLDVERSION TEXT,
NEWVERSION TEXT,
PLATFORM TEXT
)
SQL
foreach my $p (@common_platforms) {
$dbh->do("INSERT INTO package_upgrades select b.package,b.version,e.version,'$p' from 'begin_".$p."_manifest' as b LEFT JOIN 'end_".$p."_manifest' AS e ON b.package=e.package WHERE b.version != e.version") or die $!;
}
$dbh->do(<<'SQL') or die "$!";
CREATE TABLE new_package (
PACKAGE TEXT,
VERSION TEXT,
PLATFORM TEXT
)
SQL
foreach my $p (@common_platforms) {
$dbh->do("INSERT INTO new_package select b.package,b.version,'$p' from 'end_".$p."_manifest' as b WHERE NOT EXISTS(SELECT package FROM 'begin_".$p."_manifest' AS e WHERE b.package=e.package)") or die $!;
}
$dbh->do(<<'SQL') or die "$!";
CREATE TABLE removed_package (
PACKAGE TEXT,
VERSION TEXT,
PLATFORM TEXT
)
SQL
foreach my $p (@common_platforms) {
$dbh->do("INSERT INTO removed_package select b.package,b.version,'$p' from 'begin_".$p."_manifest' as b WHERE NOT EXISTS(SELECT package FROM 'end_".$p."_manifest' AS e WHERE b.package=e.package)") or die $!;
}
my $old_level = {};
my $new_level = {};
{
my $q = <<'SQL';
select package as pk ,oldversion as o ,newversion as n,
GROUP_CONCAT(platform,', ') as ps
FROM package_upgrades
GROUP BY package,oldversion,newversion
ORDER BY package,platform
SQL
my $sth = $dbh->prepare($q) or die $!;
$sth->execute();
print OUTPUT "\n## Updated Packages\n\n";
print OUTPUT "Package | Old Version | New Version | Platforms \n";
my $t;
my ($plen,$olen,$nlen,$platlen) = (3,3,3,3);
while (my $r = $sth->fetchrow_hashref) {
$t.= join(' | ',($r->{pk}, $r->{o}, $r->{n}, $r->{ps}))." \n" ;
$plen = length($r->{pk}) if $plen < length($r->{pk});
$olen = length($r->{o}) if $olen < length($r->{o});
$nlen = length($r->{n}) if $nlen < length($r->{n});
$platlen = length($r->{ps}) if $platlen < length($r->{ps});
if ($r->{pk} eq 'machine-xml') {
$old_level->{$r->{ps}."-xml"} = $r->{o};
$new_level->{$r->{ps}."-xml"} = $r->{n};
} else {
$old_level->{$r->{pk}} = $r->{o};
$new_level->{$r->{pk}} = $r->{n};
}
}
print OUTPUT "-"x$plen." | "."-"x$olen." | "."-"x$nlen." | ".
"-"x$platlen." \n";
print OUTPUT $t;
}
{
my $q = <<'SQL';
select package as pk ,version as v,
GROUP_CONCAT(platform) as ps
FROM new_package
GROUP BY package,version
ORDER BY package,platform
SQL
my $sth = $dbh->prepare($q) or die $!;
$sth->execute();
print OUTPUT "\n\n## New Packages\n\n";
print OUTPUT "Package | Version | Platforms \n";
print OUTPUT "--- | --- | --- \n";
while (my $r = $sth->fetchrow_hashref) {
print OUTPUT join(' | ',($r->{pk}, $r->{v}, $r->{ps}))." \n" ;
if ($r->{pk} eq 'machine-xml') {
$new_level->{$r->{ps}."-xml"} = $r->{v};
}
}
}
{
my $q = <<'SQL';
select package as pk ,version as v,
GROUP_CONCAT(platform) as ps
FROM removed_package
GROUP BY package,version
ORDER BY package,platform
SQL
my $sth = $dbh->prepare($q) or die $!;
$sth->execute();
print OUTPUT "\n\n## Removed Packages\n\n";
print OUTPUT "Package | Version | Platforms \n";
print OUTPUT "--- | --- | --- \n";
while (my $r = $sth->fetchrow_hashref) {
print OUTPUT join(' | ',($r->{pk}, $r->{v}, $r->{ps}))." \n" ;
if ($r->{pk} eq $r->{ps}."-xml") {
$old_level->{$r->{ps}."-xml"} = $r->{v};
}
}
print OUTPUT "\n\n";
}
foreach my $repo (keys %{$repos})
{
if (-e $repo)
{
system("cd $repo; git fetch") && die "Could not fetch $repo";
}
else
{
system("git clone $repos->{$repo}->{REPO} $repo") &&
die "Could not clone $repo";
}
}
system("cd op-build; git checkout $end_release --force; git reset HEAD --hard");
my $op_url = $repos->{'op-build'}->{REPO};
foreach my $repo (sort keys %{$repos})
{
my $package = $repo;
my $url = $repos->{$repo}->{REPO};
my $dir = $repos->{$repo}->{DIR};
print OUTPUT "\n## Package: $repo \n";
print OUTPUT "[Repository]($url) \n";
print OUTPUT "\n";
# Display patches.
if (open(LSLOG, "ls op-build/$dir/*.patch | ".
"xargs -n1 --no-run-if-empty basename |"))
{
print OUTPUT "### Patches \n";
while (my $logline = <LSLOG>)
{
chomp $logline;
print OUTPUT "* [$logline]".
"($op_url/tree/$end_release/$dir/$logline) \n";
}
close LSLOG;
print OUTPUT "\n";
}
else
{
print OUTPUT "None. \n";
}
# Display changes.
print OUTPUT "### Commits \n";
if ((not exists $old_level->{$package}) &&
(not exists $new_level->{$package}))
{
# No change identified.
print "No changes: $repo \n";
print OUTPUT "No changes.\n\n";
next;
}
if ((exists $old_level->{$package}) &&
(exists $new_level->{$package}))
{
print "Changes in $repo... \n";
open(GITLOG, "cd $repo; git shortlog $old_level->{$package}...".
"$new_level->{$package} --no-merges --format=".
"\"- [%h]($url/commit/%h) %s\" |");
while (my $logline = <GITLOG>)
{
chomp $logline;
$logline =~ s/^[[:space:]]*//;
$logline =~ s/:$/:\n/;
print OUTPUT "$logline \n";
}
close GITLOG;
print OUTPUT " \n";
next;
}
if (not exists $old_level->{$package})
{
print "New package $repo.\n";
print OUTPUT "New package. \n";
next;
}
if (not exists $new_level->{$package})
{
print "Deleted package $repo.\n";
print OUTPUT "Package removed. \n";
next;
}
}