Хотя концепция семантического управления версиями широко известна и используется в индустрии программного обеспечения, ее выполнение может быстро превратиться в запутанный беспорядок. Номер версии объявляется в нескольких местах (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 убедитесь, что у пользователя есть доступ на запись к мастеру.
- Сообщение фиксации «[пропустить CI]» необходимо, чтобы избежать повторного запуска сборки. Без него запустится бесконечный каскад сборок.
Вывод:
На этом этапе вы можете спросить себя, зачем вообще автоматизировать изменение одной цифры? Во-первых, потому что мы можем. Во-вторых, это избавляет разработчиков от необходимости не забывать обновлять его с каждым запросом на вытягивание и проверять его при просмотре запросов на вытягивание. В-третьих, репозиторий автоматически лучше организован, что делает операции более предсказуемыми и автоматизированными. В-четвертых, что наиболее важно, между процессом CI и процессом контроля версий создается петля обратной связи.
Мы можем обучить конвейеры автоматизировать рутинные изменения в нашем репозитории, такие как обработка пакетов контролируемых узлов, удаление кода на основе использования, форматирование и т. Д. Возможность доработать эти системы бизнес-логики в виде конфигураций кода не только сможет облегчить головную боль разработчика, но и лучше справляться с долгосрочными сложностями и помогать бизнесу выигрывать!