Ищете способы организовать плавный процесс CI/CD для своего программного обеспечения? В этой статье Tom Hastjarjanto делится кратким списком полезных концепций, которые можно комбинировать с GitHub Actions и пакетами NPM. Чтобы в полной мере воспользоваться преимуществами установки и выпуска с максимальной уверенностью, настоятельно рекомендуется иметь надежный набор тестов, который выполняется при интеграции.

Крупные технологические компании имеют возможность выпускать тысячи релизов в день. Еще в 2011 году Amazon выпускал новый софт раз в 11,6 секунды. В этих компаниях обычно есть целые команды, работающие над повышением скорости доставки продукта. К счастью, многие передовые методы, используемые в этих технологических компаниях, хорошо задокументированы и имеют инструменты с открытым исходным кодом, доступные каждой команде для достижения такой же производительности, как у крупных технологических компаний.

В этой статье мы рассмотрим несколько концепций, которые можно комбинировать для создания современного потока CI/CD для вашего программного обеспечения. Мы будем использовать GitHub Actions и пакеты NPM в качестве основы, но инструменты и концепции можно применить к любому языку. Я использовал их для успешного выпуска пакетов Python и контейнеров Docker.

Поток GitHub

GitHub Flow — это облегченная модель ветвления, предложенная GitHub. Для большинства компаний и команд этого более чем достаточно, и он очень подходит для модульного кода и микросервисов. Команды, выбравшие Gitflow, часто не работают в крайних случаях или ситуациях, для которых полный поток предлагает решения (например, исправления, несколько активных выпусков программного обеспечения).

Правила просты:

  • main всегда можно освободить;
  • Ответвление от main для внесения изменений (новая функция, исправление ошибок и т. д.);
  • Как только ветка будет завершена, создайте запрос на извлечение;
  • Как только запрос на вытягивание будет одобрен, объедините его с main;
  • Чтобы создать релиз, просто отметьте main.

Эта стратегия хорошо работает, когда ваша команда принимает недолговечные ветки и сохраняет небольшой объем изменений. Если вы решите работать над более крупными функциями и сохранять ветки в течение более длительного периода, вам будет трудно периодически разрешать конфликты слияния.

Часто создавая выпуски, вы уменьшаете объем изменений и, следовательно, риск возникновения проблем после нового развертывания. Это также уменьшит необходимость создания выпусков исправлений, поскольку их можно обрабатывать в обычном потоке разработки. Поскольку объем изменений для релизов невелик, а скорость их выпуска высока, часто нет необходимости иметь отдельные ветки релизов для каких-либо исправлений ошибок.

Семантическая версия #

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

Версия релиза указывается в следующем виде: vX.Y.Z

  • X: в этой версии внесено критическое изменение.
  • Y: в этой версии представлена ​​новая функция.
  • Z: в этой версии представлено исправление или другое невидимое изменение.

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

Обычные коммиты #

Обычные коммиты — это, как следует из названия, соглашение о том, как структурировать ваши сообщения коммитов. Шаблон этого соглашения выглядит следующим образом:

<type>[optional scope]: <description>
[optional body]
[optional footer]

Несколько практических примеров:

chore: add GitHub actions for merge requests
fix: handle empty post bodies
feat: add dropdown to specify currency

Спецификация допускает некоторую гибкость в отношении типов, но наиболее важными из них являются следующие:

  • fix
    Это изменение исправляет ошибку.
  • feat
    Это изменение вводит новую функцию или решает пользовательскую историю.
  • BREAKING CHANGE
    Это изменение представляет собой критическое изменение и приводит к необходимым действиям для пользователей этого программного обеспечения.

Стандартная версия

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

Стандартная версия анализирует ваш журнал Git для следующих целей:

  • Создание примечаний к выпуску;
  • Определение следующей версии на основе тегов Git;
  • Скачивание вашей package.json версии;
  • Создание коммита, включающего ваши примечания к выпуску и package.json версию версии;
  • Пометка коммита.

Чтобы установить стандартную версию, вы можете использовать NPM:

npm i -D standard-version

Затем вы можете добавить его в свой package.json как скрипт:

{
  "scripts": {
    "release": "standard-version"
  }
}

Или, как вариант, используйте npx:

npx standard-version

Если вы хотите создать выпуск, вы можете просто запустить npm run release, а стандартная версия возьмет на себя все остальное. Как правило, вы настраиваете конвейер CI/CD для выполнения этих задач за вас.

