Введение
Представьте, что вы пишете книгу большой командой. Каждый раз, когда кто-то добавляет новую главу, нужно проверять её на орфографические ошибки и несоответствия сюжета. Делать это вручную утомительно.
В разработке программного обеспечения эту задачу решает непрерывная интеграция (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 для этого используются две стандартные команды:
npm install: загружает все зависимости, перечисленные вpackage.json, например инструмент тестированияjest.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.
Изменим файл теста так, чтобы он фактически выдавал неверное утверждение. Мы заявим, что результат 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 экономит разработчикам множество часов: он обнаруживает ошибки сразу после их появления, а не через несколько дней или недель.

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



