Git
Chapters ▾ 2nd Edition

6.5 GitHub - Écriture de scripts pour GitHub

Écriture de scripts pour GitHub

Nous avons pour l’instant traité de toutes les principales fonctionnalités et des cycles de travail de GitHub mais tous les grands groupes ou projets ont des personnalisations qu’ils souhaiteront intégrer ou des services externes qu’ils voudront intégrer.

Heureusement pour nous, il est facile de « bidouiller » GitHub de différentes façons. Dans cette section nous traiterons de la façon d’utiliser le système de crochets (hooks) de GitHub et son interface de programmation (API) afin que GitHub fonctionne de la façon que nous souhaitons.

Crochets (Hooks)

La section « Hooks & Services » (crochets et services) de l’administration de dépôt GitHub est la façon la plus facile de faire interagir GitHub avec des systèmes externes.

Services

Intéressons-nous d’abord aux services. Les intégrations de services et de crochets se trouvent tous les deux dans la section Settings (paramètres) de votre dépôt où nous avions précédemment ajouté des collaborateurs et modifié la branche par défaut de votre projet. La figure Section configuration des crochets et services. vous montre ce que vous verrez en cliquant sur l’onglet « Webhooks and Services ».

Services et crochets
Figure 130. Section configuration des crochets et services.

Vous pouvez choisir parmi des dizaines de services, la plupart sont des intégrations vers d’autres systèmes commerciaux et open source. Certains sont des services d’intégration continue, des analyseurs de bogues et d’anomalies, des systèmes de salon de discussion et des systèmes de documentation. Nous examinerons le paramétrage de l’un d’eux, le crochet Email (courriel). Si vous sélectionnez « email » dans la liste déroulante « Add Service », vous verrez un écran de configuration comme Configuration du service Email..

Service Email
Figure 131. Configuration du service Email.

Dans ce cas, si vous cliquez sur le bouton « Add service » (Ajouter le service), un courriel est envoyé à l’adresse électronique que vous avez indiquée à chaque fois que quelqu’un pousse vers le dépôt. Les services peuvent écouter un grand nombre d’événements de différents types mais la plupart n’écoutent que les événements de poussée puis font quelque chose avec ces données.

Si vous utilisez un système et souhaitez l’intégrer avec GitHub, vous devriez vérifier ici s’il existe déjà un service d’intégration disponible. Par exemple, si vous utilisez Jenkins pour lancer des tests sur votre code, vous pouvez activer l’intégration du service intégré Jenkins pour lancer une série de tests à chaque fois que quelqu’un pousse vers votre dépôt.

Crochets (Hooks)

Si vous avez besoin de quelque chose de plus spécifique ou que vous voulez intégrer un service ou un site qui n’est pas dans la liste, vous pouvez utiliser à la place le système plus général des crochets. Les crochets de dépôt GitHub sont assez simples. Vous indiquez un URL et GitHub envoie (post) des informations par HTTP (payload) vers cet URL pour n’importe quel événement que vous souhaitez.

En général, la façon dont cela fonctionne est que vous configurez un petit service Web qui écoute des informations de crochet GitHub puis font quelque chose avec les données reçues.

Pour activer un crochet, vous cliquez sur le bouton « Add webhook » (Ajouter un crochet Web) de la figure Section configuration des crochets et services.. Cela vous redirige vers une page qui ressemble à Configuration d’un crochet Web..

Crochet Web
Figure 132. Configuration d’un crochet Web.

La configuration d’un crochet Web est assez simple. Dans la plupart des cas, vous saisissez simplement un URL et une clé secrète puis cliquez sur « Add webhook ». Il existe quelques options pour choisir l’événement pour lequel GitHub envoie des informations — par défaut seul l’événement push envoie des informations lorsque quelqu’un pousse un nouveau code vers une branche de votre dépôt.

