David Hockley

GitHub Actions + release-it : Comment automatiser la mise en production

...sans devenir chèvre

Coder, c'est bien. Mais, inexorablement, vient le moment où il faut compiler le code produit et diffuser le résultat final dans la nature.

Au début, c’est simple à gérer.

Mais au fur et à mesure que votre projet se développe, la complexité de la mise en production de votre code augmente. Plus il y a d’étapes, et en particulier d’étapes manuelles, plus il y a de chance que quelque chose coince.

Par exemple, au travail, on utilise une stack PHP qui intègre des applications React. Du coup, pour faire une mise en production d'une nouvelle version on a 7 ou 8 étapes à passer. Y compris par exemple la récupération des traductions depuis l’outil en ligne, la compilation du React, etc.

Et si on oublie une de ces étapes, tout risque de planter. J'ai perdu des heures à essayer de me rappeler ce qu'il fallait faire et comment résoudre le problème qui perturbait le processus de déploiement.

Et c’est encore pire quand on tente de se rappeler comment mettre à jour un projet sur lequel on n'a pas travaillé depuis trois mois.

Du coup, quelle est la solution ?

En principe, la solution est simple : automatiser tout ce qui peut l'être.

Et j'ai de bonnes nouvelles pour vous : il existe un outil puissant qui vous permet d'automatiser beaucoup de choses. Il s'agit de GitHub Actions.

Mais c'est intimidant, donc aujourd'hui, nous allons regarder :

  • comment utiliser release-it et auto-changelog pour scripter votre processus de publication.
  • comment configurer les actions GitHub pour automatiser tout ça

Publication d'un module NPM à l'aide de release-it

Tout d'abord, voyons comment déployer notre code. Je vais travailler sur une version simplifiée, en utilisant un module NPM que j'ai créé.

Alors: Un mot d'avertissement avant d'aller plus loin.

La publication de modules NPM avec GitHub Actions est beaucoup plus compliquée si vous utilisez yarn au lieu de npm.

Je vous recommande de lancer git rm sur le fichier yarn.lock et de n’utiliser que npm. (C’est possible d'utiliser yarn, mais c'est un peu plus compliqué).

Maintenant, il y a cinq étapes que j'utilise chaque fois que je mets à jour mon paquetage npm.

  1. Je m'assure que mon code est à jour (avec git pull).
  2. Je m'assure que le code est propre en exécutant des tests unitaires (avec Jest ) et en “lintant” (avec ESLint).
  3. Je prépare un changelog qui liste tous les changements depuis la dernière version.
  4. Ensuite, je fixe le nouveau numéro de version.
  5. Enfin, je “committe” et publie le tout, à la fois comme une version sur GitHub et comme un paquet sur NPM.

Une petite astuce ici : Chaque fois que j'automatise quelque chose, je commence par créer un fichier script local qui exécute toutes les étapes de manière séquentielle.

Ainsi, par exemple, pour pousser du code, j'ai tendance à créer un fichier bash appelé "up.sh" qui se trouve à la racine de mon projet et exécute toutes les tâches.

Mais je suis tombé sur un outil qui couvre tous mes besoins de publication et même plus.

release-it : pour automatiser la publication

Il s'agit d'un outil NPM appelé release-it, et je l'utilise maintenant dans presque tous mes projets. Permettez-moi de vous montrer comment il fonctionne.

Tout d'abord, pour le configurer, nous exécutons :

npm init release-it

L'outil pose quelques questions. Il stocke sa configuration soit dans le package.json, soit dans un fichier séparé appelé .release-it.json.

Personnellement, je préfère opter pour la seconde solution, car mes fichiers package.json contiennent généralement déjà beaucoup de choses.

Parmi les cinq étapes que j'ai mentionnées, l'une d'entre elles est le suivi et la mise à jour du numéro de version. Ceci est déjà intégré dans l'outil release-it. Une étape est faite, il en reste quatre.

Par défaut, release-it refuse également de faire quoi que ce soit si le dépôt git n'est pas dans un état propre. Par exemple, s'il y a un travail non enregistré en cours. Donc c'est déjà pris en charge par défaut.

La prochaine étape est de s'assurer que nous ne mettons en production que la branche git qui est réellement destinée à l’être. Pour cela, nous ajoutons une contrainte dans le fichier de configuration (.release-it.json).

On crée une section dédiée à git, et on ajoute un champ requireBranch en spécifiant la branche main.

C'est assez explicite : Il ne faut s’exécuter qu’à condition d’être sur la branche "main".

Pendant que nous sommes ici, nous pouvons également spécifier le message de commit qui sera créé en libérant le paquet, et on peut include le numero de version en

Maintenant, les prochaines étapes sont de s'assurer que mon code est à jour, et de le tester. J'ai déjà configuré des tests dans mon projet en utilisant Jest et EsLint, et je les exécute en utilisant "npm run test" et "npm run lint".

Je veux qu'ils soient exécutés au début, avant que quoi que ce soit ne se produise, donc j'utilise un hook du cycle de vie de release-it, et il y en a pas mal. Ainsi, dans mon fichier de configuration pour release-it, j'ai maintenant une liste de trois éléments dans le hook “before:init“: git pull, rpm run lint et rpm run test.

Tout ceci est également assez explicite. Nous avons défini un hook pour release-it qui s'exécute avant de se mettre au travail, et qui met à jour le code avec git pull. Ensuite, il vérifie les erreurs de linting avec npm run lint et exécute les tests unitaires avec npm run test.

Une dernière chose que j'aime faire est d'ajouter un changelog ; pour lister tout ce que nous avons fait entre les versions. Mais les commits que nous avons écrits indiquent déjà ce que nous avons fait, donc nous pouvons aussi automatiser cela. Et pour ce faire, nous allons utiliser un outil appelé auto-changelog. Pour le déclencher, nous allons utiliser un autre hook appelé after:bump. Comme son nom l'indique, il est exécuté une fois que le numéro de version a été augmenté.

Et on appelle donc “npx auto-changelog”. Et nous indiquons l’option -p pour indiquer à l'outil que le numéro de version est stocké dans le fichier package.json.

Cela créera un fichier changelog en markdown utilisant les données de commit, et créera l'info sur la version. Enfin, nous spécifions que nous voulons publier le code sur GitHub et le publier sur NPM, en rajoutant la mention “release: true” dans chacune des sections correspondantes.

Maintenant on va tester tout ça. Si vous regardez votre fichier package.json, l'init devrait avoir ajouté une entrée release dans la section scripts :

Ca nous permet d'exécuter “npm run release” pour déclencher le processus de publication.

Lorsque nous le faisons, une série de questions nous est posée : voulons-nous définir cela comme une mise à jour mineure, une mise à jour majeure ou un changement de rupture ? Voulons-nous publier ? Et tout un tas d’autres questions. Tout ça nous permet d'exécuter le processus et de vérifier ce qui se passe, et de spécifier chaque étape s’il y a des particularités.

Et une fois que tout fonctionne comme vous le souhaitez, il est temps de ... l'automatiser encore plus !

Pour cela, nous allons utiliser les actions GitHub. Maintenant, c’est quoi les actions GitHub, et comment fonctionnent-elles ?

Imaginez que vous êtes dans une entreprise et qu'un nouveau développeur rejoint votre équipe. Qu’est-ce que vous faites ?

Eh bien, d'abord vous lui achetez un nouvel ordinateur, puis vous l'aidez à télécharger le code, à tout installer et à se mettre au travail.

Dans un sens, GitHub Actions fait la même chose. Il configure un conteneur avec un système d'exploitation. Ensuite, il télécharge des logiciels et une version actuelle de notre code. Et enfin, il exécute un ensemble de tâches...

On va guider le workflow dans ce processus. Pour ça, on va créer un dossier appelé .github. Dans ce dossier, nous créons un autre dossier appelé workflows. Et dans ce dossier, nous créons un fichier appelé release.yml. Il y a trois champs obligatoires : name, on et jobs. Ils définissent le nom du flux de travail, le moment où il est déclenché et les actions qu'il entreprend. Dans notre cas, le flux de travail va s'appeler "Release & Publish to NPM", nous remplissons donc le nom en conséquence. Et il sera déclenché manuellement, donc nous définissons le champ "on" à : "workflow_dispatch". (Nous pouvons ajouter plusieurs déclencheurs différents ici, et les configurer, mais dans notre cas, nous n'en avons pas besoin). Notre fichier de configuration de la version ressemble maintenant à ceci :

nom : Release & Publish to NPM
on : workflow_dispatch

Maintenant, la partie amusante, le champ jobs ! Il définit une liste de tâches qui peuvent être exécutées, et chaque tâche est une liste d'étapes. Notre premier (et unique) job va s'appeler release, et maintenant nous devons le configurer ! Nous commençons par spécifier le système d'exploitation que nous voulons exécuter en utilisant le paramètre "runs-on". Ici, j'ai spécifié ubuntu. Et maintenant nous définissons la liste des étapes. Nous allons commencer simplement, juste pour tester les choses. La première chose que nous faisons est de récupérer le code, et pour cela, nous allons utiliser une action pré-packagée appelée "actions/checkout@v2". Celle-ci a été créée par GitHub, et il existe de nombreuses actions disponibles pour de nombreux cas d'utilisation différents. Dans la deuxième étape, nous installons les dépendances, et pour cela, nous spécifions simplement dans l'étape la commande que nous souhaitons exécuter. Ici, nous avons donc l'action execute npm ci (qui exécute une installation propre). Enfin, nous enregistrons que le travail est terminé, et de la même manière, nous exécutons simplement une commande "echo".

jobs :
  release :
    fonctionne sur : ubuntu-20.04
    stages :
      - name : Vérifier le code source
        utilisations : actions/checkout@v2
      - nom : Installer les dépendances
        exécute : npm ci
      - nom : Message de fin
        run : echo 'All done !

Commençons par tester tout cela. Pour ce faire, nous commettons le fichier de workflow et le poussons vers la branche principale. Comme vous pouvez le voir lorsque vous vous rendez dans le référentiel, il y a un onglet "Actions". Notre flux de travail y est maintenant répertorié. Ici, nous pouvons déclencher le flux de travail manuellement. Pour ce faire, nous cliquons sur le bouton "run workflow" dans l'interface utilisateur. Une fois l'exécution terminée (ou même pendant qu'elle est en cours !), nous pouvons ouvrir les journaux. Nous pouvons voir où en sont les différentes étapes, et s'il y a des erreurs. Configuration de git et NPM L'étape suivante consiste à terminer la configuration de git et npm dans le workflow. Pour ce faire, nous ajoutons une autre étape dans la liste, après l'action de vérification, et nous indiquons l'utilisateur git et l'email que nous voulons utiliser

      - name: Initialize Git user
        run: |
            git config --global user.email "david@kodaps.com"
            git config --global user.name "Release Workflow"

Maintenant, nous devons être en mesure de publier sur NPM sans nous connecter, et pour cela, nous avons besoin d'un jeton "publish". Pour le récupérer, nous devons nous rendre sur le site Web de NPM. Une fois connecté, nous devons sélectionner Access Tokens. Puis, de retour sur GitHub, sur la page du dépôt, nous cliquons sur Paramètres, puis sur Secrets > Actions. Ici nous cliquons sur "New repository secret" et entrons NPM_TOKEN comme nom de secret, et collons la valeur du jeton. Maintenant, nous devons configurer npm pour qu'il utilise le jeton lorsqu'il communique avec le registre NPM. Nous utilisons la commande "npm config set", et nous passons le secret NPM_TOKEN que nous venons de générer.

  • name: Initialise the NPM config
        run: npm config set //registry.npmjs.org/:_authToken $NPM_TOKEN
        env:
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

Maintenant, il y a un problème. La commande crée un fichier .npmrc sur le conteneur. Et ce fichier va bloquer la publication car le répertoire git ne sera plus propre.

Donc allons-y et ajoutons ce fichier au fichier .gitignore :

#.gitignore
node_modules/
.env
.npmrc

Et maintenant pour la version Maintenant, remplaçons le log final par la commande de publication du paquet, en utilisant la commande release et le flag —ci (ici le ci signifie continuous integration, ou intégration continue). Nous devons également fournir deux jetons à l'action. Le premier est le jeton GitHub, et il est fourni par défaut par l'action.

- nom : Run release
        run : npm run release --ci
        env :
          GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN : ${{ secrets.NPM_TOKEN }}

Notre flux de travail final ressemble maintenant à quelque chose comme ceci

##.github/workflows/release.yml
nom : Release & Publish to NPM
on : workflow_dispatch
jobs :
  release :
    fonctionne sur : ubuntu-20.04
    étapes :
    - nom : code source de la caisse
      utilisations : actions/checkout@v2
    - nom : Installer les dépendances
      exécute : npm ci
    - nom : Initialisation de la configuration NPM
      run : npm config set //registry.npmjs.org/:_authToken $NPM_TOKEN
      env :
        NPM_TOKEN : ${{ secrets.NPM_TOKEN }}
    - name : Initialiser l'utilisateur Git
      Exécuter : |
        git config --global user.email "david@kodaps.com"
        git config --global user.name "Flux de travail de validation".
    - nom : Enregistrement de l'état de Git
      Exécuter : git status
    - nom : Run release
      exécuter : npm run release --ci
      env :
        NPM_TOKEN : ${{ secrets.NPM_TOKEN }}
        GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}

En conclusion

Je trouve que la combinaison de release-it et de GitHub Actions est puissante. Ensemble, ils soulagent un de mes problèmes récurrents, que ce soit dans mes projets personnels ou au travail.  Jusqu'à présent, je ne les ai appliquées qu'aux modules NPM et aux sites Web NextJS (bien que j'utilise également les actions GitHub pour mettre automatiquement à jour mon profil), mais j'ai hâte de les utiliser également pour créer et publier des applications mobiles. Et bien sûr, vous pouvez faire beaucoup de choses amusantes comme envoyer des notifications Slack ou Discord, configurer un cron pour déclencher des appels d'API, etc. Faites-moi signe si vous voulez que je vous explique comment faire !

Social
Made by kodaps · All rights reserved.
© 2023