<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Emilien Mottet</title>
    <description>The latest articles on DEV Community by Emilien Mottet (@emilienmottet).</description>
    <link>https://dev.to/emilienmottet</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F97981%2F84025984-c74e-4f13-80b3-e45fb7e8425d.png</url>
      <title>DEV Community: Emilien Mottet</title>
      <link>https://dev.to/emilienmottet</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/emilienmottet"/>
    <language>en</language>
    <item>
      <title>From MITM to Agentic Design: Automating Sports Nutrition with Claude, n8n, and Hexis</title>
      <dc:creator>Emilien Mottet</dc:creator>
      <pubDate>Mon, 29 Dec 2025 01:44:12 +0000</pubDate>
      <link>https://dev.to/emilienmottet/from-mitm-to-agentic-design-automating-sports-nutrition-with-claude-n8n-and-hexis-12gg</link>
      <guid>https://dev.to/emilienmottet/from-mitm-to-agentic-design-automating-sports-nutrition-with-claude-n8n-and-hexis-12gg</guid>
      <description>&lt;p&gt;Automating sports nutrition is the Holy Grail for many amateur athletes. We want the precision of a nutritionist without the mental load.&lt;/p&gt;

&lt;p&gt;My goal was simple: synchronize my workouts (Intervals.icu / nolio.io) with my nutritional needs (&lt;strong&gt;Hexis.live&lt;/strong&gt;) and generate automatic meal plans.&lt;/p&gt;

&lt;p&gt;For those unfamiliar, &lt;strong&gt;Hexis&lt;/strong&gt; is an intelligent nutrition platform that calculates your real-time energy needs (carbs, proteins, fats) based on the intensity of your past and future workouts. The problem? &lt;strong&gt;Hexis does not have a public API for meal creation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is how I combined &lt;strong&gt;Reverse Engineering&lt;/strong&gt;, &lt;strong&gt;Man-in-the-Middle&lt;/strong&gt;, &lt;strong&gt;Advanced Agentic Design&lt;/strong&gt;, &lt;strong&gt;Meta-MCP&lt;/strong&gt;, and &lt;strong&gt;n8n&lt;/strong&gt; to build an autonomous and cost-effective system.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Hack: Reverse Engineering &amp;amp; Man-in-the-Middle
&lt;/h2&gt;

&lt;p&gt;Since the front door was locked, I went through the window. To automate meal logging, I set up a &lt;strong&gt;Man-in-the-Middle (MITM)&lt;/strong&gt; attack to listen to traffic between the mobile app and the servers.&lt;/p&gt;

&lt;p&gt;Unexpectedly, this interception proved &lt;strong&gt;easier to set up on iPhone than on Android&lt;/strong&gt;, allowing me to quickly map the structure of the private APIs.&lt;/p&gt;

&lt;p&gt;I discovered that the API doesn't just settle for a food ID. It requires a specific &lt;code&gt;refCode&lt;/code&gt; (a Base64 string hidden in search results) to validate the log. Without this key, the API returns a silent error.&lt;/p&gt;

&lt;p&gt;I encapsulated this complexity (search + &lt;code&gt;refCode&lt;/code&gt; extraction + formatting) in a &lt;strong&gt;custom MCP server&lt;/strong&gt;. For my AI agents, the operation becomes transparent: they ask to "add a banana", and the server handles the cryptography backstage.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Crew Architecture: 2 Pipelines and 10 Agents
&lt;/h2&gt;

&lt;p&gt;Once data access was solved, I built the system's "brain" with &lt;strong&gt;CrewAI&lt;/strong&gt;. The architecture is split into two distinct pipelines to ensure precision and reliability.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧠 Pipeline 1: Data Analysis
&lt;/h3&gt;

&lt;p&gt;This first group defines the nutritional strategy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;HEXIS_DATA_SUPERVISOR&lt;/strong&gt;: The Strategist. Plans which data to retrieve (training load, recovery status). Pure "Thinking" model, no tool access.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;HEXIS_ANALYSIS_REVIEWER&lt;/strong&gt;: The Nutritionist. Analyzes raw data to define precise macro targets (e.g., "Tomorrow is a big session, we need 400g of carbs").&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fniqdatj9b0qdkcpwphef.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fniqdatj9b0qdkcpwphef.png" alt="Example pipeline" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🍳 Pipeline 2: Meal Generation
&lt;/h3&gt;

