<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Til on FtBx.fr</title><link>https://ftbx.fr/tags/til/</link><description>Recent content in Til on FtBx.fr</description><image><title>FtBx.fr</title><url>https://ftbx.fr/images/placeholder-image.jpg</url><link>https://ftbx.fr/images/placeholder-image.jpg</link></image><generator>Hugo -- 0.146.6</generator><language>fr</language><copyright>2025 ftbx.fr - This work is licensed under CC BY-NC-SA 4.0</copyright><lastBuildDate>Wed, 03 Sep 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://ftbx.fr/tags/til/index.xml" rel="self" type="application/rss+xml"/><item><title>GitLab CI parallel:matrix : les needs individuels sont enfin là</title><link>https://ftbx.fr/posts/gitlab-ci-parallel-matrix-es-needs-individuels-sont-enfin-e/</link><pubDate>Wed, 03 Sep 2025 00:00:00 +0000</pubDate><guid>https://ftbx.fr/posts/gitlab-ci-parallel-matrix-es-needs-individuels-sont-enfin-e/</guid><description>&lt;p>Avant, &lt;code>parallel:matrix&lt;/code> permettait de lancer la même tâche sur
plusieurs versions. Mais impossible de référencer UN job spécifique
de la matrice dans un &lt;code>needs&lt;/code>. Toute la matrice formait un bloc
indivisible.&lt;/p>
&lt;p>GitLab 16.7 a changé ça. Maintenant, tu peux &lt;code>needs&lt;/code> un job précis
de la matrice. Et ça débloque des pipelines plus propres.&lt;/p>
&lt;h3 id="avant--le-workaround">Avant : le workaround&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># ❌ Avant GitLab 16.7 : impossible de référencer un job de la matrice&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">test&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">parallel&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">matrix&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">PYTHON&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;3.9&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;3.10&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;3.11&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">pytest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">deploy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">needs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;test&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># Attend TOUS les jobs de la matrice&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">./deploy.sh&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="après--des-needs-chirurgicaux">Après : des needs chirurgicaux&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># ✅ GitLab 16.7+ : on cible un job précis&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">test&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">parallel&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">matrix&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">PYTHON&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;3.9&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;3.10&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;3.11&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">pytest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">deploy_39&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">needs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;test: [3.9]&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">./deploy-py39.sh&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">deploy_latest&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">needs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;test: [3.11]&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">./deploy-pylatest.sh&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Le job &lt;code>deploy_39&lt;/code> attend UNIQUEMENT &lt;code>test: [3.9]&lt;/code>. Il n&amp;rsquo;attend pas
les tests Python 3.10 et 3.11. Résultat : le déploiement peut partir
dès que sa version est validée, sans attendre les autres.&lt;/p></description></item><item><title>just : un Makefile moderne que j'ai quitté pour make</title><link>https://ftbx.fr/posts/just-makefile-moderne-que-jai-quitte-make/</link><pubDate>Sun, 08 Jun 2025 00:00:00 +0000</pubDate><guid>https://ftbx.fr/posts/just-makefile-moderne-que-jai-quitte-make/</guid><description>&lt;p>J&amp;rsquo;ai découvert &lt;code>just&lt;/code> en parcourant des projets Rust lorsque j&amp;rsquo;ai commencé à apprendre le langage.&lt;/p>
&lt;p>&lt;code>just&lt;/code> c&amp;rsquo;est un Makefile sans la syntaxe particulière de Make. Les recettes sont
plus lisibles, le langage est pensé pour lancer des commandes (pas pour
compiler du C). Et la syntaxe des dépendances est plus intuitive :&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-justfile" data-lang="justfile">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># justfile
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nf">deploy&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="n">build&lt;/span> &lt;span class="n">push&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> kubectl apply -f deploy/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">build&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> docker build -t monapp .
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">push&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> docker push monapp:latest
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Moi qui ai tendance à utiliser pas mal Make pour ce genre de raccourcis (et jamais pour builder du C), ça m&amp;rsquo;a convaincu pendant 3 mois. Puis j&amp;rsquo;ai travaillé sur des machines où &lt;code>just&lt;/code> n&amp;rsquo;était pas installé. Et là, Make est toujours installé. Prêt à opérer. Aucun obstacle.&lt;/p></description></item><item><title>k9s : l'UX qui fait aimer Kubernetes, au prix de l'amnésie kubectl</title><link>https://ftbx.fr/posts/k9s-ux-qui-fait-aimer-kubernetes-prix-amnesie-kubectl/</link><pubDate>Mon, 28 Apr 2025 00:00:00 +0000</pubDate><guid>https://ftbx.fr/posts/k9s-ux-qui-fait-aimer-kubernetes-prix-amnesie-kubectl/</guid><description>&lt;p>&lt;code>k9s&lt;/code> est un excellent TUI Kubernetes. Quand je l&amp;rsquo;ai découvert, j&amp;rsquo;ai eu
l&amp;rsquo;impression de passer du terminal IBM 3270 à un OS graphique. Tu navigues
dans les pods avec &lt;code>↑↓&lt;/code>, tu filtres avec &lt;code>/&lt;/code>, tu lances des commandes
avec &lt;code>:&lt;/code>. Plus besoin de taper &lt;code>kubectl get pods -n machin -o wide | grep bidule&lt;/code>.&lt;/p>
&lt;p>Mais il y a un prix : tu oublies &lt;code>kubectl&lt;/code>. Vite. Très vite.&lt;/p>
&lt;h3 id="ce-que-k9s-fait-mieux-que-kubectl">Ce que k9s fait mieux que kubectl&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Navigation&lt;/strong> : &lt;code>:pods&lt;/code> → liste des pods → &lt;code>Enter&lt;/code> sur un pod → logs.
3 touches au lieu de &lt;code>kubectl get pods -n X &amp;amp;&amp;amp; kubectl logs -n X pod/Y&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Filtrage&lt;/strong> : &lt;code>/error&lt;/code> filtre en temps réel. &lt;code>Ctrl+A&lt;/code> pour désactiver.
C&amp;rsquo;est &lt;code>grep&lt;/code> intégré, réactif à chaque frappe.&lt;/li>
&lt;li>&lt;strong>Actions&lt;/strong> : &lt;code>d&lt;/code> pour décrire, &lt;code>s&lt;/code> pour shell, &lt;code>l&lt;/code> pour logs, &lt;code>y&lt;/code> pour YAML.
Tout le monde a les mêmes raccourcis — pas besoin d&amp;rsquo;apprendre les flags.&lt;/li>
&lt;li>&lt;strong>Nodes&lt;/strong> : &lt;code>:nodes&lt;/code> → tu vois l&amp;rsquo;état des nœuds, les pods par nœud, les
ressources utilisées. En une vue. &lt;code>kubectl describe node&lt;/code> × 10 nœuds,
c&amp;rsquo;est 10 commandes. k9s = une vue.&lt;/li>
&lt;/ul>
&lt;h3 id="le-revers">Le revers&lt;/h3>
&lt;p>Après 3 mois de k9s intensif, j&amp;rsquo;ai réalisé que j&amp;rsquo;étais incapable d&amp;rsquo;écrire
un &lt;code>kubectl get pods --sort-by=.status.startTime&lt;/code> sans Google. k9s m&amp;rsquo;a
rendu plus rapide au quotidien mais plus dépendant d&amp;rsquo;un outil qui n&amp;rsquo;est
pas installé partout.&lt;/p></description></item><item><title>uv a remplacé pip dans mon workflow Python</title><link>https://ftbx.fr/posts/uv-a-remplace-pip-mon-workflow-python/</link><pubDate>Mon, 10 Mar 2025 00:00:00 +0000</pubDate><guid>https://ftbx.fr/posts/uv-a-remplace-pip-mon-workflow-python/</guid><description>&lt;p>J&amp;rsquo;ai découvert &lt;code>uv&lt;/code> en février 2025. En mars, pip n&amp;rsquo;existait plus chez moi.&lt;/p>
&lt;p>Avant, gérer les dépendances Python c&amp;rsquo;était pip + pip-tools + virtualenv + un fichier texte pour se souvenir de la commande d&amp;rsquo;activation. Trop de pièces mobiles pour un truc qui devrait être simple. (Quant à poetry, j&amp;rsquo;ai jamais passé le pas)&lt;/p>
&lt;p>&lt;code>uv pip install&lt;/code> est 10 à 100× plus rapide que pip. &lt;code>uv venv&lt;/code> crée un virtualenv en moins d&amp;rsquo;une seconde. Et &lt;code>uv pip compile&lt;/code> remplace pip-tools sans avoir à installer quoi que ce soit. Tout est dans un seul binaire.&lt;/p></description></item><item><title>age + sops : le combo qui remplace GPG pour les secrets dans Git</title><link>https://ftbx.fr/posts/age-sops-e-combo-qui-remplace-gpg-es-secrets-git/</link><pubDate>Sat, 01 Mar 2025 00:00:00 +0000</pubDate><guid>https://ftbx.fr/posts/age-sops-e-combo-qui-remplace-gpg-es-secrets-git/</guid><description>&lt;p>Stocker des secrets dans Git, tout le monde le dit : c&amp;rsquo;est une mauvaise
pratique. Mais stocker ses secrets dans un vault et ses fichiers de
config dans Git, c&amp;rsquo;est deux sources de vérité qui finissent par dériver.&lt;/p>
&lt;p>&lt;code>sops&lt;/code> résout ça : on commit ses secrets chiffrés avec ses fichiers
de config. Un seul dépôt, une seule source de vérité. Au déploiement,
le secret est déchiffré à la volée.&lt;/p>
&lt;h3 id="setup-avec-age">Setup avec age&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Générer une clé age (une ligne)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">age-keygen -o ~/.config/sops/age/keys.txt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Récupérer la clé publique&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">age-keygen -y ~/.config/sops/age/keys.txt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># → age1ql3z7hjy54p3w6d...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>La config minimale &lt;code>.sops.yaml&lt;/code> à la racine du dépôt :&lt;/p></description></item><item><title>age vs GPG : pourquoi j'ai arrêté de m'arracher les cheveux</title><link>https://ftbx.fr/posts/age-comment-jai-arrete-marracher-es-cheveux-avec-gpg/</link><pubDate>Mon, 17 Feb 2025 00:00:00 +0000</pubDate><guid>https://ftbx.fr/posts/age-comment-jai-arrete-marracher-es-cheveux-avec-gpg/</guid><description>&lt;p>Pendant des années, chiffrer un fichier c&amp;rsquo;était : générer une clé GPG, la stocker
sur une clé physique, gérer l&amp;rsquo;expiration, prier pour que le keyring ne soit pas corrompu, et relire la doc GPG pour la trente-septième fois.&lt;/p>
&lt;p>&lt;code>age&lt;/code> a remplacé tout ça. Une clé publique, une clé privée, zéro concept de keyring.
La clé privée tient sur une ligne. La clé publique aussi. C&amp;rsquo;est tellement simple
qu&amp;rsquo;on peut les stocker dans son gestionnaire de mots de passe.&lt;/p></description></item><item><title>zellij : pourquoi je n'ai jamais eu besoin de tmux</title><link>https://ftbx.fr/posts/zellij-pourquoi-je-nai-jamais-eu-besoin-tmux/</link><pubDate>Sun, 19 Jan 2025 00:00:00 +0000</pubDate><guid>https://ftbx.fr/posts/zellij-pourquoi-je-nai-jamais-eu-besoin-tmux/</guid><description>&lt;p>Je n&amp;rsquo;ai jamais utilisé &lt;code>tmux&lt;/code>. Pas par principe, juste parce que
quand j&amp;rsquo;ai commencé à chercher un multiplexer, &lt;code>zellij&lt;/code> est tombé
au bon moment.&lt;/p>
&lt;p>C&amp;rsquo;est contre-intuitif : tmux est plus réputé, plus ancien, installé
partout. Mais zellij a une qualité rare : il est utilisable sans
config. Pas de &lt;code>.tmux.conf&lt;/code> à écrire. Pas de préfixes bizarres à
mémoriser. Une barre d&amp;rsquo;état qui montre les onglets et les processus
en cours, sans plugin. Des raccourcis qu&amp;rsquo;on découvre en appuyant
sur &lt;code>Ctrl+G&lt;/code>.&lt;/p></description></item><item><title>GitLab CI resource_group : empêcher deux déploiements concurrents</title><link>https://ftbx.fr/posts/gitlab-ci-resource-group-empecher-deux-deploiements-concurrents/</link><pubDate>Wed, 15 Jan 2025 00:00:00 +0000</pubDate><guid>https://ftbx.fr/posts/gitlab-ci-resource-group-empecher-deux-deploiements-concurrents/</guid><description>&lt;p>Quand deux pipelines déploient sur le même environnement en parallèle,
le deuxième écrase le premier. Résultat : état incohérent, erreurs
de connexion, rollback en catastrophe.&lt;/p>
&lt;p>&lt;code>resource_group&lt;/code> règle ça proprement. Tu assignes un nom de groupe à
un job de déploiement. GitLab garantit qu&amp;rsquo;un seul job par groupe
s&amp;rsquo;exécute à la fois. Les autres attendent.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">deploy_staging&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">stage&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">deploy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">./deploy.sh staging&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">staging&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resource_group&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">staging&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Si deux pipelines arrivent en même temps sur &lt;code>deploy_staging&lt;/code>, le
premier s&amp;rsquo;exécute, le deuxième attend que le premier finisse. Pas
de lock manuel, pas de vérification Slack &amp;ldquo;qui déploie ?&amp;rdquo;.&lt;/p></description></item><item><title>direnv + .envrc : j'arrête de source des variables à la main</title><link>https://ftbx.fr/posts/direnv-envrc-jarrete-source-variables-e-a-main/</link><pubDate>Sun, 22 Sep 2024 00:00:00 +0000</pubDate><guid>https://ftbx.fr/posts/direnv-envrc-jarrete-source-variables-e-a-main/</guid><description>&lt;p>J&amp;rsquo;en avais assez de taper &lt;code>source .env&lt;/code> en entrant dans chaque projet. Et surtout
d&amp;rsquo;oublier de le faire une fois sur trois, et de perdre 10 minutes à comprendre
pourquoi la variable d&amp;rsquo;environnement n&amp;rsquo;était pas chargée.&lt;/p>
&lt;p>&lt;code>direnv&lt;/code> règle ça en un hook shell. Tu entres dans un dossier, il exécute
&lt;code>.envrc&lt;/code>. Tu en sors, il décharge tout. Plus rien à faire.&lt;/p>
&lt;p>Mais ce qui change tout, c&amp;rsquo;est quand on le combine avec un password manager en CLI (pour ma part &lt;code>rbw&lt;/code>) pour injecter les secrets automatiquement :&lt;/p></description></item><item><title>fzf + rg + fd : la trinité qui rend mon terminal plus rapide que l'explorateur</title><link>https://ftbx.fr/posts/fzf-rg-fd-a-trinite-qui-rend-mon-terminal-plus-rapide-que-explorateur/</link><pubDate>Sat, 03 Aug 2024 00:00:00 +0000</pubDate><guid>https://ftbx.fr/posts/fzf-rg-fd-a-trinite-qui-rend-mon-terminal-plus-rapide-que-explorateur/</guid><description>&lt;p>Trois outils. Chacun remplace un binaire POSIX vieux de 40 ans.
Ensemble, ils transforment le terminal en interface plus rapide
que n&amp;rsquo;importe quel explorateur graphique.&lt;/p>
&lt;p>Alors oui, c&amp;rsquo;est dans les vieux pots qu&amp;rsquo;on fait les meilleures soupe et si un binaire qui a 40 ans est toujours utilisé, c&amp;rsquo;est qu&amp;rsquo;il y a une bonne raison, mais là, ce serait dommage de se privée d&amp;rsquo;une UX shell bien léchée.&lt;/p>
&lt;p>&lt;strong>&lt;code>fd&lt;/code>&lt;/strong> remplace &lt;code>find&lt;/code>. Même usage, syntaxe humaine :&lt;/p></description></item><item><title>zoxide : j'ai remplacé cd et ma mémoire musculaire a survécu</title><link>https://ftbx.fr/posts/zoxide-jai-remplace-cd-ma-memoire-musculaire-a-survecu/</link><pubDate>Sun, 14 Jul 2024 00:00:00 +0000</pubDate><guid>https://ftbx.fr/posts/zoxide-jai-remplace-cd-ma-memoire-musculaire-a-survecu/</guid><description>&lt;p>&lt;code>zoxide&lt;/code> remplace &lt;code>cd&lt;/code> par un saut intelligent. Tu tapes &lt;code>z projet&lt;/code> et il
t&amp;rsquo;emmène dans le dossier &lt;code>projet&lt;/code>, même s&amp;rsquo;il est à 4 niveaux de profondeur.
Il apprend tes habitudes : plus tu vas souvent dans un dossier, plus il
le priorise.&lt;/p>
&lt;p>La commande s&amp;rsquo;appelle &lt;code>z&lt;/code>. Pas &lt;code>zoxide&lt;/code>, pas &lt;code>zoxide cd&lt;/code>. Juste &lt;code>z&lt;/code>.
Un alias &lt;code>alias cd=&amp;quot;z&amp;quot;&lt;/code> et ni vu ni connu !&lt;/p>
&lt;h3 id="setup">Setup&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Installer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo apt install zoxide &lt;span class="c1"># ou cargo install zoxide&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Ajouter à .zshrc / .bashrc&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">eval&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="k">$(&lt;/span>zoxide init zsh --cmd z&lt;span class="k">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># (Le --cmd z renomme la commande en &amp;#39;z&amp;#39; au lieu de &amp;#39;zoxide&amp;#39;)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="cheatsheet-zoxide">Cheatsheet zoxide&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Commande&lt;/th>
&lt;th>Équivalent cd&lt;/th>
&lt;th>Effet&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>z projet&lt;/code>&lt;/td>
&lt;td>&lt;code>cd ~/dev/machin/truc/projet&lt;/code>&lt;/td>
&lt;td>Va au dossier le plus utilisé contenant &amp;ldquo;projet&amp;rdquo;&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>z proj bidule&lt;/code>&lt;/td>
&lt;td>-&lt;/td>
&lt;td>Combine &amp;ldquo;proj&amp;rdquo; et &amp;ldquo;bidule&amp;rdquo; pour trouver&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>zi&lt;/code>&lt;/td>
&lt;td>-&lt;/td>
&lt;td>Interface interactive avec fzf&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>z -&lt;/code>&lt;/td>
&lt;td>&lt;code>cd -&lt;/code>&lt;/td>
&lt;td>Retour au dossier précédent&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>z ..&lt;/code>&lt;/td>
&lt;td>&lt;code>cd ..&lt;/code>&lt;/td>
&lt;td>Remonte d&amp;rsquo;un niveau&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Le &lt;code>zi&lt;/code> avec fzf est le plus utile : tu tapes &lt;code>zi&lt;/code>, tu scrolles dans ton historique,
tu choisis. Plus rapide que &lt;code>cd $(find . -type d | fzf)&lt;/code>.&lt;/p></description></item><item><title>glab CLI : gérer GitLab sans jamais ouvrir le navigateur</title><link>https://ftbx.fr/posts/glab-cli-gerer-gitlab-jamais-ouvrir-e-navigateur/</link><pubDate>Fri, 14 Jun 2024 00:00:00 +0000</pubDate><guid>https://ftbx.fr/posts/glab-cli-gerer-gitlab-jamais-ouvrir-e-navigateur/</guid><description>&lt;p>Quand tu gères 120 dépôts et que chaque action commence par
&amp;ldquo;ouvrir GitLab → Projects → chercher le projet → cliquer → &amp;hellip;&amp;rdquo;,
tu perds un temps fou. &lt;code>glab&lt;/code> remplace l&amp;rsquo;interface web pour
toutes les opérations courantes.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Installer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">brew install glab &lt;span class="c1"># macOS&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo apt install glab &lt;span class="c1"># Linux (ou télécharger le binaire)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Authentification (une fois)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">glab auth login
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="ce-que-jutilise-souvent">Ce que j&amp;rsquo;utilise souvent&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Créer une MR depuis la branche courante&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">glab mr create --title &lt;span class="s2">&amp;#34;Fix: pipeline timeout&amp;#34;&lt;/span> --assignee @me
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Lister mes MRs ouvertes&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">glab mr list --assignee @me
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Voir le statut d&amp;#39;une pipeline&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">glab ci status --branch main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Relancer un job spécifique&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">glab ci retry --job build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Lister les issues&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">glab issue list --label &lt;span class="s2">&amp;#34;bug&amp;#34;&lt;/span> --assignee @me
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Créer un snippet (partage de code rapide)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">glab snippet create fichier.py --title &lt;span class="s2">&amp;#34;Debug: race condition&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="le-combo-qui-tue-avec-git">Le combo qui tue avec git&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Créer une branche, commit, push, MR en une passe&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git checkout -b fix/timeout
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -am &lt;span class="s2">&amp;#34;fix: increase pipeline timeout&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push -u origin HEAD
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">glab mr create --fill &lt;span class="c1"># --fill utilise le message du commit comme titre&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="cheatsheet-glab">Cheatsheet glab&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Commande&lt;/th>
&lt;th>Équivalent UI GitLab&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>glab mr list -a @me&lt;/code>&lt;/td>
&lt;td>Merge Requests → Assignees → Moi&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>glab mr view 42&lt;/code>&lt;/td>
&lt;td>Ouvrir la MR #42&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>glab mr merge 42&lt;/code>&lt;/td>
&lt;td>Bouton &amp;ldquo;Merge&amp;rdquo;&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>glab ci status&lt;/code>&lt;/td>
&lt;td>CI/CD → Pipelines&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>glab ci trace&lt;/code>&lt;/td>
&lt;td>Logs du job en cours&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>glab release create 1.0&lt;/code>&lt;/td>
&lt;td>Deploy → Releases → New release&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>glab api projects/:id&lt;/code>&lt;/td>
&lt;td>API GitLab sans curl ni token&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;code>glab api&lt;/code> est la killer feature : tu appelles l&amp;rsquo;API GitLab directement
avec ton token géré par &lt;code>glab&lt;/code>. Plus besoin de &lt;code>curl -H &amp;quot;...&amp;quot;&lt;/code>.&lt;/p></description></item><item><title>.gitconfig includeIf : ma config Git différente selon le dossier</title><link>https://ftbx.fr/posts/gitconfig-includeif-ma-config-git-differente-selon-e-dossier/</link><pubDate>Sun, 26 May 2024 00:00:00 +0000</pubDate><guid>https://ftbx.fr/posts/gitconfig-includeif-ma-config-git-differente-selon-e-dossier/</guid><description>&lt;p>J&amp;rsquo;ai deux vies Git : une pro (Gitlab d&amp;rsquo;entreprise, email pro, clé SSH pro) et une
perso (GitHub perso, email perso, clé SSH perso). Avant d&amp;rsquo;utiliser ce qui suit, il m&amp;rsquo;est arrivé de devoir réécrire l&amp;rsquo;historique git parce que j&amp;rsquo;avais commit avec la mauvaise identité.&lt;/p>
&lt;p>&lt;code>includeIf&lt;/code> règle ça. On définit une config différente selon le chemin
du repo.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ini" data-lang="ini">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ~/.gitconfig&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">[includeIf &amp;#34;gitdir:~/dev/michelin/&amp;#34;]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">~/.gitconfig-michelin&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">[includeIf &amp;#34;gitdir:~/dev/perso/&amp;#34;]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">~/.gitconfig-perso&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Et chaque fichier ne contient que les différences :&lt;/p></description></item><item><title>GitLab CI coverage regex : pourquoi ta regex ne matche jamais</title><link>https://ftbx.fr/posts/gitlab-ci-coverage-regex-pourquoi-ta-regex-ne-matche-jamais/</link><pubDate>Mon, 08 Apr 2024 00:00:00 +0000</pubDate><guid>https://ftbx.fr/posts/gitlab-ci-coverage-regex-pourquoi-ta-regex-ne-matche-jamais/</guid><description>&lt;p>GitLab peut extraire le pourcentage de couverture de tests depuis les
logs du job et l&amp;rsquo;afficher dans le badge du projet, les MR, et l&amp;rsquo;UI.
Il suffit de définir une regex dans &lt;code>coverage:&lt;/code>. Et c&amp;rsquo;est là que tout
le monde se plante.&lt;/p>
&lt;h3 id="la-regex-qui-foire-systématiquement">La regex qui foire systématiquement&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># ❌ Ne matchera JAMAIS&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">job&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">pytest --cov&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">coverage&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;/TOTAL.*\s+(\d+%)$/&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Pourquoi ? &lt;code>$&lt;/code> veut dire &amp;ldquo;fin de ligne&amp;rdquo;. Mais les logs GitLab
sont collectés dans un buffer multi-lignes. La vraie fin de ligne
dans ce buffer, c&amp;rsquo;est la dernière ligne du log entier, pas la
ligne &lt;code>TOTAL&lt;/code>.&lt;/p></description></item><item><title>gitlab-ci-local : tester ses pipelines sans pousser</title><link>https://ftbx.fr/posts/gitlab-ci-local-tester-ses-pipelines-pousser/</link><pubDate>Fri, 08 Mar 2024 00:00:00 +0000</pubDate><guid>https://ftbx.fr/posts/gitlab-ci-local-tester-ses-pipelines-pousser/</guid><description>&lt;p>Pousser un commit juste pour tester un changement de &lt;code>.gitlab-ci.yml&lt;/code>,
c&amp;rsquo;est 30 secondes par tentative. Sur une pipeline un peu tordue,
20 essais. 10 minutes perdues à corriger des erreurs de syntaxe.&lt;/p>
&lt;p>&lt;code>gitlab-ci-local&lt;/code> exécute tes pipelines en local, avec Docker.
Tu modifies ton &lt;code>.gitlab-ci.yml&lt;/code>, tu lances &lt;code>gitlab-ci-local&lt;/code>, tu vois
les erreurs immédiatement. Zéro push, zéro attente de runner.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Installer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">npm install -g gitlab-ci-local
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Lancer tous les jobs du .gitlab-ci.yml courant&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gitlab-ci-local
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Lancer un job spécifique&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gitlab-ci-local --job build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Lister les jobs disponibles&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gitlab-ci-local --list
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="ce-que-ça-supporte">Ce que ça supporte&lt;/h3>
&lt;ul>
&lt;li>&lt;code>image&lt;/code>, &lt;code>services&lt;/code>, &lt;code>before_script&lt;/code>, &lt;code>script&lt;/code>, &lt;code>after_script&lt;/code>&lt;/li>
&lt;li>&lt;code>artifacts&lt;/code>, &lt;code>cache&lt;/code> (local, pas partagé)&lt;/li>
&lt;li>&lt;code>variables&lt;/code>, &lt;code>extends&lt;/code>, &lt;code>!reference&lt;/code>, &lt;code>needs&lt;/code>&lt;/li>
&lt;li>&lt;code>parallel:matrix&lt;/code> (partiellement)&lt;/li>
&lt;/ul>
&lt;h3 id="ce-que-ça-ne-supporte-pas">Ce que ça NE supporte PAS&lt;/h3>
&lt;ul>
&lt;li>&lt;code>trigger&lt;/code> (pipelines enfants)&lt;/li>
&lt;li>&lt;code>environment&lt;/code> (pas de déploiement réel)&lt;/li>
&lt;li>&lt;code>rules:if&lt;/code> avec des variables GitLab prédéfinies (&lt;code>$CI_COMMIT_BRANCH&lt;/code>)&lt;/li>
&lt;li>Runner tags, Kubernetes executor&lt;/li>
&lt;/ul>
&lt;h3 id="le-piège">Le piège&lt;/h3>
&lt;p>&lt;code>gitlab-ci-local&lt;/code> utilise Docker pour exécuter les jobs. Si ton job
fait référence à &lt;code>$CI_REGISTRY_IMAGE&lt;/code> ou &lt;code>$CI_JOB_TOKEN&lt;/code>, ces variables
n&amp;rsquo;existent pas en local. Il faut les définir manuellement :&lt;/p></description></item><item><title>Proxmox qm : les 5 commandes qui évitent l'interface web</title><link>https://ftbx.fr/posts/proxmox-qm-es-5-commandes-qui-evitent-interface-web/</link><pubDate>Sun, 11 Feb 2024 00:00:00 +0000</pubDate><guid>https://ftbx.fr/posts/proxmox-qm-es-5-commandes-qui-evitent-interface-web/</guid><description>&lt;p>L&amp;rsquo;interface web de Proxmox est propre. Mais quand on gère plus de 10 VMs et qu&amp;rsquo;on veut automatiser, la CLI est 10 fois plus rapide. Voilà les 5 commandes
&lt;code>qm&lt;/code> que j&amp;rsquo;utilise au lieu de cliquer.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. Lister les VMs avec leur état&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">qm list
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. Démarrer / arrêter / redémarrer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">qm start &lt;span class="m">100&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">qm stop &lt;span class="m">100&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">qm reboot &lt;span class="m">100&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. Ouvrir une console série (comme le bouton &amp;#34;Console&amp;#34; dans l&amp;#39;UI)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">qm terminal &lt;span class="m">100&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 4. Cloner une VM (template → VM fonctionnelle en 30 secondes)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">qm clone &lt;span class="m">9000&lt;/span> &lt;span class="m">101&lt;/span> --name &lt;span class="s2">&amp;#34;ma-vm&amp;#34;&lt;/span> --full
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 5. Modifier une option sans ouvrir l&amp;#39;UI&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">qm &lt;span class="nb">set&lt;/span> &lt;span class="m">100&lt;/span> --memory &lt;span class="m">8192&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">qm &lt;span class="nb">set&lt;/span> &lt;span class="m">100&lt;/span> --cores &lt;span class="m">4&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">qm &lt;span class="nb">set&lt;/span> &lt;span class="m">100&lt;/span> --net0 virtio,bridge&lt;span class="o">=&lt;/span>vmbr0
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="le-combo-qui-automatise-tout">Le combo qui automatise tout&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Cloner un template cloud-init, personnaliser, démarrer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">qm clone &lt;span class="m">9000&lt;/span> &lt;span class="m">200&lt;/span> --name &lt;span class="s2">&amp;#34;k8s-worker-3&amp;#34;&lt;/span> --full
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">qm &lt;span class="nb">set&lt;/span> &lt;span class="m">200&lt;/span> --sshkey ~/.ssh/id_ed25519.pub
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">qm &lt;span class="nb">set&lt;/span> &lt;span class="m">200&lt;/span> --ipconfig0 &lt;span class="nv">ip&lt;/span>&lt;span class="o">=&lt;/span>10.0.0.203/24,gw&lt;span class="o">=&lt;/span>10.0.0.1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">qm start &lt;span class="m">200&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Les 5 commandes à retenir : &lt;code>list&lt;/code>, &lt;code>start&lt;/code>, &lt;code>stop&lt;/code>, &lt;code>clone&lt;/code>, &lt;code>set&lt;/code>.
Avec ça, on fait 90% de ce qu&amp;rsquo;on fait dans l&amp;rsquo;interface web, sans
toucher la souris.&lt;/p></description></item><item><title>shell set -euo pipefail : l'option qui m'a sauvé 100 heures de debug</title><link>https://ftbx.fr/posts/shell-set-euo-pipefail-option-qui-ma-sauve-100-heures-debug/</link><pubDate>Sun, 05 Nov 2023 00:00:00 +0000</pubDate><guid>https://ftbx.fr/posts/shell-set-euo-pipefail-option-qui-ma-sauve-100-heures-debug/</guid><description>&lt;p>&lt;code>set -euo pipefail&lt;/code> devrait être la première ligne de tout script shell
non trivial après le shebang.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="nb">set&lt;/span> -euo pipefail
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Voilà pourquoi :&lt;/p>
&lt;p>&lt;strong>&lt;code>set -e&lt;/code>&lt;/strong> : le script s&amp;rsquo;arrête à la première commande qui échoue.
Sans ça, le script continue comme si de rien n&amp;rsquo;était après un &lt;code>cd /tmp/inexistant&lt;/code>.
J&amp;rsquo;ai perdu des heures à comprendre pourquoi un &lt;code>rm -rf&lt;/code> s&amp;rsquo;exécutait
dans le mauvais dossier à cause d&amp;rsquo;un &lt;code>cd&lt;/code> silencieusement raté.&lt;/p></description></item></channel></rss>