# Livraison de déploiements

À l’aide de l’API REST Déploiements, vous pouvez créer des outils personnalisés qui interagissent avec votre serveur et une application tierce.

Vous pouvez utiliser l’API REST pour déployer vos projets hébergés sur GitHub un serveur que vous possédez. Pour plus d’informations sur les points de terminaison permettant de gérer les déploiements et les états, consultez [Points de terminaison d’API REST pour les déploiements](/fr/enterprise-server@3.22/rest/deployments). Vous pouvez également utiliser l’API REST pour coordonner vos déploiements au moment où votre code arrive sur la branche par défaut. Pour plus d’informations, consultez « [Création d’un serveur CI](/fr/enterprise-server@3.22/rest/guides/building-a-ci-server) ».

Ce guide utilise l’API REST pour illustrer une configuration possible.
Dans notre scénario, nous allons :

* Fusionner une pull request.
* Une fois l’intégration continue (CI) terminée, nous définirons l’état de la demande de tirage en conséquence.
* Une fois que le pull request est fusionné, nous lancerons notre déploiement sur notre serveur.

Notre système CI et notre serveur hôte seront le fruit de notre imagination. Il pourrait s’agir de Heroku, d’Amazon, ou de toute 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, veillez à [télécharger `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/delivering-deployments).

## É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 :

* Déploiement
* état du déploiement
* 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. Nous allons tout de suite configurer notre serveur pour *simplement* gérer lorsqu'un pull request est fusionné.

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

  case request.env['HTTP_X_GITHUB_EVENT']
  when "pull_request"
    if @payload["action"] == "closed" && @payload["pull_request"]["merged"]
      puts "A pull request was merged! A deployment should start now..."
    end
  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. Lorsqu'une pull request est fusionnée (son état est `closed`, et `merged` est `true`), nous déclenchons un déploiement.

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

## Travail avec les déploiements

Avec notre serveur en place, le code en cours d'examen et notre pull request fusionnée, nous voulons que notre projet soit déployé.

Nous allons commencer par modifier notre écouteur d’événements pour traiter les demandes de tirage lors de leur fusion, et commencer à prêter attention aux déploiements :

```ruby
when "pull_request"
  if @payload["action"] == "closed" && @payload["pull_request"]["merged"]
    start_deployment(@payload["pull_request"])
  end
when "deployment"
  process_deployment(@payload)
when "deployment_status"
  update_deployment_status
end
```

En fonction des informations reçues de la demande de tirage, nous allons commencer par remplir la méthode `start_deployment` :

```ruby
def start_deployment(pull_request)
  user = pull_request['user']['login']
  payload = JSON.generate(:environment => 'production', :deploy_user => user)
  @client.create_deployment(pull_request['head']['repo']['full_name'], pull_request['head']['sha'], {:payload => payload, :description => "Deploying my sweet branch"})
end
```

Des déploiements peuvent avoir des métadonnées attachées, sous la forme d’une `payload` et d’une `description`. Bien que ces valeurs soient facultatives, elles sont utiles pour la journalisation et la représentation des informations.

Lorsqu'un nouveau déploiement est créé, un événement entièrement distinct est déclenché. C’est pourquoi nous avons un nouveau cas `switch` dans le gestionnaire d’événements pour `deployment`. Vous pouvez utiliser ces informations pour être averti lors du déclenchement d’un déploiement.

Les déploiements pouvant prendre un peu de temps, nous voulons écouter divers événements, tels que le moment de création du déploiement et l’état dans lequel il se trouve.

Simulons un déploiement qui effectue un certain travail, et observons son effet sur la sortie. Commençons par compléter notre méthode `process_deployment` :

```ruby
def process_deployment
  payload = JSON.parse(@payload['payload'])
  # you can send this information to your chat room, monitor, pager, etc.
  puts "Processing '#{@payload['description']}' for #{payload['deploy_user']} to #{payload['environment']}"
  sleep 2 # simulate work
  @client.create_deployment_status("repos/#{@payload['repository']['full_name']}/deployments/#{@payload['id']}", 'pending')
  sleep 2 # simulate work
  @client.create_deployment_status("repos/#{@payload['repository']['full_name']}/deployments/#{@payload['id']}", 'success')
end
```

Enfin, nous allons simuler le stockage des informations d’état en tant que sortie de console :

```ruby
def update_deployment_status
  puts "Deployment status for #{@payload['id']} is #{@payload['state']}"
end
```

Décomposons ce qui se passe. Un nouveau déploiement est créé par `start_deployment`, ce qui déclenche l’événement `deployment`. À partir de là, nous appelons `process_deployment` pour simuler le travail effectué. Pendant ce traitement, nous effectuons également un appel à `create_deployment_status`, qui permet à un récepteur de savoir ce qui se passe lorsque nous basculons l’état sur `pending`.

Une fois le déploiement terminé, nous définissons l’état sur `success`.

## Conclusion

Chez GitHub, nous avons utilisé une version de `Heaven` pour gérer nos déploiements depuis longtemps. Un flux commun est essentiellement le même que celui du serveur que nous avons généré ci-dessus :

* Attendez une réponse sur l’état des vérifications de CI (réussite ou échec)
* Si les vérifications requises passent, fusionnez la pull request.
* `Heaven` prend le code fusionné et le déploie sur des serveurs de préproduction et de production
* Entre-temps, `Heaven` informe également tout le monde de la build, via la présence de [Hubot](https://github.com/github/hubot) dans nos salles de conversation

Et voilà ! Vous n’avez pas besoin de générer votre propre configuration de déploiement pour utiliser cet exemple.
Vous pouvez toujours vous appuyer sur des intégrations [GitHub](https://github.com/integrations).