Article original : How to build a GitHub bot with PhantomJS, React, and Serverless framework
Par Pavel Vlasov
Ce tutoriel explique comment construire un bot Serverless simple qui retourne un graphique avec les principaux contributeurs d'un dépôt GitHub pour une période sélectionnée. Il est destiné à ceux qui ont une certaine expérience avec React, JavaScript, TypeScript, Node.js, Amazon Web Services (AWS) et le framework Serverless.
Vous pouvez consulter le code sur GitHub.
Services et outils que nous utiliserons
Avant de plonger dans le codage, faisons un rapide aperçu des services AWS et des outils que nous utiliserons.
Pour récupérer les principaux contributeurs d'un dépôt, nous utiliserons l'API de statistiques de GitHub, l'incroyable Nivo pour afficher les données, Storybook pour vérifier l'apparence de notre graphique, PhantomJS pour transformer du HTML en image, et le framework Serverless pour interagir avec AWS.
Commençons
J'utiliserai TypeScript. Si vous préférez ES6, vous devrez configurer Babel.
Tout d'abord, vous devez créer [tsconfig.json](https://github.com/threadheap/github-stats-bot/blob/master/tsconfig.json) à la racine de votre dépôt. Les options auxquelles il faut prêter attention incluent :
"module": "commonjs","target": "es5","lib": ["es6", "esnext.asynciterable"],"moduleResolution": "node","jsx": "react"
Ensuite, nous créerons une API simple pour interroger les statistiques de GitHub. Vous pouvez suivre la structure de fichiers du dépôt GitHub ou utiliser la vôtre. Par exemple :
Pour accéder à l'API GitHub, vous devrez créer un jeton d'accès personnel.
Ce module envoie simplement la requête avec le jeton fourni et récupère les données.
Affichage des graphiques
Pour afficher les données, nous utiliserons Nivo et Storybook. Un composant simple peut ressembler à ceci :
Tout d'abord, configurez Storybook en exécutant la commande suivante dans le dossier racine :
npm i -g @storybook/cligetstorybook
Copiez le dossier .storybook dans le dépôt racine et remplacez tous les fichiers existants. Il contient la configuration de Webpack et Storybook. Créez un dossier stories et placez-y un exemple de story pour votre composant :
Exécutez npm run storybook et ouvrez localhost dans le navigateur. Vous devriez voir le résultat suivant :

