Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Using a Single Point of Truth for $VERSION in a distribution?

by jcb (Parson)
on Apr 17, 2020 at 03:00 UTC ( [id://11115663]=perlquestion: print w/replies, xml ) Need Help??

jcb has asked for the wisdom of the Perl Monks concerning the following question:

I have recently uploaded the first indexed release of WARC to CPAN and found that PAUSE only indexed the top-level module because that is the only module where $VERSION is defined — all other modules simply alias \$WARC::VERSION using a typeglob assignment. Perl itself understands this approach (the WARC testsuite verifies it for each module) but PAUSE and Kwalitee apparently do not.

I believe the regex m/(?:use|require)\s+($PackageName)\s*;\s*\*($PackageName)::VERSION\s*=\s*(?:\\\$|\*)\1::VERSION\s*;/, where $PackageName is a regex matching a Perl package name (tentatively qr/[[:alpha:]][[:alnum:]_:]+/ but there is probably a more precise pattern possible), and tests that $2 is loaded with the current package name and that $1 is loaded with the name of another package in the same distribution would be enough to recognize code using this technique.

Where do I need to contribute code to make this work properly, or is the community fundamentally opposed to applying SPOT here and proper indexing will require all of the modules to contain their own $VERSION values literally?

If all modules must explicitly define $VERSION independently, is it necessary for each module's series of version numbers to be "dense" or is simply copying the release version in which the module was most recently changed suitable? Are there existing tools for maintaining these with code stored in a Git repository or do I need to write such a tool? If I need to write a tool, where would be the appropriate place to put it on CPAN?

Replies are listed 'Best First'.
Re: Using a Single Point of Truth for $VERSION in a distribution?
by Corion (Patriarch) on Apr 17, 2020 at 06:38 UTC

    I use perl-reversion -bump from Perl::Version to bump the version string in all scripts and modules of a distribution at the same time.

    Having a $VERSION in every file is important to me, because files do get copied between distributions or (partially) restored from backup and it is highly confusing if running the code outputs a different (file) version than the file actually is.

      In this case "backup" is a Git repository and the Git history is the authoritative file history, so tracking versions at file granularity in the files seems superfluous to me.

      Does perl-reversion -bump also increment $VERSION in files that were not changed at all? That would be a problem for me, since it would create many "same file, only different" versions of most of the files in WARC — I tend to only change a few files to implement the next step on the roadmap, then make another release to get at least CPAN Testers feedback.

      Copying files between distributions is more of a concern to me. On one hand, that is perfectly allowed under the licensing, but on the other, it violates encapsulation and sets (other people) up for future maintenance problems. Is this really that common in the CPAN community? If so, I may need to abandon the idea of applying SPOT to distribution versioning and put unique $VERSION literals in each module.

        This may or may not be common in the CPAN community, but if a file is installed on some disk, it may get copied somewhere else instead of reinstalling the set of files from CPAN. Or it may get restored from backup, as I already said.

        The $VERSION is not for you, the module author, but for the sysadmin and/or programmer to find what version of a file they really have, and which distribution it belongs to.

        Only in the second step, it is also for you, because bug reports will be much easier to resolve when you have a unique version.

        And yes, you will have to get accustomed to a "bump version numbers, regenerate META files" commit in your commit history for every release.

      I recommend my perl-bump-version since 1) it will install as a script unlike perl-reversion, and 2) it correctly handles Perl versions unlike Perl::Version.
