NAME
Dist::Zilla::Plugin::LicenseFile - Ship the repository's committed LICENSE, and keep it honest
VERSION
version 0.001
SYNOPSIS
; in dist.ini — note that @Basic's License plugin has to go, it would
; generate a second LICENSE and the build would abort
[@Filter]
-bundle = @Basic
-remove = License
[LicenseFile]
Then write the file once and commit it:
dzil genlicense
git add LICENSE && git commit
DESCRIPTION
Dist::Zilla generates LICENSE into the build by default, which means the file exists in the tarball on CPAN but never in the repository. Hosting platforms only see the repository: GitHub, Gitea and Forgejo all detect and link a licence from a committed LICENSE file, so a distribution built the default way shows up as unlicensed on its own project page.
The fix is to commit the file and let GatherDir pick it up like any other source file. That works, but it silently rots: nothing connects the committed text to the license setting in dist.ini any more. Switch the licence and the repository keeps serving the old one, with no warning and no build failure.
This plugin closes that gap. On every build it checks the LICENSE that was gathered from the repository against the licence the distribution declares, and refuses to build when the file is missing or no longer matches. The companion command dzil genlicense writes the file the check expects.
The plugin never writes or modifies anything itself — the committed file is shipped verbatim, and a build either passes the check or stops.
Why the bare licence text
The file holds $zilla->license->license, the licence on its own, and deliberately not ->fulltext, which is what Dist::Zilla::Plugin::License writes into the build. fulltext prefixes the licence with a copyright notice for the current distribution, and that prefix is enough to stop GitHub's detector: a repository whose LICENSE holds the fulltext of the Artistic License 2.0 is reported as NOASSERTION — GitHub links the file but names no licence. The same repository with the bare text is reported as Artistic-2.0.
Since detection is the entire reason to commit the file, the bare text wins. Nothing is lost: the copyright notice still reaches the tarball through the LICENSE AND COPYRIGHT section Pod::Weaver writes into the POD, and the holder and year still reach META.json.
required
Whether a failing check aborts the build. Defaults to true.
Set it to 0 to log the same complaint as a warning and carry on — useful while migrating an existing distribution, where the first build is the thing that tells you the file is missing.
[LicenseFile]
required = 0
filename
The name of the file, LICENSE. A class method, so that Dist::Zilla::App::Command::genlicense writes the file this plugin looks for.
wanted_text
The text the committed file is expected to hold, for a given Dist::Zilla object. A class method shared with the command, see "Why the bare licence text" for what it returns and why.
comparable
Normalises licence text for comparison, and is likewise a class method shared with the command. Only whitespace at the very end of the text is forgiven — an editor adding a final newline is not drift, any other difference is.
Both halves have to agree on this, or a distribution can end up in a state where dzil genlicense reports the file as current and the build still rejects it.
SEE ALSO
Dist::Zilla::App::Command::genlicense — writes the file this plugin checks
Dist::Zilla::Plugin::License — the default plugin, which generates
LICENSEinto the build instead
SUPPORT
Issues
Please report bugs and feature requests on GitHub at https://github.com/Getty/p5-dist-zilla-plugin-licensefile/issues.
CONTRIBUTING
Contributions are welcome! Please fork the repository and submit a pull request.
AUTHOR
Torsten Raudssus <getty@cpan.org>
COPYRIGHT AND LICENSE
This software is copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.