Catégories
Astuces et Design

Création d'un flux de travail de test d'intégration continue à l'aide d'actions GitHub – Smashing Magazine

A propos de l'auteur

Fiyinfoluwa Akinsiku est un développeur backend issu d'une formation en microbiologie. Elle est continuellement étonnée des nombreuses façons dont la technologie fait la vie…
Plus à propos
Fiyinfoluwa

À l'aide de ce didacticiel, vous pouvez apprendre à créer un flux de travail d'intégration continue pour votre API REST Node JS à l'aide des actions GitHub, ainsi qu'à signaler la couverture de test avec des combinaisons.

Lors de la contribution à des projets sur des plates-formes de contrôle de version telles que GitHub et Bitbucket, la convention est qu'il existe la branche principale contenant la base de code fonctionnelle. Ensuite, il existe d'autres branches dans lesquelles plusieurs développeurs peuvent travailler sur des copies du main pour soit ajouter une nouvelle fonctionnalité, corriger un bogue, etc. Cela a beaucoup de sens car il devient plus facile de surveiller le type d'effet que les modifications entrantes auront sur le code existant. S'il y a une erreur, elle peut facilement être tracée et corrigée avant d'intégrer les modifications dans la branche principale. Il peut être long de parcourir chaque ligne de code manuellement à la recherche d'erreurs ou de bogues, même pour un petit projet. C'est là qu'intervient l'intégration continue.

Qu'est-ce que l'intégration continue (CI)?

«L'intégration continue (CI) consiste à automatiser l'intégration des modifications de code de plusieurs contributeurs dans un seul projet logiciel.»

– Atlassian.com

L'idée générale derrière l'intégration continue (CI) est de s'assurer que les modifications apportées au projet ne «brisent pas la construction», c'est-à-dire ruinent la base de code existante. La mise en œuvre d'une intégration continue dans votre projet, en fonction de la configuration de votre flux de travail, créerait une compilation chaque fois que quelqu'un apporterait des modifications au référentiel.

Alors, qu'est-ce qu'une construction?

Une construction – dans ce contexte – est la compilation du code source dans un format exécutable. Si cela réussit, cela signifie que les modifications entrantes n'auront pas d'impact négatif sur la base de code et qu'elles sont prêtes à fonctionner. Cependant, si la génération échoue, les modifications devront être réévaluées. C'est pourquoi il est conseillé d'apporter des modifications à un projet en travaillant sur une copie du projet sur une branche différente avant de l'incorporer dans la base de code principale. De cette façon, si la construction échoue, il sera plus facile de déterminer d'où vient l'erreur, et cela n'affecte pas non plus votre code source principal.

«Plus vous détectez les défauts tôt, moins ils sont à réparer.»

– David Farley, livraison continue: versions de logiciels fiables grâce à l'automatisation de la construction, des tests et du déploiement

Il existe plusieurs outils disponibles pour vous aider à créer une intégration continue pour votre projet. Il s'agit notamment de Jenkins, TravisCI, CircleCI, GitLab CI, GitHub Actions, etc. Pour ce tutoriel, je vais utiliser les actions GitHub.

Actions GitHub pour une intégration continue

CI Actions est une fonctionnalité relativement nouvelle sur GitHub et permet la création de flux de travail qui exécutent automatiquement la compilation et les tests de votre projet. Un flux de travail contient un ou plusieurs travaux qui peuvent être activés lorsqu'un événement se produit. Cet événement peut être une poussée vers l'une des branches du dépôt ou la création d'une pull request. J'expliquerai ces termes en détail au fur et à mesure que nous avancerons.

Commençons!

Conditions préalables

Ceci est un tutoriel pour les débutants, donc je parlerai principalement de GitHub Actions CI au niveau de la surface. Les lecteurs doivent déjà être familiarisés avec la création d'une API REST Node JS à l'aide de la base de données PostgreSQL, Sequelize ORM et l'écriture de tests avec Mocha et Chai.

Vous devriez également avoir les éléments suivants installés sur votre machine:

  • NodeJS,
  • PostgreSQL,
  • NPM,
  • VSCode (ou tout éditeur et terminal de votre choix).

