Статьи

Творческое использование для Webhooks

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

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

Когда вы выполняете определенные действия в репозитории Git, у вас есть возможность вызывать данный скрипт. Это называется хуком, и в Git есть несколько типов хуков. Например, вы можете выполнить скрипт непосредственно перед внесением изменений в репозиторий или перед отправкой в ​​удаленный репозиторий.

Эти примеры для локального хранилища. Однако при использовании службы размещения репозитория, такой как Bitbucket, у вас есть возможность выполнять веб-хуки. Они очень похожи на ловушку Git, но вместо выполнения сценария вы отправляете HTTP-запрос на заданный URL-адрес, с различной полезной нагрузкой в ​​зависимости от типа webhook.

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

Первый шаг для настройки ловушки POST для данного репозитория — это установить репозиторий на место. Для этого урока я собираюсь использовать модифицированную версию примера Jumbotron от Bootstrap . Вы можете получить репозиторий из Bitbucket или просто раскрутить его в своей учетной записи. Этот пример аналогичен Jumbotron от Bootstrap, но использует RequireJS и управляет зависимостями через npm и Bower.

Как только у вас будет хранилище, пришло время настроить POST-хук. Перейдите к обзору репозитория, перейдите в « Настройки» и перейдите в раздел « Хуки ». В качестве типа подключения выберите POST и введите URL-адрес для отправки HTTP-запроса, когда репозиторий будет перемещен. Это все, что вам нужно сделать на стороне Bitbucket, чтобы автоматизировать процесс развертывания через webhooks.

Установите POST-хук в Bitbucket

После того, как вы сконфигурировали ловушку POST для своего репозитория, следующее, что вам нужно сделать, это перехватить запрос и в этом случае клонировать и построить репозиторий по общедоступному пути HTML. Для этого мы будем использовать NodeJS с ExpressJS . Давайте создадим скрипт, который будет обрабатывать клонирование, установку, сборку и перемещение приложения. Это bash-скрипт, который мы можем выполнить с нашего сервера NodeJS.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
#/bin/bash
 
git clone $1
 
cd tuts-webhooks
 
npm install
 
bower install
 
node_modules/requirejs/bin/r.js -o build.js
rm build/build.txt
 