&lt;p&gt;This is where magic happens to turn numbers into recipes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;MEAL_PLANNING_SUPERVISOR&lt;/strong&gt; (The Chef): Designs the structure of the 4 daily meals respecting energy codes (Low/Medium/High Carb) and ensuring culinary variety.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;INGREDIENT_VALIDATION_EXECUTOR&lt;/strong&gt; (The Commis): The only agent allowed to talk to the database. Uses parallel execution to quickly validate ingredient existence in the Passio/Hexis database.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;MEAL_RECIPE_REVIEWER&lt;/strong&gt; (The Controller): Performs final mathematical calculations. If the Chef planned too much chicken, the Reviewer adjusts the portion to the gram to hit ±5% of targets.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This structure relies on a key principle: &lt;strong&gt;Reasoning/Action Separation&lt;/strong&gt;. "Intelligent" models (Supervisors) never touch tools to avoid hallucinations. They delegate technical execution to simpler, faster models (Executors).&lt;/p&gt;

&lt;h3&gt;
  
  
  Support Agents
&lt;/h3&gt;

&lt;p&gt;Other agents (Weekly Structure, Nutritional Validation, Integration) ensure overall weekly consistency and final synchronization to the app.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. MCP Infrastructure: Why Meta-MCP?
&lt;/h2&gt;

&lt;p&gt;I use &lt;strong&gt;Meta-MCP&lt;/strong&gt;, an essential abstraction layer. Why? Mainly for &lt;strong&gt;security&lt;/strong&gt; and &lt;strong&gt;modularity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It allows me to group tools by domain (Sports, Nutrition, Weather) and distribute to each agent only what it strictly needs. Thus, my "Hexis Executor" doesn't risk accidentally deleting a Strava activity. It's a least privilege principle applied to AI agents.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnbd34nrm1y21m3i3t9e8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnbd34nrm1y21m3i3t9e8.png" alt="MetaMCP" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Cost Optimization: Smart AI Pricing
&lt;/h2&gt;

&lt;p&gt;Running autonomous agents 24/7 has a cost. To avoid an astronomical bill, I implemented an aggressive strategy:&lt;/p&gt;

&lt;h3&gt;
  
  
  Reverse Proxies &amp;amp; Alternative Models
&lt;/h3&gt;

&lt;p&gt;I use OpenAI-compatible &lt;strong&gt;Reverse Proxies&lt;/strong&gt; (like CLIProxyAPI) to access high-performance alternative models. Special mention to &lt;strong&gt;DeepSeek&lt;/strong&gt; and &lt;strong&gt;GLM-4.6 (via z.ai)&lt;/strong&gt; which now offer performance close to &lt;strong&gt;Claude 4.5 Sonnet&lt;/strong&gt; for a fraction of the price.&lt;/p&gt;

&lt;p&gt;Using specialized "Coder" models for structured tasks (JSON) also drastically reduces costs without quality loss.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automatic Rotation
&lt;/h3&gt;

&lt;p&gt;My system manages a &lt;strong&gt;model cascade&lt;/strong&gt;. If the "Premium" model (Claude 4.5 Sonnet) hits its quota or rate-limit, the system automatically switches to an "Eco" model (GPT-4o-mini or GLM-4) to finish the task. It's transparent to the user and saves production.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Orchestration with n8n
&lt;/h2&gt;

&lt;p&gt;Having intelligent agents isn't enough; they need to live over time. That's where &lt;strong&gt;n8n&lt;/strong&gt; comes in.&lt;/p&gt;

&lt;p&gt;I set up a workflow (&lt;code&gt;meal-planning-weekly&lt;/code&gt;) that runs every Sunday evening:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Retrieve training load&lt;/strong&gt;: The workflow queries Intervals.icu (or nolio.io) to know my upcoming sessions for the week.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Schedule optimization&lt;/strong&gt;: A JS script reorganizes my slots (e.g., "If big bike ride on Saturday -&amp;gt; High carb meal on Friday night").&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Asynchronous Call to AI&lt;/strong&gt;: n8n triggers my CrewAI Python script via an HTTP webhook.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Callback Pattern&lt;/strong&gt;: Since meal generation takes time (several minutes of thinking for the agents), n8n doesn't block. It waits for a return "ping" (callback) once the agents have finished their work.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Distribution&lt;/strong&gt;: The final result (shopping list + menu) is sent directly to Telegram.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsndvteh0qql8foxlef20.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsndvteh0qql8foxlef20.png" alt="n8n" width="800" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This project demonstrates that with thoughtful architecture, we can bypass closed API limits and create AI systems that are truly useful in daily life.&lt;/p&gt;

