Une aventure d’automatisation avec Exercism et GitLab CI
Introduction
Après avoir consacré un temps considérable à la fantastique plateforme exercism.io, j’ai appris de nombreux langages de programmation et reçu des conseils inestimables de mentors. À mesure que j’accumulais divers exercices, j’ai ressenti le besoin d’automatiser et de rationaliser le processus. Cela m’a conduit à explorer les fonctionnalités avancées offertes par GitLab CI. Voici ce que j’ai appris.
Qu’est-ce qu’Exercism ?
Exercism est une plateforme communautaire où les apprenants peuvent acquérir de nouveaux langages de programmation et recevoir des conseils d’experts de mentors bénévoles. La plateforme propose des parcours d’apprentissage structurés, constitués d’une séquence logique d’exercices, pour assurer une progression régulière.

Contrôle de version avec Git
Bien qu’Exercism fournisse une CLI pour télécharger et téléverser des exercices, elle ne remplace pas le besoin de contrôle de version. J’utilise Git pour gérer mes exercices, chacun organisé dans son dossier de langage respectif.
Structure des dossiers
Voici un exemple de la structure du dossier Exercism :
exercism
+-- c
¦ +-- hello-world
¦ +-- hello-world.c
¦ +-- hello-world-test.c
+-- go
¦ +-- leap
¦ ¦ +-- leap.go
¦ ¦ +-- leap_test.go
¦ +-- hamming
¦ +-- hamming.go
¦ +-- hamming_test.go
+-- ruby
+-- sieve
+-- sieve.rb
+-- sieve_test.rb
Développement piloté par les tests (TDD)
Chaque exercice est accompagné de tests qui respectent la méthodologie du Développement piloté par les tests (TDD). Une fois que les tests passent, vous pouvez soumettre votre solution et demander un retour au mentor.
Le besoin d’intégration continue
Après avoir accumulé diverses solutions, je voulais un système d’Intégration Continue (CI) qui m’aiderait à maintenir et mettre à jour mes exercices, surtout lorsque de nouveaux tests sont introduits. Je voulais également adhérer au principe DRY (Don’t Repeat Yourself), visant un modèle de CI qui pourrait être appliqué à tous les exercices d’un même langage.
Après avoir évalué diverses solutions de CI comme Jenkins, CircleCI, Travis CI et Codeship, j’ai opté pour GitLab CI en raison de ses fonctionnalités robustes et de ses spécifications.
Exploiter les pipelines parents-enfants de GitLab CI
GitLab offre un service de CI gratuit qui peut être facilement intégré aux projets Git et GitHub. Une fonctionnalité puissante est les Pipelines parents-enfants, qui permettent l’exécution d’un pipeline CI depuis un autre, permettant effectivement la création de méta-pipelines CI.
Niveaux de CI imbriqués
Ma configuration CI s’étend sur trois niveaux imbriqués :
- Niveau Racine : Exécute une CI pour chaque langage de programmation.
- Niveau Langage : Exécute une CI pour chaque exercice au sein d’un langage.
- Niveau Exercice : Exécute les tests fournis par la plateforme pour chaque exercice.
Extraits de code
Voici quelques extraits de code pour vous donner une idée de comment cela fonctionne :
Niveau Racine .gitlab-ci.yml
emacs-lisp:
stage: test
trigger:
project: EmilienMottet/exercism-emacs-lisp-sol
strategy: depend
rules:
- changes:
- emacs-lisp/*
x86-64-assembly:
stage: test
trigger:
project: EmilienMottet/exercism-x86-64-assembly-sol
strategy: depend
rules:
- changes:
- x86-64-assembly/*
Niveau Langage .generate-config.jsonnet
local exercism_projects = std.map(function(x) std.strReplace(x, '/', ''), std.split(std.extVar('exercism_projects'), '\n'));
local lang = std.extVar('lang');
local JobHandler(name) = {
['test_' + lang + '_' + name]: {
stage: 'test',
trigger: {
include: [
{
artifact: '.' + lang + '-' + name + '-gitlab-ci.yml',
job: 'generate_' + lang + '_gitlab_ci',
},
],
strategy: 'depend',
},
},
};
{
'.generated-config.yml': { ['generate_' + lang + '_gitlab_ci']: {
stage: 'build',
image: {
name: 'bitnami/jsonnet:latest',
entrypoint: [''],
},
script: [
'DIR_SPLIT=$(echo $DIR_TO_BE_TESTED | tr " " "\n")',
'jsonnet -m . --ext-str exercism_projects="$DIR_SPLIT" --ext-str lang="' + lang + '" ".' + lang + '-gitlab-ci.jsonnet"',
],
needs: [
{
pipeline: '$PARENT_PIPELINE_ID',
job: 'build_vars',
},
],
artifacts: {
paths: [
'.' + lang + '-*-gitlab-ci.yml',
],
},
} } + std.foldl(function(x, y) x + y, std.map(JobHandler, exercism_projects), {}),
}
Niveau Exercice .c-gitlab-ci.jsonnet
local exercism_projects = std.map(function(x) std.strReplace(x, '/', ''), std.split(std.extVar('exercism_projects'), '\n'));
local lang = std.extVar('lang');
local CTestJob(name) = {
['.' + lang + '-' + name + '-gitlab-ci.yml']: {
default: {
image: 'gcc:latest',
},
['test-' + lang + '-' + name + '-exercism']: {
script: [
'cd ' + name,
'make',
],
},
},
};
std.foldl(function(x, y) x + y, std.map(CTestJob, exercism_projects), {})
Conclusion
J’espère que cet article vous inspirera à essayer Exercism et peut-être même à contribuer à la communauté. Automatiser votre flux de travail permet non seulement de gagner du temps mais aussi de s’assurer que vous êtes toujours à jour, vous permettant de vous concentrer sur ce qui compte vraiment : apprendre et s’améliorer.
Merci d’avoir lu !
Article complet : https://dev.to/emilienmottet/a-journey-into-the-depths-of-gitlab-ci-15j5