<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Cli on Matteo ZINUTTI</title><link>https://mzinutti.fr/tags/cli/</link><description>Recent content in Cli on Matteo ZINUTTI</description><generator>Hugo -- gohugo.io</generator><language>fr-fr</language><lastBuildDate>Mon, 11 May 2026 11:12:28 +0200</lastBuildDate><atom:link href="https://mzinutti.fr/tags/cli/index.xml" rel="self" type="application/rss+xml"/><item><title>Golang CLI</title><link>https://mzinutti.fr/posts/go-cli/</link><pubDate>Wed, 10 Apr 2024 22:56:48 +0000</pubDate><guid>https://mzinutti.fr/posts/go-cli/</guid><description>&lt;img src="https://mzinutti.fr/posts/go-cli/cover.png" alt="Featured image of post Golang CLI" /&gt;&lt;p&gt;Ce projet a été réalisé dans le cadre de ma première année de Master à Sup De Vinci lors d&amp;rsquo;un module sur le langage Golang.&lt;/p&gt;
&lt;h2 id="introduction"&gt;Introduction
&lt;/h2&gt;&lt;p&gt;Le cahier des charges fourni par l&amp;rsquo;intervenant faisait la demande de réaliser une CLI en Golang pour une des solutions d&amp;rsquo;authentification imposées parmi les trois suivantes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://casdoor.org/" target="_blank" rel="noopener"
 &gt;Casdoor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://pocketbase.io/" target="_blank" rel="noopener"
 &gt;PocketBase&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://goauthentik.io/" target="_blank" rel="noopener"
 &gt;Authentik&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Une documentation devait être fournie afin d&amp;rsquo;avoir un projet clé en main utilisable par n&amp;rsquo;importe qui.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="choix-des-solutions"&gt;Choix des solutions
&lt;/h2&gt;&lt;h3 id="backend"&gt;Backend
&lt;/h3&gt;&lt;p&gt;Après avoir comparé les 3 solutions d&amp;rsquo;authentification, j&amp;rsquo;ai remarqué qu&amp;rsquo;Authentik et Casdoor sont très complets, de ce fait, il faut un certain temps pour les prendre en main. Mais au vu de la deadline du projet ainsi que ses besoins, je suis parti sur l&amp;rsquo;outil &lt;strong&gt;PocketBase&lt;/strong&gt;. C&amp;rsquo;est un outil simple à déployer et à utiliser, il remplit pile les besoins requis pour le projet.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://mzinutti.fr/posts/go-cli/pocketbase.png"
 alt="pocketbase-ui" width="800px"&gt;&lt;figcaption&gt;
 &lt;h4&gt;PocketBase UI&lt;/h4&gt;
 &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id="framework-golang"&gt;Framework Golang
&lt;/h3&gt;&lt;p&gt;Pour le framework Go, j&amp;rsquo;ai vu qu&amp;rsquo;il existait 2 frameworks qui font l&amp;rsquo;unanimité dans ce domaine : &lt;a class="link" href="https://github.com/spf13/cobra" target="_blank" rel="noopener"
 &gt;&lt;strong&gt;Cobra&lt;/strong&gt; 🐍&lt;/a&gt; et &lt;a class="link" href="https://github.com/alecthomas/kong" target="_blank" rel="noopener"
 &gt;&lt;strong&gt;Kong&lt;/strong&gt; 🦍&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;En suivant des tutoriels sur YouTube qui utilisait le framework &lt;strong&gt;Cobra&lt;/strong&gt;, la simplicité d&amp;rsquo;utilisation m&amp;rsquo;a permis de rapidement mettre en place un POC de ma CLI avec une gestion des flags très intuitive et une documentation automatisée. J&amp;rsquo;ai donc continué sur ce framework. Il y a énormément de projet qui utilise Cobra comme on peut le voir dans cette &lt;a class="link" href="https://github.com/spf13/cobra/blob/main/site/content/projects_using_cobra.md" target="_blank" rel="noopener"
 &gt;liste&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai aussi ajouté le package &lt;a class="link" href="https://github.com/spf13/viper" target="_blank" rel="noopener"
 &gt;&lt;strong&gt;Viper&lt;/strong&gt;&lt;/a&gt; dans le projet qui va permettre la gestion de la configuration dans le projet Golang dans le but de manipuler le fichier conf.json.&lt;/p&gt;
&lt;p&gt;Et pour finir, l&amp;rsquo;ajout du package &lt;a class="link" href="https://github.com/manifoldco/promptui" target="_blank" rel="noopener"
 &gt;&lt;strong&gt;promptUI&lt;/strong&gt;&lt;/a&gt; va permettre d&amp;rsquo;améliorer l&amp;rsquo;UX grâce notamment aux prompts interactifs.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Prompt interactif" class="gallery-image" data-flex-basis="824px" data-flex-grow="343" height="122" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://mzinutti.fr/posts/go-cli/promptui.png" width="419"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="architecture"&gt;Architecture
