Как использовать Node.js и Github Webhooks для синхронизации удаленных проектов

Вступление

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

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

GitHub позволяет вам настроитьwebhooks для ваших репозиториев, которые представляют собой события, которые отправляют HTTP-запросы, когда происходят события. Например, вы можете использовать веб-крючок, чтобы уведомить вас, когда кто-то создает запрос на извлечение или вводит новый код.

В этом руководстве вы разработаете серверNode.js, который прослушивает уведомление о веб-перехватчике GitHub всякий раз, когда вы или кто-то другой отправляете код на GitHub. Этот сценарий автоматически обновит хранилище на удаленном сервере самой последней версией кода, избавляя от необходимости входить на сервер для получения новых коммитов.

Предпосылки

Для завершения этого урока вам понадобится:

  • Один сервер Ubuntu 16.04, настроенный следующим образомthe Ubuntu 16.04 initial server setup guide, включая пользователя без полномочий root с привилегиямиsudo и брандмауэр.

  • Git установлен на вашем локальном компьютере. Вы можете следовать руководствуContributing to Open Source: Getting Started with Git, чтобы установить и настроить Git на свой компьютер.

  • Node.js and npm installed on the remote server using the official PPA, as explained explained in How To Install Node.js on Ubuntu 16.04. Достаточно установить стабильную версию дистрибутива, поскольку она предоставляет нам рекомендуемую версию без какой-либо дополнительной настройки.

  • Репозиторий на Github, содержащий код вашего проекта. Если вы не задумываетесь о каком-либо проекте, смело используйтеfork this example, которые мы будем использовать в оставшейся части руководства.

[[step-1 -—- setting-up-a-webhook]] == Шаг 1. Настройка веб-перехватчика

Мы начнем с настройки веб-крюка для вашего хранилища. Этот шаг важен, потому что без него Github не знает, какие события отправлять, когда что-то происходит, или куда их отправлять. Сначала мы создадим webhook, а затем создадим сервер, который будет отвечать на его запросы.

Войдите в свою учетную запись GitHub и перейдите в репозиторий, который вы хотите отслеживать. Щелкните вкладкуSettings в верхней строке меню на странице репозитория, затем щелкнитеWebhooks в левом меню навигации. ЩелкнитеAdd Webhook в правом углу и введите пароль своей учетной записи, если будет предложено. Вы увидите страницу, которая выглядит следующим образом:

Webhooks Page

  • В полеPayload URL введитеhttp://your_server_ip:8080. Это адрес и порт сервера Node.js, который мы скоро напишем.

  • ИзменитеContent type наapplication/json. Сценарий, который мы напишем, будет ожидать данные JSON и не сможет понимать другие типы данных.

  • ДляSecret введите секретный пароль для этого веб-перехватчика. Вы будете использовать этот секрет на своем сервере Node.js, чтобы проверить запросы и убедиться, что они поступают с GitHub.

  • ДляWhich events would you like to trigger this webhook выберитеjust the push event. Нам нужно только событие push, так как именно тогда код обновляется и его нужно синхронизировать с нашим сервером.

  • Установите флажокActive.

  • Просмотрите поля и щелкнитеAdd webhook, чтобы создать его.

Сначала проверка связи не будет выполнена, но будьте уверены, ваш веб-крючок настроен. Теперь давайте скопируем репозиторий на сервер.

[[step-2 -—- cloning-the-repository-to-the-server]] == Шаг 2 - Клонирование репозитория на сервер

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

ssh sammy@your_server_ip

Убедитесь, что вы находитесь в своем домашнем каталоге. Затем используйте Git для клонирования вашего хранилища. Обязательно заменитеsammy своим именем пользователя GitHub, аhello_hapi - именем вашего проекта Github.

cd
git clone https://github.com/sammy/hello_hapi.git

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

С вашим клонированным проектом вы можете создать скрипт webhook.

[[step-3 -—- created-the-webhook-script]] == Шаг 3 - Создание скрипта Webhook

Давайте создадим наш сервер для прослушивания запросов веб-хука от GitHub. Мы напишем сценарий Node.js, который запускает веб-сервер на порту8080. Сервер будет прослушивать запросы от webhook, проверять секрет, который мы указали, и извлекать последнюю версию кода из GitHub.

Перейдите в свой домашний каталог:

cd ~

Создайте новый каталог для вашего скрипта веб-перехватчика с именемNodeWebhooks:

mkdir ~/NodeWebhooks

Затем перейдите в новый каталог:

cd ~/NodeWebhooks

Создайте новый файл с именемwebhook.js внутри каталогаNodeWebhooks.

nano webhook.js

Добавьте эти две строки в скрипт:

webhook.js

var secret = "your_secret_here";
var repo = "/home/sammy/hello_hapi";

Первая строка определяет переменную для хранения секрета, созданного вами на шаге 1, который проверяет, что запросы поступают от GitHub. Вторая строка определяет переменную, которая содержит полный путь к хранилищу, которое вы хотите обновить на локальном диске. Это должно указывать на хранилище, которое вы извлекли на шаге 2.

Затем добавьте эти строки, которые импортируют библиотекиhttp иcrypto в сценарий. Мы будем использовать их для создания нашего веб-сервера и хеширования секрета, чтобы мы могли сравнить его с тем, что мы получаем от GitHub:

webhook.js

let http = require('http');
let crypto = require('crypto');

