Непрерывная интеграция (CI)

GitBeginner
Практиковаться сейчас

Введение

Представьте, что вы пишете книгу большой командой. Каждый раз, когда кто-то добавляет новую главу, нужно проверять её на орфографические ошибки и несоответствия сюжета. Делать это вручную утомительно.

В разработке программного обеспечения эту задачу решает непрерывная интеграция (CI). CI автоматически проверяет изменения сразу после их появления: обычно устанавливает зависимости, запускает тесты и проверяет проект после каждого обновления.

Главная идея CI — быстро получать обратную связь. Проблемы проще исправить сразу после внесения изменения, а не через несколько дней.

Именно поэтому CI обычно становится первым уровнем автоматизации, который создают команды. Он защищает основную ветку, превращая каждое отправление изменений в автоматическую проверку качества.

В этой лабораторной работе вы создадите такую защиту для простого приложения Node.js. Вы:

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

Предварительные требования

Эта лабораторная работа продолжает предыдущую. Мы снова будем использовать репозиторий github-actions-basics, который вы создали ранее.

Подготовьте проект Node.js

Сначала нам понадобится код для тестирования. Мы создадим небольшое приложение Node.js. Если вы не программист, не беспокойтесь — ниже приведён весь необходимый код.

Перейдите в каталог проекта. Поскольку это новое окружение лабораторной работы, репозиторий нужно снова загрузить.

cd ~/project
git clone https://github.com/your-username/github-actions-basics.git
cd github-actions-basics

Примечание: не забудьте заменить your-username своим именем пользователя GitHub.

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

1. «Рецепт» (package.json)

Этот файл сообщает компьютеру, что представляет собой проект и какие инструменты ему нужны. Мы указываем, что проект использует инструмент тестирования jest.

cat > package.json << EOF
{
  "name": "ci-demo",
  "version": "1.0.0",
  "scripts": {
    "test": "jest"
  },
  "dependencies": {
    "jest": "^29.7.0"
  }
}
EOF

2. «Блюдо» (index.js)

Это код самого приложения. Он содержит простую функцию, складывающую два числа.

cat > index.js << EOF
function sum(a, b) {
  return a + b;
}
module.exports = sum;
EOF

3. «Проверка вкуса» (index.test.js)

Это автоматический тест. Он утверждает, что результат сложения 1 и 2 должен быть равен 3.

cat > index.test.js << EOF
const sum = require('./index');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});
EOF

Теперь файлы созданы, и их нужно сохранить в GitHub. Выполните стандартные команды Git, чтобы отправить свою работу.

git add .
git commit -m "Add Node.js project files"
git push

GitHub может снова запросить вход. Используйте имя пользователя и Personal Access Token (PAT), как и раньше.

Создайте рабочий процесс CI

Теперь нужно объяснить нашему роботу-помощнику, как тестировать этот код. Мы создадим файл рабочего процесса ci.yml в стандартном каталоге .github/workflows.

touch .github/workflows/ci.yml

Откройте этот файл в редакторе nano.

nano .github/workflows/ci.yml

Добавьте следующую конфигурацию. Ниже мы объясним новые элементы.

name: Node.js CI

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 16

Здесь появляется новое важное ключевое слово: uses.

Это один из важных шаблонов GitHub Actions. Вместо того чтобы вручную описывать каждый шаг оболочки, рабочие процессы часто используют повторно применяемые actions, которые упаковывают распространённые задачи: извлечение кода, настройку языка или загрузку артефактов.

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

  • actions/checkout@v4: это стандартный action, который говорит роботу: «Загрузи мой код». Без него рабочее пространство робота останется пустым.
  • actions/setup-node@v3: устанавливает Node.js на runner. Мы также передаём конкретную версию (16), чтобы обеспечить единообразие окружения.

Сохраните файл и выйдите из редактора (Ctrl+X, Y, Enter).

Добавьте шаги установки и тестирования

Код у нас уже есть — он извлекается на шаге checkout, — и инструмент Node.js тоже установлен. Теперь нужно фактически запустить тест.

В экосистеме Node.js для этого используются две стандартные команды:

  1. npm install: загружает все зависимости, перечисленные в package.json, например инструмент тестирования jest.
  2. npm test: запускает тестовый скрипт, определённый в package.json.

Вместе эти шаги отражают суть CI: подготовить окружение, установить зависимости и проверить код на чистом runner до того, как считать изменение работоспособным.

Добавим эти шаги в рабочий процесс. Снова откройте .github/workflows/ci.yml.

nano .github/workflows/ci.yml

Добавьте следующие два шага в конец файла. Убедитесь, что отступы совпадают с отступами предыдущих шагов.

- name: Install dependencies
  run: npm install

- name: Run tests
  run: npm test

Полный файл должен выглядеть так:

name: Node.js CI

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 16

      - name: Install dependencies
        run: npm install

      - name: Run tests
        run: npm test

Сохраните файл и выйдите из редактора.

Теперь активируйте защиту, отправив этот файл в GitHub.

git add .
git commit -m "Add CI pipeline"
git push

Откройте свой репозиторий на GitHub и перейдите на вкладку Actions. Вы должны увидеть запущенный новый рабочий процесс с именем «Node.js CI». После завершения рядом с ним появится зелёная галочка. Это означает, что код работает!

CI Pipeline

Нарушьте сборку

Защита полезна только тогда, когда срабатывает при падении. Намеренно «сломаем» код и посмотрим, как работает система CI.

Изменим файл теста так, чтобы он фактически выдавал неверное утверждение. Мы заявим, что результат 1 + 2 должен быть равен 4.

Откройте index.test.js с помощью nano.

nano index.test.js

Измените ожидаемый результат теста с 3 на 4.

const sum = require("./index");

test("adds 1 + 2 to equal 3", () => {
  expect(sum(1, 2)).toBe(4); // CHANGED 3 to 4
});

Сохраните файл и выйдите из редактора. Теперь зафиксируйте и отправьте этот «баг».

git add .
git commit -m "Intentionally break the test"
git push

Сразу вернитесь на вкладку Actions в GitHub. Наблюдайте за запуском нового рабочего процесса.

Через несколько мгновений запуск должен завершиться ошибкой. Рядом с коммитом появится значок красного X. Это система CI буквально кричит: «Стоп! Что-то не так!»

Откройте неудачный запуск, затем выберите задание build. Раскройте шаг Run tests, чтобы увидеть журнал ошибки:

Error: expect(received).toBe(expected) // Object.is equality

Expected: 4
Received: 3

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

CI Pipeline Failed

Итоги

В этой лабораторной работе вы создали профессиональный конвейер непрерывной интеграции.

Вы научились:

  • определять «рецепт» проекта с помощью package.json;
  • использовать ключевое слово uses для подключения мощных инструментов, таких как actions/checkout и actions/setup-node;
  • автоматизировать тестирование, чтобы робот проверял каждое изменение кода;
  • понимать значение «красного X» как защиты вашего кода.

Далее мы узнаем, как взять работающий код и упаковать его для публикации!