&lt;p&gt;By combining the reasoning power of "Thinking" models, the execution precision of MCP servers, and the robust orchestration of n8n, we are no longer in gadget territory, but dealing with a real personal assistant.&lt;/p&gt;

&lt;p&gt;The code is available on my GitHub. Next step? Automating grocery ordering via a drive-thru API... the next reverse engineering challenge!&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/EmilienMottet/crew-coach" rel="noopener noreferrer"&gt;https://github.com/EmilienMottet/crew-coach&lt;/a&gt;&lt;/p&gt;

</description>
      <category>agentic</category>
      <category>hack</category>
      <category>mcp</category>
      <category>n8n</category>
    </item>
    <item>
      <title>A journey into the depths of gitlab-ci</title>
      <dc:creator>Emilien Mottet</dc:creator>
      <pubDate>Wed, 03 Mar 2021 21:48:03 +0000</pubDate>
      <link>https://dev.to/emilienmottet/a-journey-into-the-depths-of-gitlab-ci-15j5</link>
      <guid>https://dev.to/emilienmottet/a-journey-into-the-depths-of-gitlab-ci-15j5</guid>
      <description>&lt;h1&gt;
  
  
  The beginning of an adventure
&lt;/h1&gt;

&lt;p&gt;After spending a lot of time on the awesome exercism.io platform, I was able to learn a lot of new languages and received great advice. After having accumulated a lot of exercism, I tried to automate and industrialize it. I was able to discover advanced features proposed by gitlab-ci. Here is my feedback&lt;/p&gt;

&lt;h3&gt;
  
  
  Exercism
&lt;/h3&gt;

&lt;p&gt;Exercism is a community site, where people wishing to learn a new language can receive expert advice from volunteer mentors.&lt;br&gt;
To learn a language, it is advisable to follow a path that corresponds to a logical sequence of exercises to have a regular progression in the language.&lt;/p&gt;

&lt;p&gt;Here is the list of all the tracks (learning paths) available on the platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F60xuj1vhv8x8p8wik608.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F60xuj1vhv8x8p8wik608.png" alt="All tracks available on exercism.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Exercism offers a cli to download and upload these exercises. This system is good but does not replace a versioning with git. So I use git to version my exercises.&lt;/p&gt;

&lt;p&gt;The exercism folder is composed of subfolders for each language, and each language contains a folder for each exercism.&lt;/p&gt;

&lt;p&gt;Here is an example of the architecture of an exercism folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each exercise has tests to validate. The exercises use the &lt;a href="https://en.wikipedia.org/wiki/Test-driven_development" rel="noopener noreferrer"&gt;TDD method&lt;/a&gt;. Once the tests have been validated, the solution can be submitted and the return of a mentor is requested.&lt;/p&gt;

&lt;p&gt;After accumulating many solutions, I wanted to have an IC that would allow me to stabilize and keep my exercises up to date if new tests were added.&lt;/p&gt;

&lt;p&gt;Moreover, the way of executing the tests is similar depending on the tracks/languages. For example the exercises in go will be tested with the command &lt;code&gt;go test&lt;/code&gt; or for java exercises &lt;code&gt;gradle test&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Wanting to follow the &lt;a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself" rel="noopener noreferrer"&gt;DRY principle&lt;/a&gt;, I would like to have a CI template that I could apply to all the exercises in the same language and add this CI to all the new exercises.&lt;/p&gt;

&lt;p&gt;I compared the different continuous integration solutions available for open source projects (Jenkins, CircleCI, Travis CI, Codeship Gitlab CI). I chose gitlab-ci because it offers the most interesting specifications and features.&lt;/p&gt;

&lt;h1&gt;
  
  
  🦊 The Powerful Feature : Parent Child Pipelines
&lt;/h1&gt;

