Friday, December 27, 2013

Perl development workflow

There is a Perl module that I have been developing. It is now finding its way onto CPAN and the openSUSE Build Service; the process of reaching that goal, however, was a bit tedious -- hence this blog entry which will describe the workflow so I won't have to reinvent the wheel each time I want to do this again.

Prerequisites


First, I set up a project on SourceForge (or Github) and clone it to my local machine. I do _NOT_ add any files to this project yet.

Second, if I know nothing about CPAN distributions, I read this tutorial ("How CPAN Distributions Work") at a minimum.

Third, on my local machine, I "mint a distribution". Using module-starter:
# zypper in perl-Module-Starter
$ man module-starter
$ module-starter --module=[MODULE_NAME_WITH_COLONS] --author=[MY_NAME] --email=[MY_EMAIL] \
--license=artistic2 --minperl=5.10.0
$ cd [MODULE_NAME_WITH_HYPHENS]

Fourth, having already set up the Git repo with my SourceForge project as a remote, I put the newly "minted" distribution into the git repo:
$ cp -a * [GIT_REPO_DIR]
$ cd [GIT_REPO_DIR]
$ git add .
$ git commit -m "Commit freshly minted dist skeleton"
$ git push

Coding


At this point, I will need to write some code and documentation in lib/PATH/TO/MY/MODULE.pm (note that the skeleton is already provided for me there), and unit tests in the 't' subdirectory (some tests are already provided there -- these have to be tweaked and twaddled, and real tests added to put my code through its paces).

Let's now say that I have reached a point in the development process where I want to release a new version of the code to the wider world of open source software. The next thing at this point is to edit the following files (at least), if I haven't done so already:
  • Makefile.PL
  • MANIFEST
  • Changes

Check the version number


I will want to be very careful to make sure the version number is correct throughout the distribution. It can and does appear in several places, and they all have to be set to the exact same number. Also, though Perl doesn't "force" me into any particular version number format, the de facto standard is X.YZ (e.g. 0.01). There are some permissible variations on this theme, like W.XYZ (and V.WX_YZ if I try hard enough), but in general if I deviate from this standard I am asking for trouble, in the form of additional work.

Push the changes to remote git repo


This part is well-documented, and I rely on the following commands to do most of the work: git status, git add, git commit, get remote, git push, vim .git/config

Prepare and push release to CPAN


Though on my local machine I may be able to simply put my XYZ.pm file in the right place and use it, and this is fine for one-off personal needs, or while improvising, it is wholly inadequate when it comes to packaging. For that I will need a distribution, which is a Gzipped tarball in a special, standardardized structure. I have already set up the skeleton for this tarball in the first step (using module-starter) and presumably I have already written my code, including documentation (POD), and I have unit tests (Test::More being the de facto standard here) in a subdirectory entitled 't'. I have all of this stuff in my git repo.

My next trick is to build the distribution tarball. This involves running 'make' and creating lots of crufty files that can be considered temporary in the sense that I won't need them (and can easily re-build them if I do), and I don't want this cruft in my git repo. On the other hand, my git repo contains additional stuff like the .git directory and, later, my .spec file (at the very least), and I don't want these in my CPAN distribution, since that is considered upstream. Ideally, I would like to create a temporary directory and copy only the files I need to build the distribution. Here is a one-liner that does just that:
From the local git repo:
$ rsync -av --files-from=MANIFEST . ~/tmp/[MODULE_NAME_WITH_HYPHENS]/

Seeing as I used module-starter and I have edited all the files properly, I run the following commands in the new temporary directory ~/tmp/[MODULE_NAME_WITH_HYPHENS]:
$ make clean
$ perl Makefile.PL
$ make test
$ make dist

And then I upload the resulting tarball (ending in .tar.gz) to CPAN by pointing my browser to this URL and "logging in" with my PAUSE credentials.

Prepare and push release to openSUSE Build Service


For this step, I will need a proper .spec file -- possibly use this one as a model.

And now execute the following steps, replacing 'perl-Date-Holidays-CZ' with the name of my package. (Note: if my package is Foo::Bar::Baz in Perl, on the openSUSE Build Service the package needs to be named 'perl-Foo-Bar-Baz'):
1. make sure version number in perl-Date-Holidays-CZ.spec is correct
2. make sure we have cloned devel:languages:perl/perl-Date-Holidays-CZ from OBS
3. cp ~/tmp/Date-Holiday-CZ/Date-Holidays-CZ-[VERSION_NUM].tar.gz ~/devel:languages:perl/perl-Date-Holidays-CZ/
4. cp perl-Date-Holiday-CZ.spec perl-Date-Holiday-CZ.changes ~/devel:languages:perl/perl-Date-Holidays-CZ/
5. cd ~/devel:languages:perl/perl-Date-Holidays-CZ/
6. oosc build openSUSE-13.1 x86_86 (e.g.)
7. review spec file (version number)
8. less Changes (copy latest changes)
9. oosc vc (paste latest changes)
10. oosc ci
11. wait for OBS to publish the new version (can take some time, depending on how busy it is)
12. make sure you have devel:languages:perl as an active repo in /etc/zypp/repos.d
13. zypper ref devel_languages_perl
14. zypper up perl-Date-Holidays-CZ


A text-mode summary of the above:
Release workflow
================

Releasing involves:

1. making changes in local git working directory
2. pushing the changes to sourceforge
3. pushing the changes to CPAN
4. pushing the changes to the openSUSE Build Service


Make changes in local git 
-------------------------

1. make changes
2. test changes
3. increment version number in CZ.pm and perl-Date-Holidays-CZ.spec
4. log change to Changes file
5. git status, git add, git commit


Push changes to sourceforge
---------------------------

1. git remote -v
2. git push


Push changes to CPAN
--------------------

1. verify that we are in local git working directory
2. rsync -av --files-from=MANIFEST . ~/tmp/Date-Holiday-CZ/
3. cd ~/tmp/Date-Holiday-CZ/
4. perl Makefile.PL
5. make test
6. review test results
7. if all green, make dist
8. upload resulting file to PAUSE via this web page:
   https://pause.perl.org/pause/authenquery?ACTION=add_uri


Push changes to openSUSE Build Service
--------------------------------------

1. make sure version number in perl-Date-Holidays-CZ.spec is correct
2. make sure we have cloned devel:languages:perl/perl-Date-Holidays-CZ from OBS
3. cp ~/tmp/Date-Holiday-CZ/Date-Holidays-CZ-[VERSION_NUM].tar.gz ~/devel:languages:perl/perl-Date-Holidays-CZ/
4. cp perl-Date-Holiday-CZ.spec perl-Date-Holiday-CZ.changes ~/devel:languages:perl/perl-Date-Holidays-CZ/
5. cd ~/devel:languages:perl/perl-Date-Holidays-CZ/
6. oosc build openSUSE-13.1 x86_86 (e.g.)
7. review spec file (version number)
8. less Changes (copy latest changes)
9. oosc vc (paste latest changes)
10. oosc ci
11. wait for OBS to publish the new version
12. make sure you have devel:languages:perl as an active repo in /etc/zypp/repos.d
13. zypper ref devel_languages_perl
14. zypper up perl-Date-Holidays-CZ

No comments:

Post a Comment