Хотя концепция семантического управления версиями широко известна и используется в индустрии программного обеспечения, ее выполнение может быстро превратиться в запутанный беспорядок. Номер версии объявляется в нескольких местах (package.json, переменные среды, теги версии, конфигурации CI и т. д.). Запоминание об обновлении всех этих местоположений является нагрузкой на память разработчика, и частое запоминание об обновлении номера версии вообще часто не работает. После того, как эта проблема постоянно мешала нашей стратегии развертывания в контрактном клубе, мы решили, что пришло время разработать длительный процесс. Чтобы увидеть рабочий пример, перейдите на https://bitbucket.org/Scfast/pipelines-autoversion или https://github.com/scfast/autoversion.

Вот как это сделать:

Шаг 1. Сократите все ссылки на номера версий до одного места.

Прямо вперед — поищите в базе кода и инструментах CI ссылки на номер версии и убедитесь, что все они ссылаются на одно и только одно место. По традиции мы использовали поле версии по умолчанию в package.json. Чтобы сослаться на это значение в любом файле javascript, используйте следующее объявление:

const currentVersion = require(‘./package.json’).version;

Намеренное использование const для сохранения неизменности номера версии во время выполнения.

Для ссылки на номер версии в bash наша команда использовала инструмент командной строки jq (https://stedolan.github.io/jq/download/). Подробнее об этом ниже.

Шаг 2. Настройте автоматическую пометку Git во время процесса непрерывной интеграции.

Часть CI нашей команды использует Bitbucket Pipelines. Команды, используемые для захвата номера версии и автоматической маркировки отправки репозитория, который инициировал сборку:

- declare -x VERSION=$(jq -r '.version' package.json)
- echo $VERSION
- git tag $VERSION
- git push origin --tags

Единственной магией здесь может быть первая команда. По сути, инструмент командной строки «jq» ищет в файле package.json поле «версия». Затем jq возвращает значение «версия» (скажем, «1.2.3»). Флаг ‘-r’ убирает кавычки с возвращаемого значения (теперь только 1.2.3). Значение сохраняется в переменной VERSION, которая создается как тег и передается в ветку, запустившую сборку. Вы можете использовать теги с кавычками, но после того, как я лично столкнулся с этим, я рекомендую не использовать теги с кавычками по причинам, которые будут слишком долго объясняться здесь.

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

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

Для Contract Club мы решили автоматизировать номер патча с каждым объединенным запросом на включение в мастер. Незначительные и основные обновления являются более субъективными и изменяются вручную, когда это оправдано ходом разработки. Это было успешным с нашим стилем разработки на основе ствола.

Возвращаясь к конвейерам Bitbucket, сначала реализуйте стратегию рабочего процесса ветки (см. https://confluence.atlassian.com/bitbucket/branch-workflows-856697482.html). Во-вторых, создайте скрипт для обновления номера исправления в package.json. Мы только что использовали gulp-задачу под названием автоверсия, чтобы выполнить это:

const gulp = require('gulp');
const runSequence = require('run-sequence'); // Run tasks sequentially
const jsonModify = require('gulp-json-modify');
gulp.task('upversion', function () {
let ver = require('./package.json').version; //version defined in the package.json file
console.log('current version: ', ver)
let splitString = ver.split('.', 3)
let patchVersion = splitString[2].split('"',1)let patchNumber = Number(patchVersion[0])
patchNumber++
splitString[2] = String(patchNumber);
process.env.VERSION = splitString.join('.');
console.log(process.env.VERSION)
})
gulp.task('saveversion', function () {
return gulp.src(['./package.json'])
.pipe(jsonModify({
key: 'version',
value: process.env.VERSION
}))
.pipe(gulp.dest('./'))
})
gulp.task('autoversion', function () {
runSequence('upversion','saveversion');
})

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

pipelines:
  default:
    - step:
      script:
        # Regular CI process for feature branches
branches:
    master:
      - step:
        script:
          # PACKAGE INSTALLATIONS
          - npm install
          - npm install -g gulp
          # AUTO VERSIONING
          - git config remote.origin.url https://<URL to repository here>
          - gulp autoversion
          - git init
          - git config user.name "<your username>"
          - git config user.email "<your email>"
          - git add package.json
          - git commit -m "[skip CI]"
          - git push
          - declare -x VERSION=$(jq -r '.version' package.json)
          - echo $VERSION
          - git tag $VERSION
          - git remote -v
          - git push origin --tags

Пара замечаний:

  • В этом примере используется HTTPS. Использование SSH предпочтительнее. Если вы используете HTTPS, убедитесь, что у пользователя есть доступ на запись к master.
  • Сообщение коммита «[пропустить CI]» необходимо, чтобы избежать повторного запуска сборки. Без него сработает бесконечный каскад билдов.

Вывод:

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

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