Examinons un petit exemple de service Web que vous pourriez configurer pour gérer un crochet Web. Nous utiliserons l’architecture Web Ruby appelée Sinatra car c’est assez concis et vous devriez être capable de voir facilement ce que nous faisons.

Disons que vous voulez recevoir un courriel si une personne précise pousse vers une branche spécifique de notre projet un fichier particulier. Nous pourrions faire facilement cela avec le code suivant :

require 'sinatra'
require 'json'
require 'mail'

post '/payload' do
  push = JSON.parse(request.body.read) # parse the JSON

  # gather the data we're looking for
  pusher = push["pusher"]["name"]
  branch = push["ref"]

  # get a list of all the files touched
  files = push["commits"].map do |commit|
    commit['added'] + commit['modified'] + commit['removed']
  end
  files = files.flatten.uniq

  # check for our criteria
  if pusher == 'schacon' &&
     branch == 'ref/heads/special-branch' &&
     files.include?('special-file.txt')

    Mail.deliver do
      from     'tchacon@example.com'
      to       'tchacon@example.com'
      subject  'Scott Changed the File'
      body     "ALARM"
    end
  end
end

Ici nous récupérons les informations JSON que GitHub nous délivre et cherchons qui les a poussées, vers quelle branche et quels fichiers ont été touchés dans tous les commits qui ont été poussés. Puis nous comparons cela à nos critères et envoyons un courriel si cela correspond.

Afin de développer et tester quelque chose comme cela, il existe une console développeur sympa sur la même fenêtre que celle où vous avez activé le crochet. Vous pouvez afficher les quelques dernières livraisons que GitHub a essayé de faire pour ce crochet Web. Pour chaque crochet, vous pouvez afficher plus d’informations pour savoir quand il s’est exécuté, s’il a réussi et pour connaître les en-têtes et le corps de la requête et de la réponse. Ceci rend incroyablement facile de tester et débugger vos crochets.

Webhook debug
Figure 133. informations de debuggage du crochet web

L’autre fonctionnalité intéressante est que vous pouvez redéclencher la livraison de n’importe quel message pour tester votre service.

Pour plus d’information sur l’écriture de crochets web et tous les différents types d’événement que vous pouvez écouter, rendez-vous à la documentation du Developpeur GitHub à l’adresse https://developer.github.com/webhooks/.

L’interface de programmation (API) GitHub

Les services et les crochets vous fournissent un moyen de recevoir des notifications de poussée sur des événements qui arrivent sur vos dépôts, mais que faire si vous avez besoin de plus d’informations sur ces événements ? Que faire si vous avez besoin d’automatiser quelque chose comme ajouter des collaborateurs ou étiqueter des problèmes (issues) ?

C’est là que l’Interface de Programmation (API) GitHub s’avère utile. GitHub a des tas de points d’entrée sur l’interface d’application pour faire presque tout ce que vous pouvez faire sur le site web de façon automatisée. Dans cette section, nous apprendrons comment s’authentifier et se connecter à l’interface de programmation, comment commenter un problème et comment changer le statut d’une requête de tirage (pull request) à travers l’interface de programmation.

Utilisation Basique

La chose la plus basique que vous pouvez faire est une simple requête GET sur une entrée qui ne requiert pas d’authentification. Cela peut être un utilisateur ou une information en lecture seule sur un projet open source. Par exemple, si nous voulons en savoir plus sur un utilisateur appelé « schacon », nous pouvons lancer quelque chose comme ceci :

$ curl https://api.github.com/users/schacon
{
  "login": "schacon",
  "id": 70,
  "avatar_url": "https://avatars.githubusercontent.com/u/70",
# …
  "name": "Scott Chacon",
  "company": "GitHub",
  "following": 19,
  "created_at": "2008-01-27T17:19:28Z",
  "updated_at": "2014-06-10T02:37:23Z"
}