&lt;p&gt;Gitlab offers a free CI, which can be easily integrated into a git project and even integrated into a Github project. Cool, my repo is on  &lt;a href="https://github.com/EmilienMottet/exercism-sol" rel="noopener noreferrer"&gt;github&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://docs.gitlab.com/ee/ci/parent_child_pipelines.html" rel="noopener noreferrer"&gt;Parent Child Pipelines&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;They allow to execute a CI from a CI. It is therefore possible to create a meta-CI. Despite some limitations that we will see later, Parent Child Pipelines allow me to spread my CI over 3 nested levels :  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At the root of the exercises folder which will execute a CI for each language. The simplest file, it just has to trigger the ci of the languages:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;emacs-lisp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;trigger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EmilienMottet/exercism-emacs-lisp-sol&lt;/span&gt;
    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;depend&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;changes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;emacs-lisp/*&lt;/span&gt;

&lt;span class="na"&gt;x86-64-assembly&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;trigger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EmilienMottet/exercism-x86-64-assembly-sol&lt;/span&gt;
    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;depend&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;changes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;x86-64-assembly/*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gitlab.com/EmilienMottet/exercism-sol/-/blob/master/.gitlab-ci.yml" rel="noopener noreferrer"&gt;Full file&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At the root of each language that will execute a CI for each exercise:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"generate_c_gitlab_ci"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"artifacts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"paths"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;".c-*-gitlab-ci.yml"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"entrypoint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bitnami/jsonnet:latest"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"needs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"job"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"build_vars"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"pipeline"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$PARENT_PIPELINE_ID"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"script"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="s2"&gt;"jsonnet -m . --ext-str exercism_projects=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;$( echo $DIR_TO_BE_TESTED | sed -En 's/ /&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;n/p' )&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; --ext-str lang=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;c&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;.c-gitlab-ci.jsonnet&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"stage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"build"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"test_c_armstrong-numbers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"stage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"trigger"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"include"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"artifact"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".c-armstrong-numbers-gitlab-ci.yml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"job"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"generate_c_gitlab_ci"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"strategy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"depend"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"test_c_hello-world"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"stage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"trigger"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"include"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"artifact"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".c-hello-world-gitlab-ci.yml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"job"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"generate_c_gitlab_ci"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"strategy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"depend"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gitlab.com/EmilienMottet/exercism-sol/-/blob/master/c/.generate-config.jsonnet" rel="noopener noreferrer"&gt;Template file&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At the root of each exercise to run the tests provided by the platform :
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gcc:latest"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"test-c-armstrong-numbers-exercism"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"script"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="s2"&gt;"cd armstrong-numbers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="s2"&gt;"make"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gitlab.com/EmilienMottet/exercism-sol/-/blob/master/c/.c-gitlab-ci.jsonnet" rel="noopener noreferrer"&gt;Template file&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note the use of the rules field which allows each new push to execute the CI task only if there has been a modification in the given path.&lt;/p&gt;

&lt;p&gt;To be DRY, I need to templating my CI, an example is proposed with &lt;a href="https://jsonnet.org/" rel="noopener noreferrer"&gt;jsonnet&lt;/a&gt;. Here is an example proposed by the gitlab team: &lt;a href="https://gitlab.com/gitlab-org/project-templates/jsonnet" rel="noopener noreferrer"&gt;https://gitlab.com/gitlab-org/project-templates/jsonnet&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  A template for each situation
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F10fl7agsugown8fautyp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F10fl7agsugown8fautyp.png" alt="jsonnet logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A gitlab-ci.yml file can be described in jsonnet format.&lt;/p&gt;

&lt;p&gt;For example :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsonnet"&gt;&lt;code&gt;&lt;span class="k"&gt;local&lt;/span&gt; &lt;span class="nx"&gt;exercism_projects&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;strReplace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'exercism_projects'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="k"&gt;local&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'lang'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;local&lt;/span&gt; &lt;span class="nx"&gt;CTestJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'.'&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'-'&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'-gitlab-ci.yml'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'gcc:latest'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'test-'&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'-'&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'-exercism'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s"&gt;'cd '&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'make'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;span class="nx"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;foldl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CTestJob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;exercism_projects&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This template allows you to describe gitlab-ci.yml for C exercisms.&lt;/p&gt;

&lt;p&gt;Morality, jsonnet templates to avoid repetition, it's perfect!&lt;/p&gt;

&lt;h1&gt;
  
  
  The almost perfect IC, multi project pipeline
&lt;/h1&gt;

&lt;p&gt;Parent Child Pipeline are awesome but have several flaws, 2 were notable to me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only 2 levels for Nested child pipelines. In my case I need 3 levels. The limitation can be bypassed by using multi-project pipelines.&lt;/li&gt;
&lt;li&gt;Management of files modified by the last commit to avoid rebuilding all exercisms.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the management of modified files, it is possible to recalculate the modified files using a pre-step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;build_vars&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.pre&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;if [ "$CI_PIPELINE_TRIGGERED" = "true" ]; then&lt;/span&gt;
        &lt;span class="s"&gt;DIR_TO_BE_TESTED=$(ls -d */)&lt;/span&gt;
      &lt;span class="s"&gt;else&lt;/span&gt;
        &lt;span class="s"&gt;DIR_TO_BE_TESTED=$(git diff --name-only $CI_COMMIT_SHA^ $CI_COMMIT_SHA */ | cut -d'/' -f1 | sort | uniq)&lt;/span&gt;
        &lt;span class="s"&gt;if [ -z $DIR_TO_BE_TESTED ]; then&lt;/span&gt;
          &lt;span class="s"&gt;DIR_TO_BE_TESTED=$(ls -d */)&lt;/span&gt;
        &lt;span class="s"&gt;fi&lt;/span&gt;
      &lt;span class="s"&gt;fi&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo DIR_TO_BE_TESTED=$DIR_TO_BE_TESTED &amp;gt;&amp;gt; build.env&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cat build.env&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;reports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;dotenv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build.env&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the exercisms has been modified, it can be exported to artifact to share it with the job that will be generated afterwards.&lt;/p&gt;