Je vais utiliser une API REST que j'ai déjà créée appelée countries-info-api. Il s'agit d'une simple API sans autorisations basées sur les rôles (comme au moment de la rédaction de ce didacticiel). Cela signifie que n'importe qui peut ajouter, supprimer et / ou mettre à jour les détails d'un pays. Chaque pays aura un identifiant (UUID généré automatiquement), un nom, une capitale et une population. Pour y parvenir, j'ai utilisé Node js, express js framework et Postgresql pour la base de données.

Je vais expliquer brièvement comment j'ai configuré le serveur, la base de données avant de commencer à écrire les tests pour la couverture des tests et le fichier de flux de travail pour l'intégration continue.

Vous pouvez cloner le countries-info-api repo pour suivre ou créer votre propre API.

Technologie utilisée: Node Js, NPM (un gestionnaire de packages pour Javascript), base de données Postgresql, sequelize ORM, Babel.

Configuration du serveur

Avant de configurer le serveur, j'ai installé des dépendances à partir de npm.

npm install express dotenv cors

npm install --save-dev @babel/core @babel/cli @babel/preset-env nodemon

J'utilise le framework express et j'écris au format ES6, donc j'ai besoin de Babeljs pour compiler mon code. Vous pouvez lire la documentation officielle pour en savoir plus sur son fonctionnement et comment le configurer pour votre projet. Nodemon détectera toutes les modifications apportées au code et redémarrera automatiquement le serveur.

Remarque: Packages Npm installés à l'aide de --save-dev flag ne sont requis que pendant les étapes de développement et sont visibles sous devDependencies dans le package.json fichier.

J'ai ajouté ce qui suit à mon index.js fichier:

import express from "express";
import bodyParser from "body-parser";
import cors from "cors";
import "dotenv/config";

const app = express();
const port = process.env.PORT;

app.use(bodyParser.json());

app.use(bodyParser.urlencoded({ extended: true }));

app.use(cors());

app.get("/", (req, res) => {
    res.send({message: "Welcome to the homepage!"})
})

app.listen(port, () => {
    console.log(`Server is running on ${port}...`)
})

Cela configure notre API pour qu'elle s'exécute sur tout ce qui est assigné au PORT variable dans le .env fichier. C'est également là que nous déclarerons des variables auxquelles nous ne voulons pas que les autres aient facilement accès. le dotenv Le package npm charge nos variables d'environnement depuis .env.

Maintenant quand je cours npm run start dans mon terminal, je reçois ceci:

Serveur en cours d'exécution
Serveur opérationnel sur le port 3000. (Grand aperçu)

Comme vous pouvez le voir, notre serveur est opérationnel. Yay!

Ce lien http://127.0.0.1:your_port_number/ dans votre navigateur Web doit renvoyer le message de bienvenue. Autrement dit, tant que le serveur est en cours d'exécution.

Navigateur
Page d'accueil. (Grand aperçu)
Ensuite, base de données et modèles.

J'ai créé le modèle de pays en utilisant Sequelize et je me suis connecté à ma base de données Postgres. Sequelize est un ORM pour Nodejs. Un avantage majeur est qu'il nous fait gagner du temps lors de l'écriture de requêtes SQL brutes.

Puisque nous utilisons Postgresql, la base de données peut être créée via la ligne de commande psql en utilisant le CREATE DATABASE database_name commander. Cela peut également être fait sur votre terminal, mais je préfère PSQL Shell.

Dans le fichier env, nous allons configurer la chaîne de connexion de notre base de données, en suivant ce format ci-dessous.

TEST_DATABASE_URL = postgres://:@127.0.0.1:5432/

Pour mon modèle, j'ai suivi ce tutoriel de séquelle. Il est facile à suivre et explique tout sur la configuration de Sequelize.

Ensuite, j'écrirai des tests pour le modèle que je viens de créer et configurerai la couverture sur Coverall.

Rédaction de tests et couverture de rapports

Pourquoi écrire des tests? Personnellement, je pense que la rédaction de tests vous aide en tant que développeur à mieux comprendre comment votre logiciel est censé fonctionner entre les mains de votre utilisateur car il s'agit d'un processus de brainstorming. Cela vous aide également à découvrir les bogues à temps.

Tests:

Il existe différentes méthodes de test logiciel, cependant, pour ce tutoriel, j'ai utilisé des tests unitaires et de bout en bout.

J'ai écrit mes tests en utilisant le framework de test Mocha et la bibliothèque d'assertions Chai. J'ai aussi installé sequelize-test-helpers pour aider à tester le modèle que j'ai créé en utilisant sequelize.define.