&lt;/h2&gt;&lt;h3 id="cli"&gt;CLI
&lt;/h3&gt;&lt;p&gt;Au niveau de l&amp;rsquo;architecture de la CLI, j&amp;rsquo;ai choisi de me baser sur celle de &lt;strong&gt;Docker&lt;/strong&gt; que je trouve personnellement très intuitive et pratique à utiliser, et qui est également réaliser via &lt;strong&gt;Cobra&lt;/strong&gt;. Je suis donc parti sur le même modèle &lt;code&gt;command [ressource] [action] [flags]&lt;/code&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://mzinutti.fr/posts/go-cli/cli-architecture.png"
 alt="architecture-de-la-cli" width="700px"&gt;&lt;figcaption&gt;
 &lt;h4&gt;Architecture de la CLI&lt;/h4&gt;
 &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;La CLI va donc pouvoir permettre de se connecter et déconnecter de PocketBase et aussi de réaliser les actions de &lt;strong&gt;CRUD&lt;/strong&gt; (Create, Read, Update, Delete) sur les utilisateurs présents dans le backend. Ce qui répond donc à la demande exprimée dans le cahier des charges.&lt;/p&gt;
&lt;p&gt;Une fois l&amp;rsquo;architecture de ma CLI schématisé, ceci marque la fin de la phase de conception et je peux donc me lancé dans la phase de programmation de cette CLI afin de passer dans le concret.&lt;/p&gt;
&lt;h3 id="code"&gt;Code
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── cmd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── auth
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │ ├── login.go
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │ └── logout.go
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── root.go
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── user
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │ ├── create.go
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │ ├── delete.go
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │ ├── inspect.go
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │ ├── update.go
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │ └── user.go
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── version.go
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── common
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── common.go
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── go.mod
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── go.sum
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── go-cli
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── main.go
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;main.go&lt;/strong&gt; : Permet d’initialiser le programme grâce à la fonction &lt;code&gt;main()&lt;/code&gt;, qui va être le point d&amp;rsquo;entrée de notre programme.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;cmd/&lt;/strong&gt; : Ce dossier regroupe l’ensemble des commandes disponibles dans la CLI. Les fichiers sont organisés en fonction de l&amp;rsquo;architecture de la CLI.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;common/&lt;/strong&gt; : Module qui regroupe les fonctions qui sont utilisées dans plusieurs modules du projet.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="déploiement"&gt;Déploiement
&lt;/h2&gt;&lt;p&gt;Pour le déploiement du projet, celui-ci se résume à un simple fichier &lt;code&gt;docker-compose.yaml&lt;/code&gt; afin de créer le conteneur &lt;strong&gt;PocketBase&lt;/strong&gt; qui contient la base de donnée &lt;strong&gt;SQLite&lt;/strong&gt;. On monte également le fichier pb_data afin d&amp;rsquo;avoir une base de données déjà fourni au niveau des utilisateurs.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;pocketbase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pocketbase&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="m"&gt;8090&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;8080&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./pb_data:/pb/pb_data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;La &lt;strong&gt;CLI&lt;/strong&gt; fonctionne quant à elle via un binaire récupérable depuis les &lt;strong&gt;releases&lt;/strong&gt; GitLab ou bien en compilant le code directement en local.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="démonstration"&gt;Démonstration
&lt;/h2&gt;&lt;p&gt;&lt;img alt="Démonstration de l’utilisation de la CLI" class="gallery-image" data-flex-basis="362px" data-flex-grow="151" height="397" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://mzinutti.fr/posts/go-cli/demo.gif" width="600"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Ce projet a été assez challengeant, car il est intervenu après le module de cours d&amp;rsquo;une semaine sur le Golang. Il fallait donc encore approfondir ce langage pour bien appréhender ce projet. Ayant fait du C dans un passé pas si lointain que ça ce projet m&amp;rsquo;a rappelé quelques bons souvenirs. 😄&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai également pris de l&amp;rsquo;expérience sur le fait de choisir les bons outils pour répondre aux attentes du projet, mais également pour gagner du temps sur le développement.&lt;/p&gt;
&lt;p&gt;Pour un peu plus de détails sur ce projet, le repo est disponible juste &lt;a class="link" href="https://gitlab.com/Toxma/go-cli" target="_blank" rel="noopener"
 &gt;ici&lt;/a&gt; !&lt;/p&gt;</description></item></channel></rss>