Il y a des tas de points d’entrée comme celui-ci pour obtenir des informations sur des regroupements, projets, problèmes, commits — en fait tout ce que vous pouvez voir sur le site de GitHub. Vous pouvez même utiliser l’interface de programmation pour écrire du texte en Markdown ou trouver un modèle .gitignore.

$ curl https://api.github.com/gitignore/templates/Java
{
  "name": "Java",
  "source": "*.class

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.ear

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
"
}

Commenter un problème

Cependant, si vous voulez faire une action sur le site web comme commenter un problème ou une requête de tirage ou si vous voulez voir ou interagir avec du contenu privé, vous aurez besoin de vous authentifier.

Il y a plusieurs moyens de s’authentifier. Vous pouvez utiliser l’authentification basique avec seulement votre nom d’utilisateur et votre mot de passe, mais en général c’est mieux d’utiliser un jeton d’accès personnel. Vous pouvez en générer depuis l’onglet « Applications » de votre page de paramètres.

Access Token
Figure 134. Générez votre jeton d’accès depuis l’onglet « Applications » de votre page de paramètres.

On vous demandera le périmètre applicatif que vous voulez pour ce jeton ainsi qu’une description. Assurez-vous d’utiliser une bonne description pour être certain de supprimer le bon jeton quand votre script ou application ne sera plus utilisé.

GitHub ne vous montrera le jeton qu’une seule fois, alors assurez-vous de le copier. Vous pouvez maintenant l’utiliser pour vous authentifier dans votre script au lieu d’utiliser un nom d’utilisateur et un mot de passe. C’est agréable parce que vous pouvez limiter la portée de ce que vous voulez faire et le jeton est révocable.

Ceci a l’avantage supplémentaire d’augmenter votre limite horaire du nombre d’accès. Sans authentification, vous serez limité à 60 requêtes par heure. Avec authentification, vous pouvez faire jusqu’à 5 000 requêtes par heure.

Maintenant utilisons-le pour faire un commentaire sur un de nos problèmes. Disons que nous voulons laisser un commentaire sur un problème en particulier, le problème n°6. Pour faire cela, nous devons faire une requête HTTP POST à repos/<utilisateur>/<dépôt>/issues/<num>/comments avec le jeton que nous venons de générer en tant qu’en-tête "Authorization".

$ curl -H "Content-Type: application/json" \
       -H "Authorization: token TOKEN" \
       --data '{"body":"A new comment, :+1:"}' \
       https://api.github.com/repos/schacon/blink/issues/6/comments
{
  "id": 58322100,
  "html_url": "https://github.com/schacon/blink/issues/6#issuecomment-58322100",
  ...
  "user": {
    "login": "tonychacon",
    "id": 7874698,
    "avatar_url": "https://avatars.githubusercontent.com/u/7874698?v=2",
    "type": "User",
  },
  "created_at": "2014-10-08T07:48:19Z",
  "updated_at": "2014-10-08T07:48:19Z",
  "body": "A new comment, :+1:"
}

Maintenant si vous allez à ce problème, vous pouvez voir le commentaire que nous avons posté avec succès comme dans Un commentaire posté depuis l’interface de programmation GitHub.

API Comment
Figure 135. Un commentaire posté depuis l’interface de programmation GitHub

Vous pouvez utiliser l’interface de programmation pour faire à peu près tout ce que vous pouvez faire sur le site web — créer et définir des jalons, assigner des gens à des problèmes ou à des requêtes de tirage, créer et changer des étiquettes, accéder à des données de commit, créer de nouveaux commits et des branches, ouvrir, fermer ou fusionner des requêtes de tirage, créer et éditer des équipes, commenter des lignes de code dans une requête de tirage, chercher dans le site et bien plus encore.

Changer le statut d’une requête de tirage

Nous allons voir un dernier exemple très utile si vous travaillez avec des requêtes de tirage. Chaque commit peut avoir un ou plusieurs statuts associés et il y a une interface de programmation pour ajouter et demander ce statut.