&lt;h1&gt;
  
  
  Submodule vs subtree
&lt;/h1&gt;

&lt;p&gt;Because of the limitation of the number of nested and also a wish to separate the different tracks, I created a git repository for each track (manual action that could be automated with ansible).&lt;/p&gt;

&lt;p&gt;The classic way to manage these nested projects would be to use the git submodule. However, keeping a consistent set of git submodule up to date can become quite restrictive.&lt;/p&gt;

&lt;p&gt;There is an alternative ! The subtree :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git-subtree - Merge subtrees together and split repository into subtrees
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The advantage I found in subtrees is that I can mirror only the tracks and automate this one simply with the git hooks. And this without modifying my existing one.&lt;/p&gt;

&lt;p&gt;To create a subtree nothing could be simpler :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;git subtree add --prefix=clojure --squash git@github.com:EmilienMottet/exercism-clojure-sol.git master
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then to make sure the subtrees is up to date, just add a hook to the post-commit..&lt;/p&gt;

&lt;p&gt;Here is my hook file &lt;code&gt;.git/hooks/post-commit&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

subtree_push&lt;span class="o"&gt;(){&lt;/span&gt;
    git subtree push &lt;span class="nt"&gt;-P&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; git@github.com:EmilienMottet/exercism-&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;-sol&lt;/span&gt;.git master
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="nb"&gt;dir &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;subtree_push &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt; /dev/null &amp;amp;
&lt;span class="k"&gt;done


for &lt;/span&gt;&lt;span class="nb"&gt;dir &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nb"&gt;wait
&lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt; &amp;amp;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At each commit, each subtree is updated in the background.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;I hope this article has made you want to try exercism.io and, why not, join this community.&lt;/p&gt;

&lt;p&gt;Industrialize, as quickly as possible. Exercism has a version management system, however, complementing it with git allows you to go further: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For example, I can do my exercises on several machines &lt;/li&gt;
&lt;li&gt;The automated tasks save me a lot of time&lt;/li&gt;
&lt;li&gt;have a backup system &lt;/li&gt;
&lt;li&gt;Just manage the history&lt;/li&gt;
&lt;li&gt;share my work and make it visible on github.com. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Test yourself, the basis of exercise is the TDD. It is important to test yourself and your code all the time. Moreover, I want to keep my exercism compatible with the latest version of each language and in the future with new tests added by the community. Having up to date exercism allows you to always have up to date exercism that make a very good example, and it allows you to have a lot of stars ;)&lt;/p&gt;

&lt;p&gt;DRY ! Do not repeat, Do not repeat (oops)! At first, factorized allows to gain clarity. Allows for sanctuarisation and transmission of knowledge. How many times you make a set of commands that are almost automatic, but after several months without doing them, you end up forgetting them. Taking the time to template, this time is quickly gained!&lt;/p&gt;

&lt;p&gt;Thank you for reading :)&lt;/p&gt;

</description>
      <category>git</category>
      <category>gitlab</category>
      <category>ci</category>
      <category>subtree</category>
    </item>
  </channel>
</rss>