rm -rf /usr/share/nginx/www/tuts-webhooks.bitslice.net/html/*
mv build/* /usr/share/nginx/www/tuts-webhooks.bitslice.net/html/.
cd ../
rm -rf tuts-webhooks

Этот скрипт выполняет все шаги, необходимые для получения кода приложения, а также строит, оптимизирует и перемещает результат в общедоступное местоположение сервера. $1 относится к первому аргументу скрипта, который в данном случае является URL-адресом хранилища. Однако обратите внимание, что пути установлены на пути на моем сервере, и ваши, скорее всего, будут другими, поэтому обновите их, чтобы скрипт работал правильно.

С этим сценарием мы можем запустить его вручную с URL-адресом хранилища и получить рабочую версию нашего веб-сайта. Однако мы не хотим выполнять его вручную, и именно здесь NodeJS и запрос Bitbucket POST будут работать. Давайте создадим сервер, который будет отвечать на запрос ловушки POST и выполнять предыдущий скрипт.

Описание сервера, который будет обрабатывать запросы POST-хука, выглядит следующим образом.

01
02
03
04
05
06
07
08
09
10
{
    «name» : «WebHooksTutsPlus»,
    «description» : «Server application used to catch requests send from the Tuts Bitbucket Webhooks repository.»,
    «version» : «1.0.0»,
    «private» : true,
    «dependencies» : {
        «body-parser» : «~1.0.x»,
        «express» : «4.xx»
    }
}

Единственными зависимостями для этого простого сервера являются Express и body-parser для обработки полезной нагрузки запросов JSON.

Теперь для фактического сервера NodeJS код выглядит следующим образом.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
var bodyParser = require( ‘body-parser’ ),
    express = require( ‘express’ ),
    app = express();
        
var site = require( ‘./routers/site’ );
 
app.use( bodyParser.json() );
app.use( bodyParser.urlencoded() );
 
app.get( ‘/’, function ( req, res, next ) {
    res.send( ‘Hooks listener running’ );
});
app.use( ‘/site’, site );
 
app.listen( 9090 );

Это очень простой веб-сервер, который прослушивает порт localhost 9090. В строке 10 у нас есть метод, который прослушивает базовый URL-адрес сервера и отправляет текстовое сообщение, чтобы просто убедиться, что сервер работает. Теперь для сценария, который фактически обрабатывает перехват POST, добавьте следующий сценарий и поместите его в папку _routers_ .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
var express = require( ‘express’ ),
    router = express.Router();
 
router.post( ‘/’, function ( req, res, next ) {
    var payload = JSON.parse( req.param( ‘payload’ ) ),
        repo = payload.canon_url + payload.repository.absolute_url,
        exec = require( ‘child_process’ ).exec;
 
    exec( ‘./site.sh ‘ + repo + ‘ site’, function ( error, stdout, stderr ) {});
 
    res.json({ message : ‘Site updated’ });
});
 
module.exports = router;

Этот маршрутизатор прослушивает POST-запросы к URL-адресу сайта. Он просто создает URL-адрес хранилища из полезной нагрузки запроса и выполняет наш ранее созданный сценарий с URL-адресом хранилища. Для простоты мы не обрабатываем вывод метода exde NodeJS и не проверяем ошибки при выполнении скрипта.

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

Хорошо, это здорово: наш сайт обновляется автоматически, когда мы вносим изменения в репозиторий. Но сейчас мы не проверяем какую-либо информацию при выполнении процесса обновления. Одной из самых основных проверок, которые мы можем и должны выполнить, является источник запроса, и Bitbucket дает нам IP-адреса, с которых может происходить перехват POST. С помощью этой информации мы можем теперь изменить наш сервер, чтобы попытаться обновить веб-сайт только тогда, когда запрос поступает из этого источника. Добавьте следующий код в начало нашего метода маршрутизатора.

1
2
3
4
if ( req.ip != ‘131.103.20.165’ && req.ip != ‘131.103.20.166’ ) {
    res.json({ message : ‘Untrusted origin’ });
    return;
}

Обратите внимание, что если Bitbucket обновил свои исходящие IP-адреса, нам нужно обновить этот раздел. Еще одна вещь, которую следует учитывать, — это то, что, по крайней мере, в моем случае я использую nginx в качестве обратного прокси-сервера, поэтому сейчас вызов req.ip вернет 127.0.0.1 и не будет работать. Чтобы это исправить, мы должны указать нашему серверу доверять прокси и использовать исходный IP. Достаточно просто: нам просто нужно добавить следующий код над первым app.use() в нашем server.js.

1
app.enable( ‘trust proxy’ );

И все, теперь наш req.ip даст исходный IP-адрес, и мы можем проверить исходящие адреса Bitbucket.

В этом примере для обработки запроса используется сервер NodeJS, а сервер прослушивает порт 9090 локального хоста. Поэтому, чтобы это работало, я использую nginx в качестве обратного прокси-сервера для передачи удаленного запроса на сервер NodeJS. Настройка nginx в качестве обратного прокси-сервера выходит за рамки этого руководства, но важно упомянуть и использовать эквивалентную конфигурацию при выполнении следующих действий. Также не забудьте выполнить команду npm install перед первым запуском сервера.

В этой серии мы увидели несколько действительно интересных возможностей и способов воспользоваться возможностями Bitbucket. И мы только что поцарапали поверхность webhooks. Существует множество различных триггеров и информации, предоставляемой каждым хуком (прочитайте, какая другая информация передается в хите Bitbucket POST), так что вы можете, например, настроить его на получение оповещений, когда кто-то разветвляет ваш репозиторий. Или на более продвинутой стороне спектра вы можете создать мобильное приложение, чтобы получать push-уведомления при выполнении определенных действий.

Оставляйте любые комментарии, вопросы и любые другие отзывы в разделе комментариев ниже.