Couverture de test:

Il est conseillé de vérifier votre couverture de test car le résultat montre si nos cas de test couvrent réellement le code et aussi combien de code est utilisé lorsque nous exécutons nos cas de test.

J'ai utilisé Istanbul (un outil de couverture de test), nyc (client CLI d'Instabul) et Combinaisons.

Selon la documentation, Istanbul instruments votre code JavaScript ES5 et ES2015 + avec des compteurs de ligne, afin que vous puissiez suivre dans quelle mesure vos tests unitaires exercent votre base de code.

Dans mon package.json fichier, le script de test exécute les tests et génère un rapport.

{
    "scripts": {
        "test": "nyc --reporter=lcov --reporter=text mocha -r @babel/register ./src/test/index.js"
    }
}

Dans le processus, il créera un .nyc_output dossier contenant les informations de couverture brutes et un coverage dossier contenant les fichiers du rapport de couverture. Les deux fichiers ne sont pas nécessaires sur mon dépôt, je les ai donc placés dans le .gitignore fichier.

Maintenant que nous avons généré un rapport, nous devons l'envoyer à Coveralls. Une chose intéressante à propos de Combinaisons (et d'autres outils de couverture, je suppose) est la façon dont elle rapporte votre couverture de test. La couverture est ventilée fichier par fichier et vous pouvez voir la couverture pertinente, les lignes couvertes et manquées, et ce qui a changé dans la couverture de construction.

Pour commencer, installez le package combinaison npm. Vous devez également vous connecter à une combinaison et y ajouter le dépôt.

combinaison repo
Repo connecté à Coveralls. (Grand aperçu)

Ensuite, configurez des combinaisons pour votre projet javascript en créant un coveralls.yml fichier dans votre répertoire racine. Ce fichier contiendra votre repo-token obtenu à partir de la section des paramètres de votre repo sur les combinaisons.

Les scripts de couverture sont un autre script nécessaire dans le fichier package.json. Ce script sera utile lorsque nous créerons une construction via Actions.

{
    "scripts": {
        "coverage": "nyc npm run test && nyc report --reporter=text-lcov --reporter=lcov | node ./node_modules/coveralls/bin/coveralls.js --verbose"
    }
}

Fondamentalement, il exécute les tests, obtient le rapport et l'envoie à une combinaison pour analyse.

Passons maintenant au point principal de ce tutoriel.

Créer un fichier de flux de travail JS de nœud

À ce stade, nous avons configuré les tâches nécessaires que nous exécuterons dans notre action GitHub. (Vous vous demandez ce que signifient «emplois»? Continuez à lire.)

GitHub a facilité la création du fichier de workflow en fournissant un modèle de démarrage. Comme indiqué sur la page Actions, il existe plusieurs modèles de flux de travail ayant des objectifs différents. Pour ce tutoriel, nous utiliserons le flux de travail Node.js (que GitHub a déjà gentiment suggéré).

Page Actions
Page Actions GitHub. (Grand aperçu)

Vous pouvez modifier le fichier directement sur GitHub mais je créerai manuellement le fichier sur mon dépôt local. Le dossier .github/workflows contenant le node.js.yml Le fichier sera dans le répertoire racine.

Ce fichier contient déjà quelques commandes de base et le premier commentaire explique ce qu'elles font.

# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node

Je vais y apporter quelques modifications afin qu'en plus du commentaire ci-dessus, il exécute également une couverture.

ma .node.js.yml fichier:

name: NodeJS CI
on: ("push")
jobs:
  build:
    name: Build
    runs-on: windows-latest
    strategy:
      matrix:
        node-version: (12.x, 14.x)
          
    steps:
    - uses: actions/checkout@v2
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v1
      with:
        node-version: ${{ matrix.node-version }}
    - run: npm install
    - run: npm run build --if-present
    - run: npm run coverage

    - name: Coveralls
      uses: coverallsapp/github-action@master
      env:
        COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
        COVERALLS_GIT_BRANCH: ${{ github.ref }}
      with:
        github-token: ${{ secrets.GITHUB_TOKEN }}
      

Qu'est-ce que ça veut dire?

