# Создание сервера непрерывной интеграции

Создайте собственную систему непрерывной интеграции с помощью API состояния.

С помощью REST API можно связать фиксации со службой тестирования, чтобы каждый push-запрос можно протестировать и представить в запросе GitHub на вытягивание. Дополнительные сведения о соответствующих конечных точках см. в разделе [Конечные точки REST API для состояния фиксации](/ru/enterprise-server@3.22/rest/commits/statuses).

В этом руководстве данный интерфейс API используется для демонстрации возможной конфигурации.
В описываемом сценарии мы выполним указанные ниже действия.

* Запустите наш набор непрерывной интеграции (CI) при открытии запроса на вытягивание (мы зададим состояние CI "в ожидании").
* По завершении непрерывной интеграции мы зададим соответствующее состояние запроса на вытягивание.

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

Если вы еще не сделали этого, [скачайте `ngrok`](https://ngrok.com/)и узнайте, как [его](https://ngrok.com/docs/getting-started/) использовать. Мы считаем, что это очень полезное средство для предоставления локальных приложений в Интернете.

Примечание. Полный исходный код для этого проекта можно скачать из [репозитория platform-samples](https://github.com/github/platform-samples/tree/master/api/ruby/building-a-ci-server).

## Создание сервера

Мы создадим небольшое приложение Sinatra, чтобы подтвердить работоспособность локальных подключений.
Начнем с этого:

```ruby
require 'sinatra'
require 'json'

post '/event_handler' do
  payload = JSON.parse(params[:payload])
  "Well, it worked!"
end
```

(Если вы не знакомы с тем, как работает Sinatra, рекомендуем [ознакомиться с руководством по Sinatra](http://www.sinatrarb.com/).)

Запустите этот сервер. По умолчанию Sinatra начинается с порта `4567`, поэтому вы также хотите настроить `ngrok` для этого прослушивание.

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

Давайте создадим репозиторий, с которым можно спокойно экспериментировать. Мы предлагаем [репозиторий @octocat Spoon/Knife](https://github.com/octocat/Spoon-Knife).

После этого вы создадите в репозитории новый веб-перехватчик, задав URL-адрес, `ngrok` который дал вам, и выберите `application/x-www-form-urlencoded` тип контента.

Щелкните **Обновить веб-перехватчик**. Вы должны увидеть текст ответа `Well, it worked!`.
Отлично! Установите переключатель в положение **Разрешить мне выбрать отдельные события** и выберите следующее:

* Состояние
* Запрос на вытягивание

Это события GitHub , которые будут отправляться на наш сервер всякий раз, когда происходит соответствующее действие. Давайте обновим сервер так, чтобы пока он обрабатывал *только* сценарий запроса на вытягивание:

```ruby
post '/event_handler' do
  @payload = JSON.parse(params[:payload])

  case request.env['HTTP_X_GITHUB_EVENT']
  when "pull_request"
    if @payload["action"] == "opened"
      process_pull_request(@payload["pull_request"])
    end
  end
end

helpers do
  def process_pull_request(pull_request)
    puts "It's #{pull_request['title']}"
  end
end
```

Почему? Каждое событие, GitHub которое отправляет присоединенный `X-GitHub-Event` заголовок HTTP. Пока нас интересуют только события, связанные с запросами на вытягивание. Из них мы возьмем полезные данные и вернем поле заголовка. В идеальном сценарии сервер должен обрабатывать каждое обновление запроса на вытягивание, а не только его открытие. Это позволяет гарантировать, что каждая новая отправка проходит тесты CI.
Однако в этой демонстрации нас будет интересовать только открытие запроса.

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

## Работа с состояниями

Реализовав сервер, мы готовы приступить к выполнению первого требования: заданию (и обновлению) состояний CI. Обратите внимание, что при каждом обновлении сервера можно щелкнуть **Доставить повторно**, чтобы отправить те же полезные данные. Создавать новый запрос на вытягивание каждый раз, когда вы вносите изменения, не нужно.

Так как мы взаимодействуем с GitHub API, мы будем использовать [Octokit.rb](https://github.com/octokit/octokit.rb) для управления нашими взаимодействиями. Мы настроим этот клиент с [помощью personal access token](/ru/enterprise-server@3.22/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens):

```ruby
# !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!!
# Instead, set and test environment variables, like below
ACCESS_TOKEN = ENV['MY_PERSONAL_TOKEN']

before do
  @client ||= Octokit::Client.new(:access_token => ACCESS_TOKEN)
end
```

После этого необходимо просто обновить запрос GitHub на вытягивание, чтобы убедиться, что мы обрабатываем ci:

```ruby
def process_pull_request(pull_request)
  puts "Processing pull request..."
  @client.create_status(pull_request['base']['repo']['full_name'], pull_request['head']['sha'], 'pending')
end
```

Здесь мы выполняем три основных задачи:

* Мы ищем полное имя репозитория
* Мы ищем последний SHA запроса на вытягивание
* Мы устанавливаем состояние "ожидающий"

Вот и все! Далее можно запустить любой необходимый процесс для выполнения набора тестов. Возможно, вы собираетесь передать код в Jenkins или вызвать другую веб-службу через ее API, например [Travis](https://api.travis-ci.com/docs/). После этого потребуется еще раз обновить состояние. В нашем примере мы просто задаем `"success"`:

```ruby
def process_pull_request(pull_request)
  @client.create_status(pull_request['base']['repo']['full_name'], pull_request['head']['sha'], 'pending')
  sleep 2 # do busy work...
  @client.create_status(pull_request['base']['repo']['full_name'], pull_request['head']['sha'], 'success')
  puts "Pull request processed!"
end
```

## Заключение

В GitHub мы уже много лет используем версию [Janky](https://github.com/github/janky) для управления нашим CI.
Процесс в целом такой же, как и в случае с созданным выше сервером.
В GitHub мы:

* активируем Jenkins при создании или обновлении запроса на вытягивание (через Janky);
* ожидаем ответа о состоянии CI;
* если код зеленый, выполняется слияние запроса на вытягивание.

Все это взаимодействие передается в наши комнаты чата. Чтобы использовать этот пример, не нужно создавать собственную конфигурацию CI.
Всегда можно положиться на интеграции [GitHub ](https://github.com/integrations).