Essayez de jouer avec les options et les données de test. Storybook changera l'apparence immédiatement.
Transformation de HTML en PNG
Habituellement, les systèmes de chat comme Facebook Messenger et Slack ne permettent pas aux utilisateurs d'insérer des cartes HTML dans le dialogue, donc la prochaine étape sera de construire un helper qui rend le HTML en image PNG.
En utilisant un script simple avec la bibliothèque jsdom, nous pouvons imiter le comportement du navigateur et séquentialiser le HTML, comme ceci :
createDomForChart retourne une nouvelle instance de jsdom, et la fonction chart appelle simplement dom.serialize() lorsque le rendu du composant est terminé.
Avec PhantomJS, nous pouvons transformer le balisage en image en utilisant ce script simple :
Nous passons screenshot.js dans le chemin exécutable de phantomjs — ainsi qu'une chaîne HTML, une largeur et une hauteur — et nous obtenons en retour un buffer avec l'image rendue.
Vous pouvez remarquer que j'ai utilisé deux binaires PhantomJS (pour OS X et Linux). Nous aurons besoin de la version Linux plus tard dans un environnement AWS. Vous pouvez les télécharger depuis PhantomJS.org ou utiliser les fichiers du dépôt.
Assemblage de tout
Maintenant, créons une lambda pour gérer les requêtes. Je recommande de mettre la logique de rendu PNG dans un service séparé. Parce que le binaire PhantomJS fait environ 50 Mo, il ralentit le déploiement si vous changez quoi que ce soit dans l'API. De plus, vous pouvez réutiliser cette lambda pour d'autres fins.
Nous commencerons par créer [webpack.config.ts](https://github.com/threadheap/github-stats-bot/blob/master/webpack.dev.ts) (pour bundler le code source) et [serverless.base.js](https://github.com/threadheap/github-stats-bot/blob/master/serverless.base.js) (pour définir la configuration de base serverless) dans le dossier racine.
Si vous voulez en savoir plus sur les cas d'utilisation des configurations JavaScript serverless, vous pouvez lire mon article précédent.
Vous devrez changer les noms des buckets de déploiement et d'images, comme ceci :
deploymentBucket: { name: 'com.github-stats....deploys'},environment: { BUCKET: 'com.github-stats....images', GITHUB_TOKEN: '${env:GITHUB_TOKEN}', SLACK_TOKEN: '${env:SLACK_TOKEN}, STAGE: '${self:provider.stage}'},
C'est parce que le nom du bucket doit être globalement unique.
Transformation de HTML en service PNG
Tout d'abord, nous créerons un handler qui retournera une URL de l'image générée. Le handler doit valider et traiter le corps de la requête :
...et si tout est correct, il doit générer l'image et la mettre dans un bucket S3.
Créons [webpack.config.ts](https://github.com/threadheap/github-stats-bot/blob/master/app/html-to-png/webpack.config.ts) pour bundler les fichiers sources. Nous utiliserons le plugin [copy-webpack-plugin](https://github.com/webpack-contrib/copy-webpack-plugin) et [webpack-permissions-plugin](https://github.com/GeKorm/webpack-permissions-plugin) pour inclure les binaires PhantomJS dans un bundle — et donner des permissions pour l'exécution. Cela nous obligera à exécuter la commande de déploiement avec sudo puisque Webpack n'a pas les permissions de modifier les droits du système de fichiers par défaut.
La dernière étape consistera à utiliser le fichier [serverless.js](https://github.com/threadheap/github-stats-bot/blob/master/app/html-to-png/serverless.js) pour lier notre handler à un événement API Gateway.
Maintenant, nous devons effectuer les mêmes étapes pour le handler de statistiques, mais nous n'avons pas besoin de faire de changements dans webpack.config.ts.
La seule différence est une permission supplémentaire pour invoquer lambda :
iamRoleStatements: [ ...baseConfig.provider.iamRoleStatements,{ Effect: 'Allow', Action: ['lambda:InvokeFunction'], Resource: ['*']}]
Configuration du bot Slack
La dernière étape consistera à créer un service qui gérera les événements de messages pour le bot. Pour garder cela simple, nous gérerons uniquement les événements de mention. Configurons le handler d'événements de base.
Nous devons gérer un événement de vérification de Slack et répondre avec un statut 200 et les paramètres de défi :
callback(null, { body: JSON.stringify({ challenge: (slackEvent as VerificationEvent).challenge }), statusCode: 200});
Pour gérer correctement un événement Slack, le point de terminaison doit répondre dans les 3000 millisecondes (3 secondes), donc nous devrons répondre immédiatement et envoyer un message de suivi de manière asynchrone en utilisant l'API postMessage.
Dans le code ci-dessus, nous avons analysé le texte du message pour extraire un nom de dépôt et appelé une lambda de statistiques d'images pour récupérer une URL d'image et envoyer un message à Slack. Vous pouvez trouver le code complet du handler ici.
Le code pour serverless.js et les configurations Webpack serait similaire au service de statistiques, donc si vous avez des problèmes pour le configurer, consultez le code source complet.
Création d'une application Slack
Maintenant, créons une nouvelle application Slack. Allez sur Slack API, créez un nouveau compte (si vous ne l'avez pas déjà fait), créez une nouvelle application et ajoutez la portée du bot dans la section des portées.
Allez dans la section "OAuth & Permissions" dans la barre latérale.

Ajoutez la portée de l'utilisateur bot.

Ensuite, vous pourrez installer l'application dans votre organisation et obtenir l'accès aux jetons.

Déploiement des services
Vous devrez installer une version du framework serverless supérieure à 1.26 car les versions antérieures ne supportent pas les fichiers de configuration JavaScript. Et je recommande d'installer slx pour simplifier le déploiement de plusieurs services.
npm install -g serverlessnpm install -g serviceless
Copiez les jetons du bot GitHub et Slack, et définissez-les comme variables d'environnement GITHUB_TOKEN et SLACK_TOKEN respectivement. Exécutez la commande suivante dans le terminal :
sudo GITHUB_TOKEN=<votre jeton> SLACK_TOKEN=<votre jeton slack> slx deploy all
Comme mentionné ci-dessus, nous avons besoin de sudo pour définir les permissions d'exécution aux binaires PhantomJS.
Soyez patient ! Le déploiement peut prendre un certain temps. À la fin, vous devriez voir une sortie similaire :
Deployment completed successfuly
[app/html-to-png] [completed]:Service Informationservice: html-to-pngstage: devregion: us-east-1stack: html-to-png-devapi keys: Noneendpoints: Nonefunctions: renderToPng: html-to-png-dev-renderToPngServerless: Removing old service versions...[app/slack] [completed]:Service Informationservice: git-stats-slackstage: devregion: us-east-1stack: git-stats-slack-devapi keys: Noneendpoints: POST - https://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev/stats/slack/event-handlerfunctions: eventHandler: git-stats-slack-dev-eventHandlerServerless: Removing old service versions...[app/stats] [completed]:Service Informationservice: git-statsstage: devregion: us-east-1stack: git-stats-devapi keys: Noneendpoints: GET - https://xxxxxx.execute-api.us-east-1.amazonaws.com/dev/stats/contributors/{owner}/{repo}functions: getContributorStatsImage: git-stats-dev-getContributorStatsImageServerless: Removing old service versions...
La dernière étape consistera à abonner notre point de terminaison aux événements de mention de bot.
Sélectionnez la section "Event Subscription" dans la navigation de l'API Slack.

Ensuite, collez l'URL du handler d'événements que vous pouvez trouver dans la sortie de la commande de déploiement.

Il est temps de s'amuser un peu ! Voici quelques exemples d'images rendues :



C'est tout !
J'espère que vous avez trouvé cet article utile. J'adorerais voir dans les commentaires d'autres types de statistiques que vous aimeriez voir dans le service.
Merci d'applaudir si vous avez aimé l'article ! Et si vous souhaitez discuter ou vous connecter, vous pouvez me trouver sur Twitter, GitHub et Linkedin.