introducing Dist::Release

| No Comments | No TrackBacks
=pod I know, I know, there's already more module release managers out there than there are Elvis impersonators in Vegas. Still, module releasing seems to be a very personal kind of itch, and like so many before I couldn't resist and came up with my very own scratching stick. Of course, I've tried Module::Release. But, although it is intended to be customized to suit each author's specific needs, one has to dig fairly deep in the module's guts to do so. What I really wanted was something even more plug'n'play, something that would be brain-dead easy to plop new components in. Hence Dist::Release. In Dist::Release, the release process is seen as a sequence of steps. There are two different kind of steps: checks and actions. Checks are non-intrusive verifications (i.e., they're not supposed to touch anything), and actions are the steps that do the active part of the release. When one launches a release, checks are done first. If some fail, we abort the process. If they all pass, then we are good to go and the actions are done as well. =head2 Implementing a check To create a check, all that is needed is one module with a 'check' method. For example, here is the code to verify that the distribution's MANIFEST is up-to-date: package Dist::Release::Check::Manifest::Build; use Moose; use IPC::Cmd 'run'; extends 'Dist::Release::Step'; sub check { my $self = shift; $self->diag( q{running 'Build distcheck'} ) my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) = run( command => [qw# ./Build distcheck #] ); return $self->error( join '', @$full_buf ) if not $success or grep /not in sync/ => @$stderr_buf; } 1; Dist::Release considers the check to have failed if there is any call made to C. If there is no complain, then it assumes that everything is peachy. =head2 Implementing an action Actions are only marginally more complicated than checks. The module implementing the action can have an optional C method, which is going to be run with all the other checks, and must have a C, which make the release-related changes. For example, here's the CPANUpload action: package Dist::Release::Action::CPANUpload; use Moose; use CPAN::Uploader; extends 'Dist::Release::Action'; sub check { my ($self) = @_; # do we have a pause id? unless ($self->distrel->config->{pause}{id} and $self->distrel->config->{pause}{password} ) { $self->error('pause id or password missing from config file'); } } sub release { my $self = shift; $self->diag('verifying that the tarball is present'); my @archives = <*.tar.gz> or return $self->error('no tarball found'); if ( @archives > 1 ) { return $self->error( 'more than one tarball file found: ' . join ',', @archives ); } my $tarball = $archives[0]; $self->diag("found tarball: $tarball"); $self->diag("uploading tarball '$tarball' to CPAN"); my ( $id, $password ) = map { $self->distrel->config->{pause}{$_} } qw/ id password /; $self->diag("using user '$id'"); my $args = { user => $id, password => $password }; unless ( $self->distrel->pretend ) { CPAN::Uploader->upload_file( $tarball, $args ); } } 1; As for the C, Dist::Release figures out that a C failed if there's a call to C. =head2 Configuring for a module Configuration is done via a 'distrelease.yml' file dropped in the root directory of the project. The file looks like this: pause: id: yanick password: hush checks: - VCS::WorkingDirClean - Manifest actions: - GenerateDistribution - CPANUpload - Github It's pretty self-explanatory. The checks and actions are applied in the order they are given in the file. =head2 Crying havoc... And once the configuration file is present, all that remains to be done is to run C, sit back and enjoy the show: $ distrelease Dist::Release will only pretend to perform the actions (use --doit for the real deal) running check cycle... regular checks VCS::WorkingDirClean [failed] working directory is not clean # On branch master # Changed but not updated: # (use "git add ..." to update what will be committed) # # modified: Build.PL # modified: Changes # modified: README # modified: distrelease.yml # modified: lib/Dist/Release/Check/Manifest.pm # modified: script/distrelease # # Untracked files: # (use "git add ..." to include in what will be committed) # # STDOUT # a # blog # xml # xt/dependencies.t # xxx no changes added to commit (use "git add" and/or "git commit -a") Manifest [failed] No such file: lib/Dist/Release/Action/DoSomething.pm Not in MANIFEST: a Not in MANIFEST: blog Not in MANIFEST: lib/Dist/Release/Action/Github.pm Not in MANIFEST: STDOUT Not in MANIFEST: xml Not in MANIFEST: xt/dependencies.t Not in MANIFEST: xxx MANIFEST appears to be out of sync with the distribution pre-action checks GenerateDistribution [passed] no check implemented CPANUpload [passed] Github [passed] 2 checks failed some checks failed, aborting the release =head2 Getting the good A L is already waiting for you on CPAN. It's beta, has no documentation, is probably buggy as hell, but it's there. And the code is also available on L. Comments, suggestions, forks and patches are welcome, as always. :-)

No TrackBacks

TrackBack URL: http://babyl.dyndns.org/mt/mt-tb.cgi/158

Leave a comment

About this Entry

This page contains a single entry by Yanick published on November 10, 2008 11:02 PM.

Me at OSBootCamp 8 was the previous entry in this blog.

CPAN Patching with Git is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.