# Création d’un serveur CI

Générez votre propre système CI à l’aide de l’API État.

Vous pouvez utiliser l’API REST pour associer des commits à un service de test, afin que chaque push que vous effectuez puisse être testé et représenté dans une GitHub pull request. Pour plus d’informations sur les points de terminaison pertinents, consultez [Points de terminaison de l’API REST pour les statuts de commit](/fr/enterprise-server@3.22/rest/commits/statuses).

Ce guide utilise cette API pour illustrer une configuration que vous pouvez utiliser.
Dans notre scénario, nous allons :

* Exécuter notre suite CI quand une demande de tirage est ouverte (nous définirons l’état de CI sur pending).
* Une fois le CI terminé, nous définirons l’état de la demande de tirage en conséquence.

Notre système CI et notre serveur hôte seront le fruit de notre imagination. Vous pouvez utiliser Travis, Jenkins ou autre chose. Ce guide porte principalement sur l’installation et la configuration du serveur gérant la communication.

Si vous ne l’avez pas déjà fait, [téléchargez `ngrok`](https://ngrok.com/), puis apprenez à [l’utiliser](https://ngrok.com/docs/getting-started/). Cet outil est très utile pour exposer des applications locales sur Internet.

Remarque : Vous pouvez télécharger le code source complet de ce projet [à partir du dépôt platform-samples](https://github.com/github/platform-samples/tree/master/api/ruby/building-a-ci-server).

## Écriture de votre serveur

Nous allons écrire rapidement une application Sinatra pour prouver que nos connexions locales fonctionnent.
Commençons par ceci :

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

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

(Si vous n’êtes pas familiarisé avec le fonctionnement de Sinatra, nous vous recommandons de [lire le guide Sinatra](http://www.sinatrarb.com/).)

Démarrez ce serveur. Par défaut, Sinatra démarre sur le port `4567`. Vous devez également donc configurer `ngrok` pour qu’il commence à écouter ce port.

Pour que ce serveur fonctionne, nous devons configurer un dépôt avec un webhook. Le webhook doit être configuré pour se déclencher à chaque création ou fusion d'une pull request.

Créez un dépôt dans lequel vous vous sentez à l’aise pour expérimenter. Pourquoi pas le référentiel Spoon/Knife d’[@octocat](https://github.com/octocat/Spoon-Knife) ?

Après cela, vous allez créer un webhook dans votre dépôt, en lui fournissant l’URL que `ngrok` vous a donnée et en choisissant `application/x-www-form-urlencoded` comme type de contenu.

Cliquez sur **Mettre à jour le webhook**. Vous devriez voir la réponse de corps suivante : `Well, it worked!`.
Très bien ! Cliquez sur **Me laisser sélectionner des événements individuels**, puis sélectionnez ce qui suit :

* Statut
* Demande de tirage (pull request)

Il s’agit des événements GitHub qui sont envoyés à notre serveur chaque fois que l’action appropriée se produit. Mettons à jour notre serveur pour gérer *uniquement* le scénario de pull request dès maintenant.

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

Que se passe-t-il ? Chaque événement que GitHub envoie comporte un en-tête HTTP `X-GitHub-Event`. Pour l’instant, nous allons uniquement nous occuper des événements de demande de tirage. À partir de là, nous prendrons la charge utile d’informations et retournerons le champ de titre. Dans un scénario idéal, notre serveur devrait s'intéresser à chaque fois qu'une pull request est mise à jour, pas simplement lorsqu'elle est ouverte. Nous aurions ainsi la confirmation que chaque nouvelle poussée réussit les tests CI.
Mais pour les besoins de cette démonstration, nous allons simplement nous intéresser à l’ouverture.

Pour tester cette preuve de concept, apportez des modifications à une branche dans votre dépôt de test et ouvrez une pull request. Votre serveur doit répondre en conséquence !

## Gestion des statuts

Une fois notre serveur en place, nous sommes prêts à démarrer notre première exigence, qui consiste à définir (et à mettre à jour) les états de CI. Chaque fois que vous mettez à jour votre serveur, vous pouvez cliquer sur **Relivrer** pour envoyer la même charge utile. Il n'est pas nécessaire de créer une nouvelle pull request chaque fois que vous apportez une modification !

Comme nous interagissons avec l’API GitHub , nous allons utiliser [Octokit.rb](https://github.com/octokit/octokit.rb) pour gérer nos interactions. Nous allons configurer ce client avec [un personal access token](/fr/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
```

Après cela, il nous suffira de mettre à jour la pull request sur GitHub pour indiquer clairement que le traitement s’effectue sur la 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
```

Nous effectuons trois opérations basiques ici :

* Nous recherchons le nom complet du référentiel
* Nous recherchons le dernier SHA de la pull request
* Nous définissons l’état sur « en attente »

Et voilà ! À partir de là, vous pouvez exécuter n’importe quel processus dont vous avez besoin pour exécuter votre suite de tests. Vous pouvez par exemple transmettre votre code à Jenkins ou appeler un autre service web par le biais de son API, comme [Travis](https://api.travis-ci.com/docs/). Après cela, pensez à mettre à jour l’état une fois de plus. Dans notre exemple, nous allons simplement le définir sur `"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
```

## Conclusion

Chez GitHub, nous avons utilisé une version de [Janky](https://github.com/github/janky) pour gérer notre CI depuis des années.
Le flux de base est essentiellement le même que celui du serveur que nous avons créé ci-dessus.
Chez GitHub, nous :

* déclenchons un travail Jenkins lorsqu’une demande de tirage est créée ou mise à jour (via Janky) ;
* attendons une réponse sur l’état du CI ;
* Si le code est vert, nous fusionnons la pull request.

Toutes ces communications sont synthétisées dans nos salles de conversation. Vous n’avez pas besoin de créer votre propre configuration CI pour utiliser cet exemple.
Vous pouvez toujours vous appuyer sur des intégrations [GitHub](https://github.com/integrations).