Décomposons-le.

  • name
    Ce serait le nom de votre workflow (NodeJS CI) ou de votre travail (build) et GitHub l'affichera sur la page d'actions de votre référentiel.
  • on
    C'est l'événement qui déclenche le workflow. Cette ligne dans mon fichier indique essentiellement à GitHub de déclencher le flux de travail chaque fois qu'une poussée est effectuée dans mon dépôt.
  • jobs
    Un flux de travail peut contenir au moins un ou plusieurs travaux et chaque travail s'exécute dans un environnement spécifié par runs-on. Dans l'exemple de fichier ci-dessus, il n'y a qu'un seul travail qui exécute la génération et exécute également la couverture, et il s'exécute dans un environnement Windows. Je peux également le séparer en deux emplois différents comme celui-ci:

Fichier Node.yml mis à jour

name: NodeJS CI
on: (push)
jobs:
  build:
    name: Build
    runs-on: windows-latest
    strategy:
      matrix:
        node-version: (12.x, 14.x)
          
    steps:
    - uses: actions/checkout@v2
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v1
      with:
        node-version: ${{ matrix.node-version }}
    - run: npm install
    - run: npm run build --if-present
    - run: npm run test

  coverage:
    name: Coveralls
    runs-on: windows-latest
    strategy:
      matrix:
        node-version: (12.x, 14.x)
          
    steps:
    - uses: coverallsapp/github-action@master
      env:
        COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
      with:
        github-token: ${{ secrets.GITHUB_TOKEN }}
  • env
    Celui-ci contient les variables d'environnement disponibles pour tous les travaux ou étapes spécifiques du flux de travail. Dans la tâche de couverture, vous pouvez voir que les variables d'environnement ont été «masquées». Ils se trouvent dans la page des secrets de votre dépôt sous les paramètres.
  • steps
    Il s'agit essentiellement d'une liste des étapes à suivre lors de l'exécution de ce travail.
  • le build travail fait un certain nombre de choses:
    • Il utilise une action d'extraction (v2 signifie la version) qui extrait littéralement votre référentiel afin qu'il soit accessible par votre flux de travail;
    • Il utilise une action de configuration de nœud qui configure l'environnement de nœud à utiliser;
    • Il exécute les scripts d'installation, de construction et de test trouvés dans notre fichier package.json.
  • coverage
    Cela utilise une action d'application de combinaison qui publie les données de couverture LCOV de votre suite de tests sur coveralls.io pour analyse.
emplois réussis
Tous les travaux s'exécutent avec succès. (Grand aperçu)

J'ai d'abord poussé mon feat-add-controllers-and-route branche et j'ai oublié d'ajouter le repo_token de Coveralls à mon .coveralls.yml fichier, j'ai donc l'erreur que vous pouvez voir à la ligne 132.

Échec de la construction
Echec du travail en raison d'une erreur dans le fichier de configuration des combinaisons. (Grand aperçu)
Bad response: 422 {"message":"Couldn’t find a repository matching this job.","error":true}

Une fois que j'ai ajouté le repo_token, ma construction a pu s'exécuter avec succès. Sans ce jeton, les combinaisons ne seraient pas en mesure de rapporter correctement mon analyse de couverture de test. Heureusement, notre CI Actions GitHub a signalé l'erreur avant qu'elle ne soit poussée vers la branche principale.

Construction réussie
Erreur corrigée, travail réussi. Yay! (Grand aperçu)

N.B: Celles-ci ont été prises avant que je sépare le travail en deux emplois. De plus, j'ai pu voir le résumé de la couverture et le message d'erreur sur mon terminal car j'ai ajouté le --verbose drapeau à la fin de mon script de couverture

Conclusion

Nous pouvons voir comment mettre en place une intégration continue pour nos projets et également intégrer la couverture de test à l'aide des Actions mises à disposition par GitHub. Il existe de nombreuses autres façons de l'ajuster pour répondre aux besoins de votre projet. Bien que l'exemple de dépôt utilisé dans ce didacticiel soit un projet vraiment mineur, vous pouvez voir à quel point l'intégration continue est essentielle, même dans un projet plus important. Maintenant que mes travaux se sont déroulés avec succès, je suis convaincu de fusionner la succursale avec ma succursale principale. Je vous conseillerais toujours de lire également les résultats des étapes après chaque exécution pour voir que c'est complètement réussi.

Éditorial fracassant(ra, yk, il)

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *