Table des matières
Ouvrir table des matières
Introduction
Quand tu fais du code, tu as énormément de choses à penser et à faire. Certaines d’entre elles sont répétitives.
Imagine automatiser tes tests, tes déploiements, et même tes tâches administratives, le tout depuis le confort de ton propre dépôt GitHub.
Si cela te semble séduisant, tu es au bon endroit !
Je vais te guider pas à pas dans la configuration d’une CI (Continuous Integration) qui couvrira 80% de tes besoins avec un outil gratuit présent sur ton dépôt GitHub : GitHub Actions.
Comprendre GitHub Actions 🤖
GitHub Actions est un système d’automatisation intégré directement dans ton dépôt GitHub.
Le fonctionnement de GitHub Actions est assez simple : en suivant les instructions de ton workflow, un conteneur Docker est provisionné pour exécuter ton action, étape par étape.
Il te permet de créer, tester et déployer ton code dès que tu effectues des changements. Chaque “action” est définie dans un fichier YAML, situé dans le dossier .github/workflows
de ton dépôt.
Tu peux avoir plusieurs fichiers YAML de workflow dans un même dépôt, par exemple un pour les tests et un autre pour le déploiement. Mais tu peux aussi regrouper tout cela dans un seul et même workflow.
GitHub Actions est très populaire, et de nombreux outils tiers ont développé des packages pour être utilisés dans GitHub Actions, facilitant ainsi l’intégration de ta stack avec aisance.
En explorant la documentation 🔗, tu verras que tu peux tout faire avec GitHub Actions.
Créons ton premier Workflow
Lire toute la documentation pour produire un workflow complet et efficace pour ton dépôt n’est peut-être pas très attrayant.
Je te propose donc un workflow plutôt complet pour lancer le linter, le build, les tests et le coverage.
Pour te montrer chaque étape, je vais me baser sur ce dépôt 🔗 fraîchement créé lors de mon mon guide sur les monorepo.
Création du dossier Workflows
Avant tout, il faut créer la structure de dossier pour accueillir un fichier de workflow. Localement, à la racine du dépôt, crée deux dossiers, puis le fichier de workflow :
mkdir .github
cd .github
mkdir workflows
cd workflows
touch ci.yml
Spécification des instructions dans le fichier YAML
Nous allons spécifier dans le fichier YAML les instructions que GitHub doit suivre. On commence par lui dire dans quelles conditions il doit s’exécuter :
on:
- push
- workflow_dispatch
Le workflow se déclenche dans deux cas :
- push : à chaque fois qu’un commit est poussé sur le dépôt, le workflow se lance automatiquement.
- workflow_dispatch : il est possible de déclencher manuellement ce workflow via l’interface GitHub.
Nom du workflow et concurrence
name: CI
concurrency:
group: ${{ github.ref }}
cancel-in-progress: true
- name : le workflow est nommé “CI”, ce qui permet de l’identifier facilement dans l’interface de GitHub Actions.
- concurrency : les workflows appartenant au même groupe (ici, basé sur github.ref, c’est-à-dire la branche ou le tag) ne peuvent pas s’exécuter simultanément. Si un nouveau workflow est déclenché avant la fin du précédent, celui en cours est annulé. C’est pratique pour économiser les minutes de GitHub Actions, car tu as droit à 2000 minutes gratuites chaque mois.
Définition du Job
jobs:
global:
name: Lint, Build, Test & Analyze
runs-on: ubuntu-latest
steps:
Le job est intitulé “Lint, Build, Test & Analyze” et s’exécute sur l’environnement ubuntu-latest.
La ligne global: représente l’ID du job dans GitHub Actions. Il doit être unique dans le même workflow.
Les Étapes du Workflow
Chaque job est divisé en plusieurs étapes (la ligne steps:
) :
Étape 1 : Setup Node.js
- name: ⚙️ Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
Cette étape installe Node.js version 20, nécessaire pour exécuter les commandes qui suivent. On utilise un package officiel de GitHub Actions que tu peux retrouver ici 🔗 pour connaître toutes les options de paramètrages.
Tu peux adapter le paramètre node-version pour ton dépôt si tu utilise une autre version.
Étape 2 : Installation de pnpm
- name: ⚙️ Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9
run_install: false
Me basant sur ce dépôt 🔗 l’installation de Node n’est pas suffisante. En effet, le dépôt utilise PNPM, un gestionnaire de paquets alternatif à npm.
Cette étape va installé PNPM dans sa version 9.
La commande run_install
est définie sur false
, ce qui signifie que l’installation des dépendances sera effectuée manuellement plus tard parce que à cette étape, j’ai juste un container Node.js avec PNPM mais sans le dépôt.
Tu peux adapter le paramètre version pour ton dépôt si tu utilise une autre version de PNPM.
Si tu utilise que NPM, tu peux supprimer cette step.
Dans le cas où tu utilises Yarn, tu peux adapter cette step comme ça en adaptant le paramètre version pour ton dépôt :
- name: ⚙️ Install yarn
uses: threeal/setup-yarn-action@v2.0.0 # package disponible https://github.com/threeal/setup-yarn-action
with:
version: latest
Étape 3 : Charger le Dépôt
- name: 🔄 Load repository
uses: actions/checkout@master
Le dépôt est cloné sur l’environnement CI pour que les fichiers du projet soient disponibles pour les étapes suivantes.
Étape 4 : Création du Fichier d’Environnement
- name: "Create env.local file in apps/web"
run: |
touch .env.local
echo MY_ENVIRONMENT_VAR=${{ secrets.MY_ENVIRONMENT_VAR }} >> .env.local
echo NEXT_PUBLIC_MY_ENVIRONMENT_VAR=${{ secrets.NEXT_PUBLIC_MY_ENVIRONMENT_VAR }} >> .env.local
cat .env.local
working-directory: apps/web
Un fichier .env.local
est créé pour stocker les variables d’environnement nécessaires. Ces variables sont récupérées à partir des secrets GitHub 🔗, un moyen sécurisé de stocker des informations sensibles pour ne pas qu’il soit affiché en clair dans la codebase.
Le mot-clé working-directory
permet de spécifier dans quel dossier la step doit travailler. Ici je lui dit que c’est dans le dossier apps/web
qui contient une application Next.js car je suis en monorepo. Si tu veux créer un fichier .env
à la racine de ton projet, il suffit de supprimer la ligne working-directory.
Étape 5 : Installation des Dépendances
- name: 🛠️ Install dependencies
run: pnpm i # Si tu utilises npm adapte avec npm i et pour yarn adapte avec yarn install
Les dépendances du projet sont installées à l’aide de pnpm avec la commande pnpm i
.
Étape 6 : Linting
- name: 🖋️ Linting
run: pnpm run lint # Si tu utilises npm adapte avec npm run lint et pour yarn adapte avec yarn run lint
Un contrôle de style (linting) est effectué pour s’assurer que le code respecte les règles définies dans le projet. Si des erreurs sont détectées, le processus échoue ici.
Pour lancer cette commande, tu dois bien entendu avoir une ligne script nommé lint
. Dans mon cas, voici la ligne : “lint”: “turbo lint”, car je suis en monorepo.
Logiquement dans ton projet tu devras avoir une ligne de script lint qui ressemble à ça : eslint --config .eslintrc.js --fix
.
Si tu n’as pas ou que tu ne souhaitez pas lancer le lint, alors tu peux supprimer cette étape.
Étape 7 : Construction
- name: 🏗️ Build
env:
NODE_OPTIONS: "--max_old_space_size=4096"
run: pnpm run build # Si tu utilises npm adapte avec npm run build et pour yarn adapte avec yarn run build
Le projet est construit (compilé) avec ta fameuse commande de build
que tu dois forcément avoir.
La variable d’environnement NODE_OPTIONS
augmente la mémoire disponible pour Node.js, ce qui est particulièrement utile pour les projets volumineux comme un monorepo.
Étape 8 : Exécution des Tests
- name: 🧪 Run tests
env:
NODE_OPTIONS: "--max_old_space_size=4096"
run: pnpm run test # Si tu utilises npm adapte avec npm run test et pour yarn adapte avec yarn run test
Les tests unitaires ou d’intégration sont exécutés.
Le même paramètre de mémoire est utilisé pour éviter les erreurs liées à la taille des processus.
Si tu n’as pas de tests, tu peux supprimer cette partie.
Étape 9 : Envoi du rapport de coverage vers CodeCov
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4.0.1
with:
token: ${{ secrets.CODECOV_TOKEN }}
slug: GaetanCottrez/tuto-monorepo-nextjs-nestjs-clerk-tinacms # Remplacer le slug par le nom de votre utilisateur suivi du nom de votre dépôt
Les rapports de couverture de tests sont envoyés à Codecov, qui est un service d’analyse du coverage de ton code pour évaluer le pourcentage de code couvert par les tests. Le token de Codecov est récupéré via les secrets GitHub.
Pour trouver le CODECOV_TOKEN
, il faudra te créer un compte sur CodeCov 🔗, ajouter l’accès au dépôt en question et le configurer :
Pour tomber sur une page pour récupérer le token :
Tester localement ton Workflow
On pourrait push et voir ce qui se passe avec notre workflow directement sur Github mais ce n’est pas l’idéal pour 3 raisons :
- On gaspille inutilement des minutes de Github Actions
- On multiplie des commits inutiles pour le dépôt polluant un peu ton historique Git
- On perd du temps : le temps de faire le commit, le temps que la Github Action se lance et de voir le résultat
Heureusement, il existe un outil nommé act 🔗 qui permet de lancer localement ta futur Github Actions.
Il se base sur Docker 🔗 pour fonctionner bien entendu, donc veiller à ce qu’il soit installer.
Pour installer act, rien de plus simple avec cette commande :
curl--proto '=https' --tlsv1.2 - sSf https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash
Il est possible bien évidemment de gérer les fameux SECRETS
de Github.
Pour se faire rien de plus simple. Il suffit de créer un fichier .secrets
et de placer les variables d’environnements dedans (comme le fichier .env
) :
MY_ENVIRONMENT_VAR=value_my_environment_var
NEXT_PUBLIC_MY_ENVIRONMENT_VAR=next_public_my_environment_var
CODECOV_TOKEN=140bbb5a-****-****-****-************
Une fois installé, il ne te reste plus qu’à lancer la commande suivante pour lancer ta CI Github Actions :
act --container-architecture linux/amd64
Lorsque tu vas lancer la commande pour la première fois, act va effectuer un pull de son image pour produire le container qui va lancer ta CI. Suivant ta machine et ta connexion internet, cela prendra plus ou moins de temps.
Si tu as une erreur, elle se manifestera de la façon suivante :
[CI / Lint, Build, Test & Analyze] 🏁 Job failed
Error: Job 'Lint, Build, Test & Analyze' failed
Si tout est ok, tu auras le message suivant :
[CI/Lint, Build, Test & Analyze] Cleaning up container for job Lint, Build, Test & Analyze
[CI/Lint, Build, Test & Analyze] 🏁 Job succeeded
A partir de là, tu peux considérer que la CI va fonctionner sur Github.
Déployer ton Workflow
Une fois ton workflow en place et testé, il est temps de le déployer.
Il suffit d’effectuer un commit
et un push
de tes modifications vers la branche spécifiée (dans ce cas, main
).
Puis il suffira de ce rendre dans la partie Actions
de ton dépôt pour voir le workflow en action.
Tu devrais voir les jobs s’exécuter et, normalement, réussir sans erreur!
Bonus: SonarCloud
SonarCloud c’est la version cloud de SonarQube et c’est un peu de CodeCov mais en beaucoup plus complet. En plus du Coverage, il va te permettre de détecter des bugs, des vulnérabilités, des problèmes de sécurité, ainsi que des mauvaises pratiques dans le code.
Un outil complet pour améliorer ton dépôt mais aussi ta façon de coder. L’outil est gratuit tant que tes dépôts sont en public. Pour tes dépôts privées, il faudra passer à la caisse !
Il faudra te créer un compte sur SonarCloud 🔗, ajouter l’accès au dépôt en question et lancer l’analyse initiale pour le créer dans l’outil.
Ajout de l’étape dans la CI
En parallèle de cela, il faut ajouter une nouvelle étape pour SonarCloud dans la CI :
- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONARCLOUD_TOKEN }}
Pour le secret du GITHUB_TOKEN
, il sera provisionné automatiquement via ton compte Github donc tu n’as besoin de ne rien faire.
Récupération du token SonarCloud
Pour SONARCLOUD_TOKEN
, il faudra se rendre dans son compte SonarCloud. Il suffit de se rendre dans la partie sécurité 🔗 de ton compte, puis de générer ton token et l’ajouter dans les secrets de ton repository Github :
Il faudra également désactiver l’analyse automatique sinon ta Github Action ne pourra pas demander une analyse à SonarCloud (et cela ferait doublon).
Pour désactiver l’option, il suffit de se rendre dans la partie Administration
de ton projet sous SonarCloud puis Analysis Method
:
Fichier de configuration
Il faut également créer un fichier sonar-project.properties
à la racine de ton dépôt. Grâce à ce fichier, tu vas pouvoir paramétrer SonarCloud suivant tes besoins mais surtout lui dire sur quel projet tu travailles :
sonar.projectKey=*********
sonar.organization=*******
Pour trouver la valeur de projectKey
, il suffit de se rendre dans la partie Administration
de ton projet sous SonarCloud puis Update Key
:
Pour trouver la valeur de organisation
, il suffit de se rendre dans la partie Organisation
de ton compte sous SonarCloud puis Administration
:
Il faut également lui indiquer le(s) lien(s) de tes différents coverages surtout si tu es en monorepo
sonar.javascript.lcov.reportPaths=apps/api/coverage/lcov.info
Si tu es sur un dépôt standard, remplace apps/api/coverage/lcov.info
par coverage/lcov.info
.
Il suffit ensuite de faire un commit et un push pour relancer la CI :
Et le résultat dans SonarCloud :
Conclusion
Comme tu l’as vu, cette CI est une bonne base pour ton projet TypeScript et elle couvrira la plupart de tes besoins.
Tu peux retrouver le code complet de la CI sur ce dépôt GitHub : https://github.com/GaetanCottrez/tuto-monorepo-nextjs-nestjs-clerk-tinacms 🔗
As-tu trouvé ceci utile? N’hésite pas à me poser des questions en commentaire ou me proposer un cas de figure spécifique à tes besoins.