Если вы хотите двигаться быстро, вы можете настроить свой конвейер так, чтобы создавать выпуск каждый раз, когда запрос на вытягивание сливается с вашей кодовой базой. В этом случае вы должны быть осторожны, чтобы ваш конвейер не создал бесконечный цикл сборки, поскольку инструмент будет фиксировать и отправлять изменения в себя. В GitHub Actions вы можете включить тег [skip ci] в свои сообщения о фиксации, чтобы указать GitHub не запускать сборку CI для определенной фиксации. Вы можете настроить стандартную версию, чтобы включить тег [skip ci] в свою конфигурацию в package.json:

"standard-version": {
    "releaseCommitMessageFormat": "chore(release): {{currentTag}} [skip ci]"
}

Действия на GitHub

Если вы используете GitHub, вы можете использовать интегрированную функцию автоматизации работы под названием GitHub Actions. GitHub Actions можно использовать в качестве службы CI/CD, включив файл конфигурации YAML в каталог .github/workflows в корне репозитория.

Для примера вы можете создать файл .github/workflows/learn-github-actions.yml со следующим содержимым:

name: learn-github-actions
on: [push]
jobs:
  check-bats-version:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: '14'
      - run: npm install -g bats
      - run: bats -v

GitHub Actions можно настроить таким образом, чтобы он мог фиксировать и отсылать изменения в ваш репозиторий. Для этого вам нужно всего лишь запустить git config в вашем рабочем процессе:

- name: setup git config
run: |
    git config user.name "GitHub Actions Bot"
    git config user.email "<>"
- run: ...
- run: git push --follow-tags origin main

Собираем все вместе

Объединение всех этих концепций вместе приведет к высокоавтоматизированному потоку выпуска для вашего репозитория. Конфигурация инструментов состоит в основном из двух источников:

  1. package.json
  2. .github/workflows/<your-workflow.yml>

Вот как выглядит файл package.json (включая конфигурацию [skip ci]):

{
  "name": "cicd-demo",
  "version": "1.0.4",
  "description": "",
  "main": "hello-world.js",
  "scripts": {
    "release": "standard-version"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/Intellicode/cicd-demo.git"
  },
  "author": "Tom Hastjarjanto",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/Intellicode/cicd-demo/issues"
  },
  "homepage": "https://github.com/Intellicode/cicd-demo#readme",
  "dependencies": {
    "standard-version": "^9.3.2"
  },
  "standard-version": {
    "releaseCommitMessageFormat": "chore(release): {{currentTag}} [skip ci]"
  }
}

А это рабочий процесс GitHub Actions, который запускается при нажатии на main:

name: Release on push
on:
  push:
    branches: [ main ]
jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [16.x]
    steps:
    - uses: actions/checkout@v2
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v2
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'npm'
    - run: npm ci
    - run: npm run build --if-present
    - name: setup git config
      run: |
          git config user.name "GitHub Actions Bot"
          git config user.email "<>"
    - run: npm run release
    - run: git push --follow-tags origin main

Этот npm run release будет делать следующее:

  • обновление CHANGELOG.md новыми примечаниями к выпуску с момента последнего выпуска;
  • определение следующей версии на основе тегов Git;
  • сменить вашу версию package.json;
  • создание коммита, включающего ваши примечания к выпуску и package.json изменение версии;
  • пометка коммита.

git push --follow-tags origin main доработает релиз:

  • Он отправляет вновь созданный тег в ваш репозиторий.
  • Он обновляет main изменениями, выполненными в package.json и CHANGELOG.md.

Примечание. Полный пример доступен в моем хранилище примеров.

Заключение

Мы рассмотрели несколько концепций, которые в сочетании могут привести к эффективной автоматической настройке процедуры выпуска. С этой настройкой вы сможете выпускать несколько раз в час с полностью документированной трассировкой, управляемой Git. Чтобы в полной мере воспользоваться преимуществами установки и выпуска с максимальной уверенностью, настоятельно рекомендуется иметь надежный набор тестов, который работает при интеграции.

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

Автор: Том Хастьярьянто

Том Хастьярьянто — инженер-программист из Нидерландов. Он работает инженером-программистом-консультантом в Sytac.io. В основном он работал над приложениями JavaScript/TypeScript (веб, мобильные устройства), но в настоящее время работает с Python.