Re: Using a Single Point of Truth for $VERSION in a distribution?
by 1nickt (Canon) on Apr 17, 2020 at 10:55 UTC

    Hi jcb, I use Dist::Zilla for building and releasing distributions. That's what it's for, it's brilliant at it, and it's built and maintained by smart people who release a lot of distros. There's a learning curve. Some people are intimidated by learning curves.

    There are a number of ways to manage versioning with dzil. I use a method that does two things.

    1. On build, it takes the version number from the main module and inserts it into all the other modules before building the distribution. So all the other modules get updated to the main one's version as your distro is built.
    2. On release, (after release, actually) the version number in the main module in the source directory is bumped, then the file is committed to git and pushed to origin, and you are ready to start developing the new version.

    Here is my dzil config for Dancer2::Logger::LogAny. You are welcome to copy it. Note that in the git repo there are only the files needed for dzil to build the distro, nothing more.

    Hope this helps!


    The way forward always starts with a minimal test.

      I will have to look into Dist::Zilla, with thanks for the hint to hippo and 1nickt, but from this description, it does not seem to do what I want — if the other modules are to carry the same version as the "lead" module (which in WARC exists in part for that purpose) then I firmly believe that they should actually alias that value to make it obvious that they do not have independent versions. Perl understands this, but the CPAN indexer does not.

      If I put separate $VERSION literals in each module, I want them updated if and only if that module has been changed since its version was last updated. Does Dist::Zilla support this or am I back to needing to write something that does what I want?

      Is there a convention that module versions should be "dense" or is skipping versions acceptable?

      Is there a convention for bundling distribution-specific maintenance tools into a distribution? A way to distribute a specialized support tool on a "this works for me and this distribution; feel free to use or adapt it for your work" basis?

      If I was afraid of learning curves, I would not be contributing to CPAN...

        If I put separate $VERSION literals in each module, I want them updated if and only if that module has been changed since its version was last updated.
        From a module user's viewpoint, that is an astoundingly bad idea, assuming that all the modules are packaged in a single distribution. This has nothing to do with a fetish for "density", but think about the confusion it's likely to cause users if they install MyModule 1.23 and it comes bundled with MyModule::Foo 1.21 and MyModule::Bar 1.00. "Ah, crap! I've got an old version of MyModule::Bar - I should update that and get the current version, but when I go to install 1.23, nothing happens! WTF?!? Is this thing broken? Has Bar been deprecated or discontinued? Where are they hiding the current version, if it even exists?"

        I get the impression that your real goal here is that you're trying to minimize the number of "meaningless" changes committed to your git repository. Dist::Zilla can provide this for you, while also having the same version number in each file. Not because it aliases the main module's version number into all the other files, but because it allows you to put "tags" into the file representing metadata (such as a version number) and then replaces the tags with the actual metadata values when it builds the release package. The "real" version of the file, the one in git, contains the tags, so it never needs to change for metadata updates, while the distributed versions contain the literal metadata values in each file.

        And, yeah, I realize that you may be a bit iffy about the distributed files not being identical to the files in git (I know I was, when I first heard about Dist::Zilla), but it's not really any different than a C program where you keep the source files in git, but distribute compiled binaries. The "compiling" that dzil does when building the release is much simpler and less extensive than what a C compiler does, but it still fits the same general pattern of "keep your manually-created source files in git, but not the files generated automatically from them".

        Hi again jcb.

        The remark about people fearful of learning curves had to do with the large number of negative opinions about dzil you'll hear (from people who don't use it) ... not directed at you.

        "then I firmly believe that they should actually alias that value to make it obvious that they do not have independent versions. Perl understands this, but the CPAN indexer does not."

        "If I put separate $VERSION literals in each module, I want them updated if and only if that module has been changed since its version was last updated."

        I'm afraid I'm less clear now about what you want. The second statement seems to contradict the goal implied by the first, namely that the non-primary modules should always carry the same version as the primary one. The second statement seems to imply that the different modules would/could have differing versions. It's up to you how to do it, but from what I've observed there's a lot less maintenance for the distro author if all the modules get their version number bumped together than trying to ensure that the right dependency versions are required in the build specs.

        Here's the dzil tutorial on version numbering. It addresses just the case where all modules in your distro have the same version number, showing a few plugins to do that in different ways.

        There are two-and-a-half pages of results for a metaCPAN search for 'Dist::Zilla::Plugin::Version' so I'll let you browse through them. Do your due diligence -- lots of people of varying abilities write dzil plugins. A useful technique is to look at the dist.ini of distros you admire.

        I have done no such due diligence on Dist::Zilla::Plugin::SurgicalPkgVersion but it seems to do what I think you meant by your second comment cited above ;-)

        Hope this helps!


        The way forward always starts with a minimal test.
      Please also check out my Dist::Zilla::Starter guide designed to help with this learning curve if you are willing to tackle it.
Re: Using a Single Point of Truth for $VERSION in a distribution?
by hippo (Bishop) on Apr 17, 2020 at 08:34 UTC

    See also $VERSION in module files from a couple of weeks ago where this was discussed.

    Are there existing tools for maintaining these with code stored in a Git repository or do I need to write such a tool?

    As in the other thread that probably depends on how far down the Dist::Zilla rabbit hole you are willing to go.

Re: Using a Single Point of Truth for $VERSION in a distribution?
by choroba (Cardinal) on Apr 19, 2020 at 11:14 UTC
    Another option would be to store the version in one place (be it a separate file or the main distribution module) and use a template in all other places. When running make dist (or whatever else you run to create the distribution) you'd fill in the template with the latest version. This might complicate the development process, though, if you're checking the version of a submodule somewhere in the code.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

      The testsuite verifies an import error for version 9999, but this discussion has given me the idea of keeping the typeglob aliases in the repository while changing them to literals just before rolling up a release tarball.

      Thanks to all for the help.

        So, in the end you decided to reimplement Dist::Zilla? ;-)

        If you set up a dist.ini specifying only Dist::Zilla::Plugin::PkgVersion you would have the same thing, but without having to deal with typeglobs in your module sources.

        Or, you could use Dist::Zilla::Plugin::OurPkgVersion which changes:

        package My::Module; # VERSION
        to:
        package My::Module; our $VERSION = '0.01'; # VERSION
        with a dist.ini like:
        ... version = 0.01; [OurPkgVersion]
        That is the first versioning system I used when I began with Dist::Zilla. You have to manually set the version number in your dist.ini before you build. I now use the plugins I shared earlier in this thread, so once I start a project and specify the initial version, I never have to touch the version number myself again.

        (... and of course dzil will also run the tests, build the Makefile and meta files, roll the tarball and push to CPAN ... and commit and push the changes to your Git repo, if you configure it to.)

        Of course you could build a tool to do this (will it return the source files to their "typeglob" state after rolling the tarball?). But why would you? I don't see that there's any less magic in that approach than in using the framework that many of the leading CPAN authors trust with their contributions.

        Hope this helps!


        The way forward always starts with a minimal test.
A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11115663]
Approved by GrandFather
Front-paged by haukex
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (1)
As of 2024-04-25 19:43 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found