# Criar um servidor de CI

Crie o seu próprio sistema CI usando a API de status.

Você pode usar a API REST para associar confirmações a um serviço de teste, para que cada push que você fizer possa ser testado e representado em uma solicitação GitHub de pull. Para obter mais informações sobre pontos de extremidade relevantes, confira [Pontos de extremidade da API REST para status de commits](/pt/enterprise-server@3.22/rest/commits/statuses).

Este guia usará a API para demonstrar uma configuração que você pode usar.
No nosso cenário, vamos:

* Executar o nosso conjunto de CI quando um pull request for aberto (iremos definir o status de CI como pendente).
* Quando o CI terminar, definiremos o status do pull request.

O nosso sistema de CI e servidor de hospedagem serão fruto da nossa imaginação. Eles podem ser o Travis, o Jenkins ou qualquer outro completamente diferente. O aspecto fundamental deste guia será configurar o servidor que gerencia a comunicação.

Caso ainda não tenha feito isso, [baixe o `ngrok`](https://ngrok.com/) e aprenda como [usá-lo](https://ngrok.com/docs/getting-started/). Ele é uma ferramenta muito útil para expor aplicativos locais à Internet.

Observação: baixe o código-fonte completo deste projeto [no repositório platform-samples](https://github.com/github/platform-samples/tree/master/api/ruby/building-a-ci-server).

## Escrever o seu servidor

Vamos escrever um aplicativo simples usando Sinatra para provar que nossas conexões locais estão funcionando.
Vamos começar com isso:

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

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

(Se você não estiver familiarizado com o funcionamento do Sinatra, recomendamos [ler o guia do Sinatra](http://www.sinatrarb.com/)).

Inicie este servidor. Como o Sinatra é iniciado na porta `4567` por padrão, é recomendado configurar o `ngrok` para começar a ouvir nessa porta também.

Para que esse servidor funcione, precisamos configurar um repositório com um webhook. O webhook deve ser configurado para ser acionado sempre que um pull request for criado ou mesclado.

Vá em frente e crie um repositório onde você se sinta à vontade para experimentar. Podemos sugerir o repositório do Spoon/Knife de [@octocat](https://github.com/octocat/Spoon-Knife)?

Depois disso, você criará um webhook no repositório, alimentando-o com a URL que foi fornecida por `ngrok` e escolhendo `application/x-www-form-urlencoded` como o tipo de conteúdo.

Clique em **Atualizar webhook**. Você verá a resposta de corpo `Well, it worked!`.
Ótimo! Clique em **Deixe-me selecionar eventos individuais** e selecione o seguinte:

* Status
* Solicitação de pull

Esses são os eventos GitHub que serão enviados ao nosso servidor sempre que a ação relevante ocorrer. Vamos atualizar nosso servidor para *apenas* lidar com o cenário de solicitação de pull agora:

```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
```

O que está havendo? Cada evento enviado por GitHub tem um cabeçalho HTTP `X-GitHub-Event` anexado. Por enquanto, nos importaremos apenas com os eventos do PR. Daí em diante, usaremos o conteúdo das informações e retornaremos o campo de título. Em um cenário ideal, nosso servidor ficará preocupado com a atualização de cada solicitação de pull, não apenas quando ela é aberta. Isso asseguraria que todos os novos pushes passassem pelos testes de CI.
Mas, para essa demonstração, nós nos preocuparemos quando ela for aberta.

Para testar esta prova de conceito, faça algumas alterações em um branch no repositório de teste e abra uma solicitação de pull. Seu servidor deve responder de acordo!

## Trabalhar com status

Com o servidor implementado, estamos prontos para iniciar nosso primeiro requisito, que é configurar (e atualizar) os status de CI. Observe que, a qualquer momento, você pode clicar em **Entregar novamente** para enviar o mesmo conteúdo. Não há necessidade de fazer uma nova solicitação de pull toda vez que você faz uma alteração.

Como estamos interagindo com a GitHub API, usaremos [Octokit.rb](https://github.com/octokit/octokit.rb) para gerenciar nossas interações. Configuraremos esse cliente com [um personal access token](/pt/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
```

Depois disso, só precisaremos atualizar o pull request em GitHub para deixar claro que o processamento está sendo feito na 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
```

Aqui, estamos fazendo três coisas muito básicas:

* Estamos procurando o nome completo do repositório
* Estamos procurando o último SHA da solicitação de pull
* Estamos definindo o status como "pendente"

É isso! Daí em diante, você pode executar qualquer processo de que precise para executar o conjunto de testes. Talvez você transmita seu código para o Jenkins ou ligue para outro serviço Web por meio da API, como o [Travis](https://api.travis-ci.com/docs/). Em seguida, lembre-se de atualizar o status novamente. Em nosso exemplo, vamos apenas defini-lo como `"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
```

## Conclusão

No GitHub, usamos uma versão do [Janky](https://github.com/github/janky) para gerenciar nossa CI por anos.
O fluxo básico é essencialmente o mesmo que o servidor que construímos acima.
No GitHub, nós:

* Acionamos o Jenkins quando um pull request é criado ou atualizado (via Janky)
* Aguarde uma resposta sobre o estado do CI
* Se o código estiver verde, mesclamos o pedido de pull.

Toda esta comunicação é canalizada de volta para nossas salas de bate-papo. Você não precisa criar sua configuração de CI para usar este exemplo.
Você sempre pode contar com integrações [GitHub](https://github.com/integrations).