В 2010 году я выпустил маленькую библиотеку (github) для Nodejs, для API bit.ly. Она оказалась умеренно успешной - на момент публикации этой статьи она набрала 19 049 загрузок в октябре 2017 года, и в ней есть 24 других библиотеки, которые зависят от нее.

Имея это в виду, около года или около того были некоторые нерешенные проблемы, и недавно я прошел практический курс Agile TDD и рефакторинг - так что я подумал, что сейчас хорошее время применить их.

В этой статье я не собираюсь изучать сам TDD (подобные ресурсы можно найти в Интернете), но я собираюсь показать вам, как я настраивал среду, которая обеспечивала непрерывное тестирование и интеграцию, пока я реорганизовал библиотеку, в которой не было За 2 года не коснулись поддержки node 8, а в то же время была предоставлена ​​резервная поддержка для node 4, чтобы гарантировать, что она не нарушит работу программ более чем 19 000 пользователей.

Старый код пахнет

Старый класс ES6 был моей первой попыткой создать es6module, обратно совместимый с node 4. Однако, как вы можете видеть, он полон запахов и повторений, а с описанными проблемами явно не работал. Он уже был настроен на TravisCI, но тесты давали сбой, и я не смотрел на них.

Когда я построил npm-lint, у меня была простая, но эффективная установка компилятора Typescript через веб-пакет, которую я повторил здесь, но вместо этого я бы пропустил через него es7Javascript и скомпилировал поддержку обратно в es5, что означает, что узлы 4 и 6 все еще могут поддерживаться .

Первой задачей было начать писать несколько тестов и выбрать лучшую структуру для async/await тестов. В конце концов, я выбрал mocha-webpack, так как он позволил мне запустить es7 тестов для всех версий узлов, предварительно перенеся их вместе с библиотекой chai. Еще я добавил в тесты сепию, чтобы запросы кешировались и ускоряли выполнение текста локально.

Тест претерпел некоторые изменения, но позволил мне найти фрагменты кода, которые можно было разделить на две основные категории - те, которые составляют часть библиотеки, и те, которые позволяют мне раскрыть общедоступный API для обратной совместимости. В итоге тест библиотеки выглядит так.

Это позволило мне убедиться, что при рефакторинге кода библиотеки я мог ожидать того же результата. В конце концов, это позволило мне создать async/await версию метода, и я знал, что generateUrl вернет правильные значения.

Как только это было сделано, я хотел убедиться, что async/await код может быть распространен для поддержки различных версий.

Одна вещь, которая действительно изменилась в этом выпуске, - это удаление ключевого слова new при вызове фабрики, и некоторые конечные точки были удалены, поскольку bit.ly больше не поддерживает их.

На помощь приходят Webpack, Babel и Typescript

Использование Typescript в качестве транспилятора для моего es7 кода может показаться странным, но хитрость заключается в конфигурации:

Ориентируясь на es5 и commonjs и используя allowJs, мы можем передать Javascript, а поскольку TypeScript - это просто надмножество, его легко компилировать до нашего целевого формата.

Поскольку он использует babel-polyfill и цель es5, мы также получаем Promise, доступный для узла 4. Чтобы убедиться, что это работает до того, как произойдет релиз, мне нужно было настроить конвейер для его проверки.

Затем он использует конфигурацию webpack для вывода файла распространения, который работает для всех версий узла. В конце концов, узел 4 станет устаревшим, но я хотел убедиться, что в версии 5.x моей библиотеки я продолжу его поддерживать.

Непрерывная интеграция и доставка

Я никогда не был тем, кто писал тесты, но после написания хорошего набора тестов для этого кода я решил, что он действительно должен запускаться в CI и что он также должен обрабатывать сборку и распространение библиотеки, поэтому я не забываю .

Я использовал CircleCI раньше и нашел их сервисы довольно простыми в использовании, с хорошим временем безотказной работы и скоростью. После некоторой начальной работы, изучая, как работает их новая функция рабочих процессов, я создал набор заданий в конвейере, которые работают в тандеме.

Посмотреть конфиг можно здесь, он немаленький

Первая задача - запустить npm install. На самом деле мы сначала проверяем наличие кешированных ресурсов для текущей версии, с которой работаем, обновляем все модули и устанавливаем.

Далее следует интересная часть, указав только, что нашим тестовым заданиям требуется 1 задача для продолжения, а в нашей задаче установки мы настроили их для параллельного выполнения. Поскольку в нашем коде нет собственных модулей, мы можем легко запускать наши тесты через них, используя mocha-webpack для компиляции тестов для более ранних версий.

Когда все эти тесты пройдены, мы запускаем этап сборки веб-пакета и, наконец, запускаем распространение. У меня здесь две задачи: одна для производства на основе основной ветки и одна для бета-версий в любой другой ветке. Они также возвращают теги в git после выпуска npm.

Для этого вам нужно добавить свой токен аутентификации NPM и ключи SSH Git в CircleCI, но затем он обеспечивает возврат, чтобы убедиться, что ваши версии обновлены.

С такой настройкой вы можете поддерживать гораздо больше пользователей и убедиться, что ваш код хорошо протестирован (и не разочаруйте более 19 000 пользователей!).

Следующие шаги

Следующими шагами я буду создавать документацию по API из комментариев JSDoc и связывать ее из Readme, также я хочу перейти к выпуску только в определенных ветках, таких как beta. Мне также нужно добавить поддержку переменной среды, которая переключается между patch, minor and major при изменении версии на этапе выпуска.

Надеюсь, этот шаблон поможет вам настроить среду непрерывной интеграции и развертывания, которая обеспечит высокое качество вашего программного обеспечения.

(О да, TDD не отстой)