La plupart des services d’Intégration Continue et de test utilisent cette interface de programmation pour réagir aux poussées en testant le code qui a été poussé, et en signalant si ce commit a passé tous les tests. Vous pourriez aussi utiliser ceci pour vérifier que le message de validation est formaté proprement, si l’auteur a suivi les recommandations de contribution, si la signature du commit est valide — vous pouvez faire autant de choses que vous le souhaitez.

Supposons que vous souhaitez définir un crochet web sur votre dépôt qui atteint un petit service web qui vérifie que le message de validation contient la chaîne Signed-off-by.

require 'httparty'
require 'sinatra'
require 'json'

post '/payload' do
  push = JSON.parse(request.body.read) # parse the JSON
  repo_name = push['repository']['full_name']

  # examine chaque message de validation
  push["commits"].each do |commit|

    # cherche la chaîne "Signed-off-by"
    if /Signed-off-by/.match commit['message']
      state = 'success'
      description = 'Successfully signed off!'
    else
      state = 'failure'
      description = 'No signoff found.'
    end

    # envoie le statut à GitHub
    sha = commit["id"]
    status_url = "https://api.github.com/repos/#{repo_name}/statuses/#{sha}"

    status = {
      "state"       => state,
      "description" => description,
      "target_url"  => "http://example.com/how-to-signoff",
      "context"     => "validate/signoff"
    }
    HTTParty.post(status_url,
      :body => status.to_json,
      :headers => {
        'Content-Type'  => 'application/json',
        'User-Agent'    => 'tonychacon/signoff',
        'Authorization' => "token #{ENV['TOKEN']}" }
    )
  end
end

Ça devrait être simple à suivre. Dans ce crochet web, nous examinons chaque commit qui vient d’être poussé, nous cherchons la chaîne "Signed-off-by" dans le message de validation et enfin nous faisons un POST via HTTP au point d’entrée applicatif /repos/<utilisateur>/<dépôt>/statuses/<commit_sha> avec le statut.

Dans ce cas, vous pouvez envoyer un état ("success", "failure", "error"), une description de ce qui s’est passé, un URL cible où l’utilisateur peut aller pour plus d’informations et un « contexte » dans le cas où il y a de multiples statuts pour un seul commit. Par exemple, un service de test peut fournir un statut et un service de validation comme celui-ci peut aussi fournir un statut — le champ « contexte » permet de les différencier.

Si quelqu’un ouvre une nouvelle requête de tirage sur GitHub et que ce crochet est opérationnel, vous pouvez voir quelque chose comme Statut de commit via l’interface de programmation..

Commit status
Figure 136. Statut de commit via l’interface de programmation.

Vous pouvez voir maintenant une petite coche verte près du commit qui contient la chaîne « Signed-off-by » dans le message et une croix rouge pour celui que l’auteur à oublié de signer. Vous pouvez aussi voir que la requête de tirage prend le statut du dernier commit de la branche et avertit si c’est un échec. C’est très utile si vous utilisez cette interface de programmation pour des résultats de test pour que vous ne fusionniez pas accidentellement quelque chose où le dernier commit échoue aux tests.

Octokit

Bien que nous ayons presque tout fait à travers curl et de simples requêtes HTTP dans ces exemples, il existe plusieurs bibliothèques open source qui rendent cette interface de programmation plus idiomatique. Au moment de la rédaction de ce document, les langages supportés incluent Python, Go, Objective-C, Ruby et .NET. Consultez http://github.com/octokit pour plus d’informations à ce propos, puisqu’ils gèrent une bonne partie de HTTP pour vous.

Heureusement ces outils devraient vous aider à personnaliser et modifier GitHub pour travailler mieux suivant vos méthodes de travail spécifiques. Pour une documentation complète de l’ensemble de l’interface de programmation ainsi que pour des guides pour les tâches habituelles, consultez https://developer.github.com.