- PVSM.RU - https://www.pvsm.ru -
При разработке перл-модулей приходится делать много работы, которая практически не связана с задачами и кодом модуля — начиная от создания десятка типовых файлов/каталогов и заканчивая выполнением десятка одинаковых операций необходимых для выпуска новой версии.
Помимо того, что это скучно, лениво, и часто приводит к ошибкам (из-за необходимости обновлять мета-информацию — вроде номера версии — в нескольких файлах или нечаянного пропуска части команд при релизе) всё дополнительно осложняется перловским TIMTOWTDI — существует несколько разных систем сборки, у всех есть свои достоинства и недостатки (но нет простой таблички с их перечислением), и ни одна из них не является рекомендуемой ни официально ни сообществом.
Кроме того, многие из нас пишут на перле очень много лет, и последний раз читали perlnewmod [1] когда изучали перл. В результате, когда создаются новые модули это нередко делается в стиле 15-ти летней давности, причём система сборки выбирается практически случайным образом — либо древний, но знакомый и точно умеющий что угодно EUMM [2], либо одна из других (не потому, что нужна именно она, а просто в надежде что она окажется проще и удобнее EUMM, не создав при этом новых проблем… которые она всё-таки со временем создаёт).
Далее кратко описаны имеющиеся на начало 2015 года средства, которые могут облегчить процесс разработки перл-модулей, сделать ваши модули более современными, и упростить другим разработчикам доработку ваших модулей. Я постарался перечислить их основные плюсы и минусы, но т.к. сам пользовался не всеми то буду дополнять/исправлять этот список в соответствии с вашими комментариями.
Итак, давайте составим список задач, которые обычно входят в процесс авторинга Perl модулей.
Задачи при создании нового модуля:
Задачи при релизе новой версии:
В идеале, все решения необходимые при создании нового модуля (кроме необходимости в XS) нужно принять один раз, и в дальнейшем создавать новые модули одной командой. А при релизе, в идеале, одна команда должна выполнить все шаги кроме выбора нового номера версии и описания изменений в Changes.
In a perfect world, I would never blog about version numbers [39] in Perl.
«Version numbers should be boring» — David Golden
Перед тем как перейти к сути вопроса, необходимо описать одну проблему: выбор формата для версии модуля. Хотя это и не связано напрямую с темой статьи, этот выбор необходимо делать в процессе авторинга, и он не так прост, как может показаться.
Есть очень много способов неправильно объявить версию своего модуля, поэтому я перечислю только правильные — их намного меньше.
Стабильные релизы (две/три цифры, кому как нравится):
our $VERSION = '0.08';
our $VERSION = '0.008';
package MyModule 0.08; # need perl-5.12
package MyModule 0.008; # need perl-5.12
Альфа-версии для тестирования CPAN Testers перед выпуском 0.09
/ 0.009
:
our $VERSION = '0.08_01';
our $VERSION = '0.008_001';
Либо, учитывая что альфа-версии пользователи всё-равно не увидят, вы можете использовать две независимые последовательности для стабильных и нестабильных релизов: пример [40].
Стабильные релизы (можно использовать 3 и более чисел в версии):
use version; our $VERSION = 'v0.8.0'; # need perl-5.8.1
our $VERSION = 'v0.8.0'; # need perl-5.10
package MyModule v0.8.0; # need perl-5.12
Альфа-версии для тестирования CPAN Testers перед выпуском v0.8.1
:
use version; our $VERSION = 'v0.8.0_1'; # need perl-5.8.1
our $VERSION = 'v0.8.0_1'; # need perl-5.10
Хотя "v0.8_1"
тоже можно использовать как альфа-версию между стабильными "v0.8.0"
и "v0.8.1"
но такая версия может быть только одна — если понадобится выпустить несколько альфа-версий то выпустить стабильную с номером "v0.8.1"
уже не получится.
На данный момент нет возможности полностью соответствовать спецификации семантического версионирования [41] - pre-release версии определённые как "1.2.3-alpha1"
применить к перл-модулям нельзя. Самым близким вариантом будет вышеописанная 3-х элементная точечно-числовая версия — вы можете следовать правилам определения следующей стабильной версии по спецификации, а вместо текстовых pre-release версий выпускать числовые альфа-версии.
Вы уже заметили, что альфа версии это, как говорят наши зарубежные коллеги, «боль в заднице». Фактически ведь речь идёт не о настоящих «альфа» — настоящие альфа, бета и прочие pre-release версии описаны в спецификации семантического версионирования и не поддерживаются перлом. Речь идёт о том, чтобы дать CPAN команду «не индексировать» данную версию. Таким образом мы смешиваем в одной переменной два типа данных (номер версии и флаг для CPAN), что является плохим стилем, уродливо выглядит, запутывает (что выбрать перед выпуском "v0.8.1"
— "v0.8_1"
или "v0.8.0_1"
?) и создаёт другие проблемы: альфа версии нельзя задать в package, в некоторых старых (до 5.8.1) версиях perl они работают не корректно.
Не так давно на CPAN добавили новый способ дать команду «не индексировать» данную версию — если в имени архива с модулем есть слово "TRIAL"
. Таким образом, вы можете больше не использовать «альфа» версии. Некоторые утилиты (Dist::Zilla [42], shipit [43], …) поддерживают параметр для добавления в имя архива с модулем "-TRIAL"
перед заливанием на CPAN. Учтите, что "v1.2.3-TRIAL"
(в отличие от "v1.2_3"
) это обычная версия "v1.2.3"
, так что следующая после неё должна быть "v1.2.4"
или "v1.2.4-TRIAL"
.
Эти утилиты создают каталог с новым модулем, наполняя его базовым набором необходимых файлов по какому-то шаблону. Это самый старый, и, до сих пор, основной способ создать новый модуль. Проблема этого подхода в том, что значительную часть этих файлов мало просто однократно создать, их нужно постоянно обновлять при выпуске новых версий модуля. Поэтому многие постепенно начинают использовать вместо этих утилит более комплексные решения (обычно на базе Dist::Zilla).
Использование этих модулей описано в perlnewmod [44], но суть в том, что они очень устарели, практически не поддерживаются [45], слишком сложные и при этом недостаточно гибкие.
На CPAN можно найти ещё некоторое количество аналогичных [46] модулей [47], но все, которые видел я, были заточены под потребности их авторов и не очень гибко настраивались — по сути, задача генерации каталога с новым модулем по шаблону настолько проста, что почти каждый пишет свой велосипед (мой — это скрипт на 20 строк в ~/bin/
, тоже абсолютно не настраиваемый).
С 95% модулей содержащих несколько pm-файлов, тесты и стандартно собирающийся небольшой кусок XS — справится любая система сборки.
Начиная с 5.10.1 появилась поддержка configure_requires — т.е. теперь можно в META.{json,yml}
указать какие модули должны быть установлены до запуска perl Makefile.PL
или perl Build.PL
. Иными словами теперь не важно, установлен ли у пользователя, например, Module::Build::Tiny [48] — вы можете использовать его для сборки своего модуля. А можете написать свою систему сборки для своих модулей.
Особенности:
make
make
)Недостатки:
Makefile
(либо дописывая к нему кусок, либо как-то его преобразуя; более того, это необходимо делать портабельно как в плане формата Makefile
так и в плане используемых в нём шелл-команд) — что очень сильно всё усложняет
Достоинства:
Особенности:
make
ни знание как писать портабельный Makefile
Недостатки:
Достоинства:
Особенности:
Недостатки:
inc/
- что, в свою очередь, создало новые проблемы (а сейчас и вовсе потеряло смысл) — от необходимости перевыпускать свой модуль для исправления бага в идущей в комплекте с ним версии MI до неудобств при использовании VCS из-за того, что в репозитории постоянно обновляется код относящийся к MIДостоинства:
Несмотря на единодушную нелюбовь сообщества к EUMM и Module::Build [52], у меня сложилось впечатление что Module::Install [53] в последнее время вообще перестали воспринимать всерьёз — создаваемые им время от времени проблемы перевесили его достоинства.
Особенности:
Ваш Build.PL
выглядит так:
use 5.008001; # only if you need it
use Module::Build::Tiny;
Build_PL();
Как ни странно, но этим даже можно пользоваться — используя файл cpanfile [54] для управления зависимостями и вспомогательную утилиту mbtiny [55] для авторинга (генерации Build.PL
, MANIFEST
и META.{json,yml}
, подготовки архива с модулем — того, что делал Module::Build и что не относится к процессу сборки модуля). Либо использовать Dist::Zilla вместо mbtiny
(кстати, Dist::Milla [56] и Minilla [57] используют MBT — для таких навороченных систем как раз очень удобно, когда система сборки делает только своё дело и не берёт на себя «лишние» задачи).
Это подход, при котором зависимости указываются отдельно от системы сборки, в файле cpanfile
. Есть несколько причин это делать:
Makefile.PL
или Build.PL
и зависимости указывать просто негде) — собственно, именно ради этой возможности cpanfile и был разработан. Причём можно задать для отдельной зависимости альтернативный источник, откуда её брать — из приватного CPAN mirror, из git, etc.cpanm --installdeps .
или carton [59] без META.{json,yml}
файлов.inc/
и META.{json,yml}
и корректно указывать зависимость от Module::Install как «develop» (author_requires) а не «configure» (configure_requires). При этом другие разработчики, у которых не установлен Module::Install, смогут его установить через cpanm --with-develop --installdeps .
или carton
.
В случае перл-модулей нужно иметь в виду, что в репозитории нужно, с одной стороны, хранить все необходимые для сборки модуля файлы (чтобы его можно было устанавливать прямо из репозитория через cpanm
и чтобы после форка другие разработчики получили рабочую версию проекта), а с другой избежать замусоривания его лишними авто-генерируемыми файлами (например, файлами Module::Install в inc/
) — вам ведь их commit-ить постоянно, плюс они будут замусоривать diff, etc. Особенно это касается пользователей Dist::Zilla — если вы хотите получать pull-request-ы то не стоит требовать чтобы желающие пофиксить вам какую-то мелочь были вынуждены устанавливать 150-200 дополнительных модулей для запуска сборки проекта.
При использовании GitHub [60] вам скорее всего придётся либо писать дополнительное описание модуля в README.md
, либо настроить автоматическую генерацию этого файла из POD-документации модуля. И во втором случае может потребоваться добавлять дополнительные элементы - например, статус сборки проекта в Travis CI.
До апреля 2013 CPAN Testers [61] не поддерживал отдельное указание test_requires [62] (зависимостей необходимых только для запуска тестов). При этом системы сборки уже давно давали возможность их указывать… но это не работало. В результате некоторые разработчики модулей сильно огорчались, выпускали новую версию без всяких умных test_requires и забывали про эту фичу. Так вот, уже можно! Подробности поддержки test_requires разными версиями систем сборки. [63]
В принципе, сервис CPAN Testers покрывает основные потребности, но у него есть один недостаток: тестирование происходит уже после релиза. Чтобы прогнать модуль через CPAN Testers до релиза нужно выпускать специальные alpha-версии — и всё-равно это релиз, да и работает CPAN Testers не так уж быстро.
Подключив к репозиторию с модулем на GitHub Travis CI [64] можно автоматизировать тестирование текущей версии модуля до релиза на нескольких версиях perl [65] (хоть это и не так круто в плане разных платформ как CPAN Testers, но всё-таки лучше, чем запускать тесты только у себя на машине).
Предоставляет команду scan-prereqs-cpanfile [66] для анализа зависимостей модуля и генерирования cpanfile
или вывода отличий от текущего cpanfile
(если он модифицировался вручную и просто сгенерировать его заново это не лучшая идея).
Предоставляет команду perl-reversion [67] для изменения номера версии в (почти) всех файлах модуля.
Поддерживает README
, но не README.md
.
Предоставляет команду cpan-upload [68] для заливания модулей на CPAN из командной строки. Конфиг-файл ~/.pause
с логином/паролем для PAUSE может быть зашифрован GnuPG.
К сожалению, GitHub пока не умеет автоматически заливать перл-модули на CPAN (хотя, наверное, технически правильнее будет сказать, что это CPAN не умеет выкачивать модули с GitHub) при добавлении тега для новой версии (как это происходит, например, с плагинами для jQuery). Но я всё-равно оставлю этот пункт здесь, вдруг его увидят нужные люди и добавят фичу. ☺
Баг-трекер CPAN [69] много лет был единственным доступным вариантом. Учитывая его неудобный интерфейс это было очень печально. С другой стороны, им можно пользоваться даже если вы не используете VCS при разработке модуля.
К счастью, сейчас есть возможность указать в META.{json,yml}
(не ручками, конечно, а через используемую систему сборки) альтернативный баг-трекер (например на GitHub). К сожалению, хотя при этом изменятся ссылки на баг-трекер на сайтах CPAN и MetaCPAN [70], это не отключит возможность добавлять тикеты для вашего модуля на CPAN RT (но там показывается уведомление, что предпочитаемый баг-трекер в другом месте). Разумеется, после изменения баг-трекера текущие баги остаются в RT.
Не буду описывать преимущества и удобство поддержки проектов на GitHub (особенно бросающиеся в глаза по сравнению с CPAN RT). Тем более, что даже если не нравится Git, то можно без проблем локально работать с Mercurial и всё-равно держать проект на GitHub (через плагин hg-git [71]).
Если вы захотите переместить текущие тикеты из CPAN RT в GitHub Issues - можете попробовать воспользоваться rt-to-github.pl [72] или этой модификацией [73] его старой версии.
В этом разделе будут описаны утилиты полностью берущие на себя процесс авторинга модулей, зачастую используя при этом вышеописанные утилиты решающие отдельные подзадачи авторинга.
У меня есть два сервера, один только что установлен, там всего 27 CPAN-модулей, на втором много лет разрабатывается много перл-проектов, там установлено 248 CPAN-модулей. Я подсчитал, сколько приходится установить дополнительных CPAN-модулей на каждом из серверов для описанных в этом разделе утилит:
Это настоящий монстр. Он делает всё! На CPAN сейчас порядка 900 модулей входящих в 480 дистрибутивов расширяющих возможности Dist::Zilla. Из этих 480 дистрибутивов 315 это плагины (Dist::Zilla::Plugin::*), и ещё 100 - разные подборки этих плагинов (Dist::Zilla::PluginBundle::*).
Есть только две проблемы: сколько дней нужно потратить, чтобы он начал делать то, что нужно лично вам, и количество модулей, которые требуется установить чтобы им воспользоваться.
По первой проблеме — ничего не могу сказать. Я не рискнул связываться и пытаться его настроить под себя. Кто это сделал — поделитесь впечатлениями в комментариях.
Вторая проблема тоже достаточно важна — если вы хотите получать патчи и pull-request-ы к своему модулю, необходимо, чтобы желающие внести в него изменения могли сделать это достаточно просто. Если им для исправления пары строк нужно будет установить половину CPAN (автор утверждает что не половину, а всего 0.6% [74]) и разбираться с нестандартным процессом сборки - патч вы не дождётесь.
Особенности:
cpanfile
scan-prereqs-cpanfile --diff=cpanfile
чтобы быстро найти все новые подключенные модули, которые ещё не добавлены в cpanfile
Build.PL
редактировать смысла нет, он при каждой сборке генерируется зановоНедостатки (по сравнению с Dist::Zilla):
Достоинства:
$VERSION
при релизе)
Особенности:
Недостатки:
Достоинства:
Если вы делаете авторинг практически так же, как Tokuhiro Matsuno (автор Minilla), либо если вам всё-равно как именно делается авторинг, главное чтобы всё работало само из коробки достаточно современным образом (т.е. с использованием git и GitHub) и не требовало установки дикого количества модулей — Minilla вам идеально подойдёт. Если же потребуется что-то делать иначе — придётся искать ему замену (вероятнее всего ей окажется Dist::Milla).
Позволяет одной командой shipit
выполнить большинство операций, требуемых при выпуске новой версии.
В каталоге модуля создаётся файл .shipit
, примерно такой:
steps = FindVersion, ChangeVersion, CheckChangeLog, DistTest, Commit, Tag, MakeDist, UploadCPAN
и теперь при запуске shipit
будут выполнены указанные в .shipit
операции:
Changes
и предложит её добавитьMakefile.PL
и Build.PL
)
Все доступные операции оформлены в виде плагинов, так что на CPAN полно дополнительных модулей [76] (генерация README
из POD, обновление версии в POD, прописывание новой версии в коде каждого модуля, анонсы в соц.сети, …).
Не понятно, будет ли ShipIt поддерживаться — он уже пару лет не обновлялся, а его автор сейчас активно работает над Dist::Milla и описывает миграцию с ShipIt на Dist::Milla. На мой взгляд ShipIt делает практически всё необходимое, и при этом он очень маленький, простой, расширяемый и без зависимостей. Не знаю, что в нём не устроило автора, и почему он решил делать обёртку для Dist::Zilla вместо дописывания недостающей функциональности плагинами для ShipIt. По мнению [77] автора Dist::Zilla (который активно использовал ShipIt до того как разработать Dist::Zilla) основная проблема ShipIt — сложность и недостаточная гибкость расширения его плагинами. Надо признать, эту проблему Dist::Zilla действительно решил более чем основательно.
Долго думал, стоит ли вообще включать его в статью. Функциональность у него рудиментарная, текущая версия 0.005, год его никто не обновлял… но буквально на днях автор им активно занялся, и кроме того он необходим для использования Module::Build::Tiny напрямую, не через Dist::Zilla или Minilla.
Это не похоже на утилиту для авторинга, по крайней мере если сравнить его возможности с вышеописанными утилитами. Но автор его назвал «A standalone authoring tool», значит будем рассматривать её в этом разделе. С учётом его крайне ограниченных возможностей попробуем использовать вместе с ним другие мелкие утилиты (описанные в следующих разделах) в попытке получить полную функциональность авторинга без Dist::Zilla.
Для начала — самый минималистичный способ создать модуль для CPAN:
mkdir -p Example-MBtiny/lib/Example/
cd Example-MBtiny
vi lib/Example/MBtiny.pm
mbtiny dist
В результате получаем Example-MBtiny-$VERSION.tar.gz
который можно заливать на CPAN. Никаких других файлов в каталоге с модулем больше нет - только созданный нами lib/Example/MBtiny.pm
и этот архив.
Теперь создадим (или сгенерируем какой-нибудь утилитой) все стандартные файлы, которые обычно присутствуют в каждом современном модуле выложенном на GitHub: README.md
, LICENSE
, Changes
, t/*
, .gitignore
, .travis.yml
а так же создадим репозиторий, добавим туда все эти файлы и зальём на GitHub.
Следующий вопрос — в каком стиле использовать mbtiny
:
mbtiny test
и mbtiny dist
, то необходимые для сборки, тестирования и установки файлы Build.PL
, MANIFEST
и META.{json,yml}
будут генерироваться на лету и удаляться по завершению операции. Безусловно, они будут присутствовать в созданном архиве для заливания на CPAN, но их не будет в репозитории — что сделает невозможным установку модуля через cpanm
прямо из репозитория и может озадачить сторонних разработчиков которые хотели бы что-то изменить и прислать pull-request.mbtiny regenerate
для создания Build.PL
, MANIFEST
и META.{json,yml}
и добавить их в репозиторий. При изменении версии модуля, добавлении новых файлов, или изменении зависимостей — будет необходимо снова вызывать эту команду.
При использовании GitHub нужно добавить в проект metamerge.json
, его содержимое будет учитываться при генерации META.{json,yml}
:
{
"resources" : {
"bugtracker" : {
"web" : "https://github.com/powerman/Example-MBtiny/issues"
},
"homepage" : "https://github.com/powerman/Example-MBtiny",
"repository" : {
"type" : "git",
"url" : "git://github.com/powerman/Example-MBtiny.git",
"web" : "https://github.com/powerman/Example-MBtiny"
}
}
}
При релизе новой версии пригодятся дополнительные утилиты:
# update dependencies
scan-prereqs-cpanfile >cpanfile
# ... update META.* from cpanfile if you added META.* into the repo
mbtiny regenerate
# build & test
mbtiny test
# update version everywhere
ver=1.2.3
perl-reversion -set $ver
# don't forget to update version & date
vi Changes
# regenerate README.md with badges
cp BADGES.md README.md
pod2markdown lib/Example/MBtiny.pm >> README.md
# release
git commit -a -m "release $ver"
git tag $ver
git push
mbtiny dist
cpan-upload Example-MBtiny-$ver.tar.gz
Как видите, выполнять всё это каждый раз вручную — не лучшая идея, что-то забудешь, где-то ошибёшься. Но оформить это скриптом не сложно. Двух таких простых скриптов (этого, и создающего скелет нового модуля по шаблону) вполне достаточно для авторинга современных модулей без Dist::Zilla.
use 5.010001;
our $VERSION="v1.2.3";
"-TRIAL"
вместо использования подчёркиваний в номере версииcpanfile
META.json
Что же касается выбора утилиты для авторинга — здесь сложно дать однозначную рекомендацию. Если выбирать среди не заброшенных:
______________________
Автор: powerman
Источник [86]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/razrabotka/81740
Ссылки в тексте:
[1] perlnewmod: http://perldoc.perl.org/perlnewmod.html
[2] EUMM: https://metacpan.org/pod/ExtUtils::MakeMaker
[3] Задачи: #tasks
[4] $VERSION: #version
[5] Старая десятичная / Old-style decimal: #version-old-decimal
[6] Точечно-числовая / Dotted-decimal: #version-dotted-decimal
[7] Семантическая / Semantic: #version-semantic
[8] TRIAL: #version-trial
[9] Скелет модуля / Boilerplate: #boilerplate
[10] h2xs: #boilerplate-h2xs
[11] Сборка / Build: #build
[12] ExtUtils::MakeMaker (a.k.a. EUMM): #build-eumm
[13] Module::Build (a.k.a. MB): #build-mb
[14] Module::Install (a.k.a. MI): #build-mi
[15] Module::Build::Tiny (a.k.a. MBT): #build-mbt
[16] Управление зависимостями / Dependencies: #deps
[17] cpanfile: #deps-cpanfile
[18] Управление версиями / VCS: #vcs
[19] GitHub: #vcs-github
[20] Непрерывная интеграция / CI: #ci
[21] CPAN Testers: #ci-cpan
[22] GitHub + Travis CI: #ci-travis
[23] Выпуск / Release: #release
[24] App::scan_prereqs_cpanfile: #release-cpanfile
[25] Perl::Version: #release-version
[26] CPAN::Uploader: #release-upload
[27] GitHub: #release-github
[28] Поддержка / Support: #support
[29] CPAN RT: #support-rt
[30] GitHub: #support-github
[31] Авторинг / Authoring: #authoring
[32] Dist::Zilla: #authoring-distzilla
[33] Dist::Milla: #authoring-distmilla
[34] Minilla: #authoring-minilla
[35] ShipIt: #authoring-shipit
[36] App::ModuleBuildTiny: #authoring-ambt
[37] Резюме: #resume
[38] Разные полезности для авторов модулей: #links
[39] blog about version numbers: http://www.dagolden.com/index.php/369/version-numbers-should-be-boring/
[40] пример: http://www.cpan.org/modules/04pause.html#developerreleases
[41] спецификации семантического версионирования: http://semver.org/lang/ru/
[42] Dist::Zilla: https://metacpan.org/pod/Dist::Zilla
[43] shipit: https://metacpan.org/pod/shipit
[44] perlnewmod: http://perldoc.perl.org/perlnewmod.html#Step-by-step:-Making-the-module
[45] не поддерживаются: http://perlmonks.org/?node_id=949081
[46] аналогичных: https://metacpan.org/pod/ExtUtils::ModuleMaker
[47] модулей: https://metacpan.org/pod/Distribution::Cooker
[48] Module::Build::Tiny: https://metacpan.org/pod/Module::Build::Tiny
[49] никто не хочет его поддерживать и развивать: http://stackoverflow.com/a/214717/113120
[50] FUD: https://ru.wikipedia.org/wiki/FUD
[51] Module::Build::Pluggable: https://metacpan.org/pod/Module::Build::Pluggable
[52] Module::Build: https://metacpan.org/pod/Module::Build
[53] Module::Install: https://metacpan.org/pod/Module::Install
[54] cpanfile: https://metacpan.org/pod/cpanfile
[55] mbtiny: https://metacpan.org/pod/mbtiny
[56] Dist::Milla: https://metacpan.org/pod/Dist::Milla
[57] Minilla: https://metacpan.org/pod/Minilla
[58] CPAN::Meta::Spec 2.0: https://metacpan.org/pod/CPAN::Meta::Spec
[59] carton: https://metacpan.org/pod/Carton
[60] GitHub: https://github.com/
[61] CPAN Testers: http://cpantesters.org/
[62] test_requires: https://metacpan.org/pod/CPAN::Meta::Spec#Phases
[63] Подробности поддержки test_requires разными версиями систем сборки.: http://weblog.bulknews.net/post/46653336492/test-requires-all-the-way
[64] Travis CI: https://travis-ci.org/
[65] нескольких версиях perl: http://about.travis-ci.org/docs/user/languages/perl/
[66] scan-prereqs-cpanfile: https://metacpan.org/pod/scan-prereqs-cpanfile
[67] perl-reversion: https://metacpan.org/pod/distribution/Perl-Version/examples/perl-reversion
[68] cpan-upload: https://metacpan.org/pod/cpan-upload
[69] Баг-трекер CPAN: https://rt.cpan.org/
[70] MetaCPAN: https://metacpan.org/
[71] hg-git: http://hg-git.github.io/
[72] rt-to-github.pl: https://github.com/dagolden/zzz-rt-to-github
[73] модификацией: https://gist.github.com/markstos/5096483
[74] не половину, а всего 0.6%: http://www.dagolden.com/index.php/2293/why-installing-distzilla-is-slow-and-what-you-can-do-about-it/
[75] дополнительный плагин: https://metacpan.org/pod/Dist::Zilla::Plugin::GitHubREADME::Badge
[76] дополнительных модулей: https://metacpan.org/search?q=shipit%3A%3Astep
[77] мнению: http://stackoverflow.com/a/5898913/113120
[78] What are the files in a CPAN distribution?: http://perlmonks.org/?node_id=1009586
[79] The Annotated Lancaster Consensus: http://www.dagolden.com/index.php/2098/the-annotated-lancaster-consensus/
[80] CPAN Authors FAQ: http://wiki.cpantesters.org/wiki/CPANAuthorNotes
[81] Kwalitee indicators: http://cpants.cpanauthors.org/kwalitee
[82] How to convince Meta CPAN to show a link to the version control system of a distribution?: http://perlmaven.com/how-to-add-link-to-version-control-system-of-a-cpan-distributions
[83] Minilla — система подготовки дистрибутивов для CPAN @ Pragmatic Perl #14: http://pragmaticperl.com/issues/14/pragmaticperl-14-minilla-%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0-%D0%BF%D0%BE%D0%B4%D0%B3%D0%BE%D1%82%D0%BE%D0%B2%D0%BA%D0%B8-%D0%B4%D0%B8%D1%81%D1%82%D1%80%D0%B8%D0%B1%D1%83%D1%82%D0%B8%D0%B2%D0%BE%D0%B2-%D0%B4%D0%BB%D1%8F-cpan.html
[84] habrahabr backend: https://github.com/powerman/asciidoc-habrahabr-backend
[85] AsciiDoc: http://asciidoc.org/
[86] Источник: http://habrahabr.ru/post/249767/
Нажмите здесь для печати.