Skip to main content

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 dans GitHub sur un serveur dont vous êtes propriétaire. 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 ». 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 ».

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

  • Fusionner une demande de tirage
  • Une fois l’intégration continue (CI) terminée, nous définirons l’état de la demande de tirage en conséquence.
  • Une fois la demande de tirage fusionnée, nous exécuterons 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, puis apprenez à l’utiliser. Cet outil est très utile pour exposer des applications locales sur Internet.

Remarque : Vous pouvez également utiliser le transfert de webhook pour configurer votre environnement local afin de recevoir des webhooks. Pour plus d’informations, consultez « Utilisation de l'interface CLI GitHub pour transférer des webhooks à des fins de test ».

Remarque : Vous pouvez télécharger le code source complet de ce projet à partir du dépôt platform-samples.

Écriture de votre serveur

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

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.)

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 fois qu’une demande de tirage est créée ou fusionnée.

Créez un dépôt dans lequel vous vous sentez à l’aise pour travailler. Pourquoi pas le dépôt De Spoon/Knife d’@octocat ?

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 que GitHub enverra à notre serveur chaque fois que l’action appropriée se produira. Nous allons maintenant configurer notre serveur pour simplement gérer le moment où les demandes de tirage sont fusionnées :

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 envoyé par GitHub est accompagné d’un en-tête HTTP X-GitHub-Event. Pour l’instant, nous allons uniquement nous occuper des événements de demande de tirage. Lors de la fusion d’une demande de tirage (son état est closed, et merged est true), nous lançons un déploiement.

Pour tester cette preuve de concept, modifiez une branche dans votre dépôt de test, ouvrez une demande de tirage et fusionnez-la. Votre serveur doit répondre en conséquence !

Utilisation des déploiements

Avec notre serveur en place, le code en cours de révision et notre demande de tirage 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 :

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 :

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.

Lors de la création d’un déploiement, un événement complètement 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 :

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 :

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 à simuler le travail en cours. 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 utilisons une version de Heaven pour gérer nos déploiements depuis des années. 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 réussissent, fusionnez la demande de tirage
  • Heaven prend le code fusionné et le déploie sur des serveurs intermédiaires et de production
  • Entre-temps, Heaven informe également tout le monde de la build, via la présence de 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 les intégrations GitHub.