Source

perl/keyring/auto / make_release.pl

#!/usr/bin/perl -w
#
# Package maintainer helper. Builds, tests, tags and releases
# the package to cpan. Nothing interesting, just saves some typing.

use FindBin;
use autodie qw(:all);
use Moose::Util::TypeConstraints;
use Carp;
use feature 'say';

$Carp::Verbose = 0;

{
    subtype TagNo
      => as 'Str'
      => where { $_ =~ m{^\d+\.\d{2}$} }
      => message { "Expected tag with format 1.23" };
}

{
    package RunMe;
    use Moose;
    with 'MooseX::Getopt';
    
    use Path::Class qw(file);
    use IPC::System::Simple qw(capturex systemx);
    use DateTime;

    has tag => (is=>'ro', isa=>'TagNo', required=>1);
    has force => (is=>'ro', isa=>'Bool', required=>0, default=>0);
    has noupload => (is=>'ro', isa=>'Bool', required=>0, default=>0);

    sub run {
        my $self = shift;

        chdir $FindBin::Bin;

        my $dt = DateTime->today->ymd;
        my $tag = $self->tag;

        say "* Sanity checks";

        # Some sanity checks
        $self->ensure_regexps_in_file(
            file(".hg", "hgrc"),
            qr/^pre-tag *= *python:version_hook/,
            "Version hook not installed. See version_hook.py");
        $self->ensure_regexps_in_file(
            file("MANIFEST.SKIP"),
            qr/^\^\\\.hg$/,
            ".hg not skipped. Add it to MANIFEST.SKIP",
            qr/^\^make_release\\.pl$/,
            "make_release.pl not skipped. Add it to MANIFEST.SKIP",
            qr/^\^version_hook\\.py$/,
            "version_hook.py not skipped. Add it to MANIFEST.SKIP",
           );

        $self->ensure_regexps_in_file(
            file("Changes"),
            qr/^$tag +\d{4}-\d{2}-\d{2} *$/,
            "No Changes entry. Please add\n\n$tag    $dt\n        Some desc");
            
        # Check for uncommited changes
        my $reply = capturex([0], "hg", "status");
        if($reply) {
            die "Uncommited or unmanaged files in module directory.\nCommit everything before release.\nhg status:\n$reply\n";
        }


        say "* Preliminary build";

        # Perform preliminary build and test
        systemx("perl", "Build.PL");
        systemx("./Build");
        systemx("./Build", "test");
        systemx("./Build", "distcheck");

        say "* Tag";

        # Put tag
        systemx("hg", "tag", 
                $self->force ? ("-f") : (),
                $self->tag);

        say "* Sources push";

        # Push changes
        systemx("hg", "push", "bitbucket");

        say "* Final build and test";

        # Clean, build, and test again
        systemx("./Build", "distclean");
        systemx("perl", "Build.PL");
        systemx("./Build");
        systemx("./Build", "test");
        
        say "* Distro";

        $reply = capturex("./Build", "dist");
        print $reply;
        if($reply =~ /^Creating (.*\.tar\.gz)$/m) {
            my $distro = $1;
            unless($self->noupload) {
                print "Uploading $distro\n";
                systemx("cpan-upload", $distro);
            } else {
                print "Remember to do\n    cpan-upload $distro\n";
            }
        }
    }

    sub ensure_regexps_in_file {
        my $self = shift;
        my $file = shift;
        my $rgxp = shift;
        my $comment = shift;
        unless( -f $file ) {
            die "File $file missing. $comment\n";
        }
        my @lines = $file->openr()->getlines();
        while(1) {
            unless( grep { /$rgxp/ } @lines ) {
                die "File $file does not contain expected text.\n$comment\n";
            }
            $rgxp = shift;
            $comment = shift;
            last unless $rgxp;
        }
    }

}

my $run_me = RunMe->new_with_options;
$run_me->run();