Затем включите библиотекуchild_process, чтобы вы могли выполнять команды оболочки из вашего скрипта:

webhook.js

const exec = require('child_process').exec;

Затем добавьте этот код, чтобы определить новый веб-сервер, который обрабатывает запросы GitHub webhook и выводит новую версию кода, если это подлинный запрос:

webhook.js

http.createServer(function (req, res) {
    req.on('data', function(chunk) {
        let sig = "sha1=" + crypto.createHmac('sha1', secret).update(chunk.toString()).digest('hex');

        if (req.headers['x-hub-signature'] == sig) {
            exec('cd ' + repo + ' && git pull');
        }
    });

    res.end();
}).listen(8080);

Функцияhttp.createServer() запускает веб-сервер на порту8080, который прослушивает входящие запросы от Github. В целях безопасности мы проверяем, что секрет, включенный в запрос, совпадает с тем, который мы указали при создании webhook на шаге 1. Секрет передается в заголовкеx-hub-signature в виде строки с хешированием SHA1, поэтому мы хэшируем наш секрет и сравниваем его с тем, что нам отправляет GitHub.

Если запрос подлинный, мы выполняем команду оболочки для обновления нашего локального репозитория, используяgit pull.

Завершенный скрипт выглядит так:

webhook.js

const secret = "your_secret_here";
const repo = "~/your_repo_path_here/";

const http = require('http');
const crypto = require('crypto');
const exec = require('child_process').exec;

http.createServer(function (req, res) {
    req.on('data', function(chunk) {
        let sig = "sha1=" + crypto.createHmac('sha1', secret).update(chunk.toString()).digest('hex');

        if (req.headers['x-hub-signature'] == sig) {
            exec('cd ' + repo + ' && git pull');
        }
    });

    res.end();
}).listen(8080);

Если вы следовали руководству по начальной настройке сервера, вам нужно будет разрешить этому веб-серверу связываться с внешней сетью, разрешив трафик на порт8080:

sudo ufw allow 8080/tcp

Теперь, когда наш скрипт на месте, давайте удостоверимся, что он работает правильно.

Шаг 4 - Тестирование Webhook

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

cd ~/NodeWebhooks
nodejs webhook.js

Вернитесь на страницу своего проекта черезGithub.com. Щелкните вкладкуSettings в верхней строке меню на странице репозитория, а затем нажмитеWebhooks в левом меню навигации. ЩелкнитеEdit рядом с веб-перехватчиком, который вы настроили на шаге 1. Прокрутите вниз, пока не увидите разделRecent Deliveries, как показано на следующем изображении:

Edit Webhook

Нажмите три точки справа, чтобы открыть кнопкуRedeliver. Когда сервер узла запущен, щелкнитеRedeliver, чтобы отправить запрос еще раз. Как только вы подтвердите, что хотите отправить запрос, вы увидите успешный ответ. На это указывает код ответа200 OK после повторной отправки эхо-запроса.

Теперь мы можем убедиться, что наш скрипт работает в фоновом режиме и запускается при загрузке. ИспользованиеCTRL+C останавливает сервер веб-перехватчиков узла.

[[step-5 -—- install-the-webhook-as-a-systemd-service]] == Шаг 5. Установка Webhook как службы Systemd

systemd - это диспетчер задач, который Ubuntu использует для управления службами. Мы настроим сервис, который позволит нам запускать наш скрипт webhook при загрузке и использовать команды systemd для управления им, как мы это делаем с любым другим сервисом.

Начните с создания нового файла сервиса:

sudo nano /etc/systemd/system/webhook.service

Добавьте следующую конфигурацию в служебный файл, который сообщает systemd, как запустить скрипт. Это сообщает Systemd, где найти наш скрипт узла и описывает наш сервис.

Обязательно заменитеsammy своим именем пользователя.

/etc/systemd/system/webhook.service

[Unit]
Description=Github webhook
After=network.target

[Service]
Environment=NODE_PORT=8080
Type=simple
User=sammy
ExecStart=/usr/bin/nodejs /home/sammy/NodeWebhooks/webhook.js
Restart=on-failure

[Install]
WantedBy=multi-user.target

Включите новую службу, чтобы она запускалась при загрузке системы:

sudo systemctl enable webhook.service

Теперь запустите сервис:

sudo systemctl start webhook

Убедитесь, что служба запущена:

sudo systemctl status webhook

Вы увидите следующий вывод, указывающий, что служба активна:

Output● webhook.service - Github webhook
   Loaded: loaded (/etc/systemd/system/webhook.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2018-08-17 19:28:41 UTC; 6s ago
 Main PID: 9912 (nodejs)
    Tasks: 6
   Memory: 7.6M
      CPU: 95ms
   CGroup: /system.slice/webhook.service
           └─9912 /usr/bin/nodejs /home/sammy/NodeWebhooks/webhook.js

Теперь вы можете загружать новые коммиты в свой репозиторий и видеть изменения на вашем сервере.

С вашего настольного компьютера клонируйте репозиторий:

git clone https://github.com/sammy/hello_hapi.git

Внесите изменения в один из файлов в хранилище. Затем зафиксируйте файл и отправьте ваш код на GitHub.

git add index.js
git commit -m "Update index file"
git push origin master

Запустится веб-крючок, и ваши изменения появятся на вашем сервере.

Заключение

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

Related