Quelques enseignements essentiels après 20 ans en ingénierie logicielle

Lorsque j’ai commencé ma carrière en tant qu’ingénieur logiciel il y a vingt ans, je n’aurais jamais pu imaginer l’évolution incroyable que notre domaine allait connaître. L’industrie des technologies de l’information a constamment progressé dans des directions variées, de l’émergence des méthodologies agiles à l’essor du cloud computing, en passant des applications monolithiques aux architectures microservices, et parfois même un retour en arrière. Malgré ces changements permanents, j’ai découvert que certains principes fondamentaux ont su résister à l’épreuve du temps. Ces leçons sont aujourd’hui encore plus pertinentes dans un environnement de plus en plus complexe en ingénierie logicielle.Dans ce billet, je vais partager dix enseignements cruciaux que j’ai tirés au cours de mes 20 années de carrière. Ces principes m’ont aidé à naviguer dans de nombreux projets, à diriger des équipes, et à progresser professionnellement. J’espère qu’ils vous offriront des perspectives essentielles et un regard neuf sur notre métier. 1. Évitez l’optimisation prématurée On se souvient tous de la célèbre citation de Donald Knuth : « L’optimisation prématurée est la source de tous les maux (ou du moins la plupart) en programmation. » Au début de ma carrière, je suis tombé dans le piège de l’optimisation prématurée plus souvent que je ne voudrais l’admettre. J’ai passé des semaines à développer un système de gestion de documents pour des millions d’utilisateurs, pour ensuite découvrir que nous avions à peine un millier de visiteurs par mois. J’ai aussi mis en place des modèles d’accès aux données très sophistiqués pour prendre en charge plusieurs bases de données, alors que seules deux ou trois étaient réellement utilisées.Cela m’a enseigné une leçon importante : il est inutile de construire des abstractions complexes si vous n’allez pas les utiliser. Concentrez-vous sur l’écriture de code simple qui répond aux besoins actuels.L’optimisation prématurée peut mener à des solutions surdimensionnées, plus difficiles à maintenir et à comprendre. Suivre les principes  YAGNI (You Ain’t Gonna Need It) KISS (Keep It Simple, Stupid) DRY (Don’t Repeat Yourself)  dans cet ordre est crucial. Implémentez seulement ce qui est nécessaire au moment où vous en avez besoin.Garder le code simple et clair est essentiel. Quant à la répétition, elle est parfois inévitable dans certains cas, par exemple, lorsqu’une logique partagée est utilisée dans différents contextes. 2. Réfléchissez avant d’écrire du code En tant qu’ingénieurs, nous avons tendance à penser que tous les problèmes se résolvent avec du code. Pourtant, au fil des ans, j’ai appris que parfois la meilleure solution ne nécessite pas de code supplémentaire.Avant d’ajouter une nouvelle fonctionnalité, demandez-vous : « Est-ce vraiment nécessaire ? Peut-on résoudre ce problème sans ajouter du code ? » Chaque ligne de code que vous écrivez devient une responsabilité : elle devra être maintenue, testée, et potentiellement déboguée.N’oubliez pas que votre objectif est de résoudre des problèmes et de créer de la valeur, et non pas simplement de coder. Parfois, la solution la plus efficace et la plus simple consiste à écrire moins de code, voire pas du tout. Réfléchissez donc deux fois avant d’écrire une seule ligne ! 3. Adoptez de bonnes pratiques Tout au long de ma carrière, j’ai constaté qu’adhérer aux bonnes pratiques améliore la qualité du code, la productivité de l’équipe, et le taux de réussite des projets. Cependant, j’ai aussi appris qu’appliquer ces pratiques de manière aveugle, sans comprendre leur contexte, pouvait s’avérer contre-productif.Quand je parle de bonnes pratiques, je fais référence à : Clean Code : Suivez les principes du livre « Clean Code » de Robert C. Martin pour écrire un code plus lisible et maintenable. Toutefois, ne les appliquez pas aveuglément, certaines idées vieillissent mieux que d’autres. Les Design Patterns : Comprenez les modèles de conception et appliquez-les de manière adéquate. Ne les forcez pas là où ils ne sont pas nécessaires, sous peine de rendre votre projet inutilement complexe. Les principes SOLID : Ils permettent de rendre votre code plus modulaire et maintenable, mais, là encore, ne soyez pas trop rigide dans leur application. L’idée n’est pas de suivre ces pratiques de manière rigide, mais plutôt de comprendre quand et comment les utiliser de manière judicieuse. (Single Responsibility) Principe de responsabilité unique : Une classe ou un module ne doit avoir qu’une seule raison de changer, ce qui signifie qu’il ne doit avoir qu’un seul travail ou responsabilité. (Open-Closed) Principe d’ouverture-fermeture : Les entités logicielles doivent être ouvertes à l’extension mais fermées à la modification, permettant d’étendre leur comportement sans modifier le code existant. (Liskov Substitution) Principe de substitution de Liskov : Les objets d’une superclasse doivent pouvoir être remplacés par des objets d’une sous-classe sans affecter la validité du programme. (Interface Segregation) Principe de ségrégation des interfaces : Les clients ne doivent pas être obligés de dépendre d’interfaces qu’ils n’utilisent pas ; les interfaces doivent être spécifiques aux besoins des clients. (Dependency Inversion) Principe d’inversion des dépendances : Les modules de haut niveau ne doivent pas dépendre des modules de bas niveau ; les deux doivent dépendre d’abstractions plutôt que d’implémentations concrètes. 4. Simplifiez toujours plus « Faites les choses aussi simples que possible, mais pas plus simples. » Cette citation souvent attribuée à Albert Einstein m’a toujours guidé dans la conception logicielle.Lorsque vous construisez ou concevez un logiciel, ne le compliquez pas inutilement. Optez pour des solutions faciles à comprendre. Le monde du logiciel est déjà suffisamment complexe ; il n’est pas nécessaire d’ajouter davantage de complications.La simplicité a de nombreux avantages : Un code simple est plus facile à lire, à comprendre et à maintenir. Les systèmes simples comportent moins de points de défaillance. La simplicité permet un développement plus rapide et un débogage facilité.Bien entendu, il faut trouver un juste équilibre entre simplicité et fonctionnalité. Ne sacrifiez pas les fonctionnalités nécessaires sous prétexte de vouloir garder les choses trop simples. 5. Nommez correctement Phil Karlton a dit : « Il n’y a que deux choses vraiment difficiles en informatique : l’invalidation du cache et nommer les choses. » J’ai appris à quel point cela est vrai.Bien nommer les éléments dans votre code a un impact énorme. Cela réduit la charge cognitive…

Onyx Solution – Une Mini-Formation sur l’Architecture Logiciel

Onyx Solution https://github.com/YannVasseur35/Onyx Onyx Solution Une solution Microsoft .net 7.0 / C# permettant l’apprentissage de concepts de software design, d’architecture, de clean code, de tests… Permet de partir sur de bonnes bases pour un petit/moyen projet, basé sur quelques années d’expériences dans le software design. Onyx est une pierre précieuse de couleur noire. J’ai donnée ce nom à ce projet d’apprentissage car il est court, facilement identifiable, abstrait, et j’aime bien donner des « noms de code » à un projet. On va prendre comme exemple une application de météo (qui est d’ailleurs l’exemple par défaut d’une application .net web) on aura donc Une API qui expose des données une base de données SQLite avec EntityFramwork (code first) Une clean architecture avec de nombreux tests + code coverage CI/CD avec une pipeline AzureDevops Introduction On a tous commencé par écrire un seul projet c# et tout mettre dedans, sans vraiment rien structurer. Alors oui, ça marche et honnêtement vu les ambitions de cette app méteo c’est ce que l’on devrait faire. Et puis comme tout bon projet, il évolue, en quelques années tout un tas de nouvelles fonctionnalités se sont ajoutés, plusieurs devs sont passés dessus, avec du code plus ou moins clair. De plus avec le temps, l’infrastructure a changé, on a fait évoluer la base de données, certain services sont directement sur le cloud et on a du faire face à de la montée en charge. On a du « scaler » l’application, recoder des parties, ajouter du cache etc…Et bien entendu rien n’est testé automatiquement. Bref la vie d’une application dans pas mal de boite en France et ailleurs dans le monde. Je développe avec .net depuis plus de 20 ans. Et j’ai vu un certain nombre d’application (un bon paquet à vrai dire) finir dans ce que l’on appelle un « monolith legacy », très très dure à maintenir. Ces applications existent encore à l’heure ou j’écris ces lignes. Parfois on en est au deuxième projet de « refonte ». Un cas typique est celui du projet ou l’on retrouve toute la logique métier dans les procédures SQL. Car c’est ce qui faisait vraiment gagner en pref à l’époque (et encore aujourd’hui). Mais seule la personne en charge de ces procédures stockées, souvent indéchiffrable et intestable, est en mesure de travailler dessus. Autre cas bancale, on a de la logique métier dans les pages web. Du coup on se retrouve à gérer à plusieurs endroits, du code qui fait plus ou moins la meme chose, au risque qu’un jour il ne fasse plus la même chose ! Heureusement aujourd’hui on a énormement plus de techniques, d’outils et de services qui permettent d’appréhender les projets autrement. Les entreprises comprennent les enjeux et les risques de garder trop longtemps du code legacy en production et s’engagent dans de gigantesque chantier de « renovation » voir même de ré-écriture complète. J’ai moi aussi contribuer à ces erreurs et je contribue aussi à leurs résolutions. Ce projet tente modestement de répondre à certaines problématiques couramment vues en entreprise. Je ne prétends pas tout résoudre mais apporter quelques réponses à des questions que moi même je me suis posé. Et à vrai dire, le meilleurs moyen d’y répondre pour moi est de tenter de le faire comprendre à quelqu’un d’autre. J’ai donc entrepris ce projet Onyx. Progression Vous avez deux façons de voir les choses : la rapide. Restez sur la branche master, la plus à jour et dernière en date. Vous avez tout le code source et tous les tests. Regardez le code et inspirez-en vous, prennez ce qui vous intéresse. l’apprentissage. Ce sera plus lent, mais j’explique tous les concepts pas à pas. On démarre gentillement et on progresse par étape (step). C’est une sorte de TP (travaux pratique) qu’on faisait à l’école. Pour suivre ce TP il faudra « naviguer » avec Git de branche en branche. C’est simple, toutes les branches s’appellent ‘step’ suvit d’un numéro. Chaque step aura sa propre doc (ex: step2.md). Suffit de s’y référer pour comprendre ce qu’y a été fait à chaque étape. Sommaire Step1 : Structure de solution Step2 : Premier endpoint Api Step3 : Test endpoint Api Rest Step4 : Application Service et Tests Step5 : DataService et Tests Step6 : Mapping et Tests Step7 : ORM (Entity Framework) et Tests Step8 : Entity Framework Step9 : Finalisation de la chaine de données Step10 : Code Coverage Step11 : CRUD : Implémentation et Tests Step12 : Tests d’intégration Step13 : CI/CD AzureDevops Pipeline Step14 : Pipeline avec Code Coverage Git Repo : https://dev.azure.com/ReactorLab/_git/Onyx Vous devrez connaitre quelques commandes git de base très simple pour « naviguer » dans les branches de ce repo. Pour changer de branche : git checkout step1 Si vous avez fait des modifications et que vous souhaitez changer de branche, git va vous obliger à faire un commit ou à vous débarraser de ces changements. Comme vous ne contribuez pas au projet, débarrassez vous de vos changements avec la commande stash, puis faites votre checkout git stash git checkout step2 Documentations Annexes Vous trouverez des informations complémentaires sur différents concept d’architecture ici (en anglais): Main Architecture Hexagonal Architecture DDD CQRS AND ES SOLID Tout est dans le répertoire docs.

DKIM SPF, le WTF sur MX

Si vous avez vous aussi des problèmes pour envoyer des emails à des boites Gmail depuis votre boite pro, et que vous avez un message de retour comme ceci, Mail Delevery System This is the mail system at host mo536.mail-out.ovh.net. I’m sorry to have to inform you that your message could not be delivered to one or more recipients. It’s attached below. For further assistance, please send mail to postmaster. If you do so, please include this problem report. You can delete your own text from the attached returned message. The mail system <ape.crevin@gmail.com>: host gmail-smtp-in.l.google.com[74.125.206.27] said: 550-5.7.26 This mail is unauthenticated, which poses a security risk to the 550-5.7.26 sender and Gmail users, and has been blocked. The sender must 550-5.7.26 authenticate with at least one of SPF or DKIM. For this message, 550-5.7.26 DKIM checks did not pass and SPF check for [outquest.fr] did not 550-5.7.26 pass with ip: [51.210.91.12]. The sender should visit 550-5.7.26 https://support.google.com/mail/answer/81126#authentication for 550 5.7.26 instructions on setting up authentication. v7-20020adfebc7000000b00307774d73a8si474631wrn.1056 – gsmtp (in reply to end of DATA command)   alors vous êtes au bon endroit. Cependant , je vais pas m’étendre sur le sujet car, c’est relou, ya 2 pellos qui viendront lire cet article, et surtout je pense que ca va être automatisé d’ici peut de tps.  Outil de test Voici deux liens qui permettent de comprendre ce qu’il se passe https://www.mail-tester.com/ Cet outil permet d’avoir pas mal d’info sur votre serveur mail, il m’a permit de debuger le SPF  https://toolbox.googleapps.com/apps/checkmx/ Ce dernier permet de voir comment Google voit les choses… mais en fait je pense qu’il aide pas bcp, je mets ça là…  Ma config J’ai un service email chez OVH (Email Pro), mais mon Register DNS est ailleurs (PlanetHoster) et pour le moment je veux pas changer car mon dns outquest.fr est gratuit à vie chez eux.  Faut savoir qu’à mon avis, si on a tout chez OVH, DNS et MX ça doit se faire tout seul… mais en vrai j’en sais rien.    SPF Voici la ligne supplémentaire que j’ai ajouté à mon DNS TXT 14400 outquest.fr.  « v=spf1 include:_spf.google.com include:mx.ovh.com ~all » Honnêtement je pige pas trop ce que ça fait, ni même si la partie google n’est pas de trop (je pense qu’elle est de trop) mais bon, ça à l’air de marcher alors je touche plus à rien.  DKIM DKIM c’est un échange de clé privé/public pour vérifier que vous envoyer bien du serveur officiel (outquest.fr pour moi) et que vous n’êtes pas un usurpateur (spammer) Pour ce faire, chez OVH ya toute une procédure ici  https://help.ovhcloud.com/csm/fr-dns-zone-dkim?id=kb_article_view&sysparm_article=KB0058101#pour-e-mail-pro Lisez bien toutes les petites lignes et faites gaffe la doc est pas toujours à jour et l’API en beta… Donc faut faire qq manipulation directement via l’API d’OVH https://api.ovh.com/console/#/email/pro à l’étape 3, le status va être à « Todo », puis passer à « waitingRecord » au bout de qq minutes.  Faites l’étape 4 en attendant. Celle ci consiste à rajouter une entrée DNS, qui elle même va mettre du temps à se propager (d’où le status « waitingRecord ») à l’étape 5 ou vous dit qu’il faut attendre que ce status passe à « ready ». Donc revenir à l’étape 3 et retenter de tps en tps jusqu’à obtenir un status « ready ».       Etape 1 [« ovhemp1076131-selector1″ »ovhemp1076131-selector2 »] Etape 2 Etape 3 après qq minutes, le status passe de todo à waitingRecord Etape 4 Pour passer à l’étape 5, il faut que l’état status soit « ready ».  J’ai cru à un délais de propagation lent du CNAME, mais deux jours plus tard, c’était autre chose.  Alors le support d’OVH m’a gentillement répondu qu’il me manquait un point dans mon CNAME. Voici la cible à utiliser :ovhemp1076131-selector1._domainkey.2370.ad.dkim.mail.ovh.net Voici la cible que j’ai configuré :ovhemp1076131-selector1._domainkey2370.ad.dkim.mail.ovh.net. Le targetRecord reçu de l’API est donc faux. Par contre la doc est ok. Donc si on a pas l’oeil, c’est tendu…  Après changement j’ai refais l’étape 3 : { customerRecord: « ovhemp1076131-selector1._domainkey.outquest.fr » header: « from;to;subject;date » lastUpdate: « 2023-06-13T16:34:35+00:00 » recordType: « CNAME » selectorName: « ovhemp1076131-selector1 » status: « ready » targetRecord: « ovhemp1076131-selector1._domainkey2370.ad.dkim.mail.ovh.net » taskPendingId: 0 } Etape 5 On y est, ce coup ci l’API nous renvoit qq chose qui ressemble à la doc.  Résultat En refaisant un test email avec https://www.mail-tester.com/ j’obtiens un score de 8.2/10 (7/10 avant). Ma DKIM est bien configurée.

Gestion des emails avec WooCommerce , Licence Manager WC et SendinBlue

Constat : J’ai un site e-commerce basé sur wordpress avec un plugin WooCommerce.  Pour mes besoins j’ai ajouté un autre plugin « Licence Manager for WooCommerce ». Ce dernier me permet de générer une clé de licence lors d’un achat d’un produit numérique. Comme un jeu vidéo.  On peut automatiser l’envoi de cette clé au moment ou la commande passe dans le statut « terminé » (order completed) Ceci est activable avec l’option coché ci dessous (dans WooCommerce – Réglage – Onglet Gestionnaire de licences) Ce qui nous envoi cet email, après avoir commandé un produit (numérique). On reçoit donc bien notre clé de licence (MRY-VVY)    Besoins J’aimerais pouvoir cutomiser cet email. Le rendre plus joli déjà, mais surtout ajouter un lien vers mon application avec la clé en paramètre pour démarrer le jeu directement, sans que l’utilisateur n’ait à écrire lui même cette clé de licence.  J’ai contacté un dev du plugin, il a pas su me répondre et pourrait éventuellement inclure cette fonctionnalité dans une prochaine version (inchallah) Donc on va se débrouiller sans et le faire nous même. Les fichiers emails WooCommerce est un plugin qui embarque des templates d’emails par défault.  Si l’on souhaite les cutomiser, il faut les recopier dans le path de votre theme.  Pourquoi ? Car si vous modifiez directement les fichiers dans le répertoire du plugin, ils seront effacés lors de la prochaine mise à jour et vous allez devoir remodifier ceux la.  En recopiant le template d’email dans le path de votre theme, vous sauvegarder celui ci, même apres une mise à jour du plugin. Cependant, ceci ne garantit pas une compatibilité futur. Gardez à l’esprit qu’un jour, ça peut merder… De même, Licence Manager for WooCommerce est un plugin. Il a aussi ses templates d’emails par défaut.  Le code Le fichier qui m’intéresse est le suivant : lmfwc-email-customer-deliver-license-keys.php Et le bout de code suivant affiche la clé de licence dans l’email.  <td class="td" style="text-align: left; vertical-align: middle; font-family: ‘Helvetica Neue’, Helvetica, Roboto, Arial, sans-serif;" colspan="<?php echo ($license->getExpiresAt()) ? ‘1’ : ‘2’; ?>"> <code><?php echo esc_html($license->getDecryptedLicenseKey()); ?></code> </td> Donc à ce stade, je n’ai plus qu’une ligne à rajouter :   <?php $key = $license->getDecryptedLicenseKey(); echo "<a href=’http://game.outquest.fr/activation/$key’>Avec le téléphone qui va servir à jouer, cliquez sur ce lien</a>"; ?> Sauvegardez vos modifs et placer le fichier  lmfwc-email-customer-deliver-license-keys.php dans le repertoire  /wp-content/themes/{votre-Theme/woocommerce/emails/ Notez que c’est pas : /wp-content/themes/{votre-Theme/license-manager-for-woocommerce/emails/   Voici le résultat par email  SendinBlue SendinBlue est la plateforme par laquelle je passe pour envoyer mes emails. J’ai commencé avec une simple newsletter sur ma landing page.  Ensuite j’ai demandé à SendinBlue de gérer aussi l’envoi des email de confirmation de commande effectué.  Cela permet de déléguer l’envoi à une société spécialisé (moins de risque de spam, quand c’est bien fait) mais aussi d’avoir tout un tas de données marketing (ouverture du mail, clic, call to action etc..) Une fois qu’on a autorisé SendinBlue à envoyer tout nos emails,il va légérement modifier tous les liens pour les tracer.  Par exemple, le lien ci dessus était http://game.outquest.fr/activation/XXX-XXX Et devient :  https://dfjfdhi.r.af.d.sendibt2.com/tr/cl/9TxMauVboi221d-fV6iZOAOP-8Gjao1SU9XET3Lz8pl3S_15GogAHUQ0qMN_vwJXGJKZdFP3dVXOD91R4fgkGwgS-luPEmKwSZjQZd5mIWPpQbjhKvaNxdSfY_uwHjdvsFZdi0Ph5juUWKPmNXRAM8DpsuSUiFj-AiL6tBjes4JoG2Xgih98xhgNLY1Mj-LsrmCC1_48j7MxwfvKjHoNAaZ7lRwfiiySLJxNKoRa6K0crle9dt9nfbSx6MwDnOCWGKU     Gestion des emails par SendinBlue Je vous passe l’installation du plugin SendinBlue sur wordpress. Ya dla doc en ligne. Ouvrir le menu WooCommerce – Sendinblue et cliquer en haut a droite sur réglage. On se retrouve sur le backoffice de SendinBlue. Donc celui gère notre site qq part. Allez dans la section Emails Options : et coché la case : Ensuite, je suis plus sûr de moi. J’ai coché ceci : C’est un peu obscure, mais en cochant la case de « Completed Order » mes emails de résumé de commandes partent.  Sinon je ne les reçois plus. Scénario SendinBlue   Pour les besoins de mon jeu, je voudrais envoyer un email supplémentaire pour informer l’utilisateur du déroulement du jeu. Pour cela SendinBlue propose des « Workflows » automatisé. En voici un concernant la commande terminé : Ici est représenté les séquences du workflow, lorsque qu’un évenement de type « order_completed » est détecté, on attend 1 minute (le minimum, je sais pas pourquoi faut absolument attendre…) et on envoit l’email « Email de début du jeu Quête Salamandre »‘ que j’ai au préalable configuré.  Et voila, une minute plus tard, en plus du précédent email, je reçois celui ci :   Pour aller plus loin Pour moi l’idéal serait que lien d’activation se trouve dans le second email.  Ceci implique d’inclure cette clé de licence dans les paramètres géré par sendinblue, lors de la construction de l’email.  Car lors de la création de l’automatisation d’un workflows sur un évenement commande terminé (ou produit acheté) je me suis vu proposé un template par défaut : qui présente des infos de la commande.  Si j’avais en plus qq chose comme {{params.licenceKey}} je serais en mesure de finir cet email.

Signoz et OpenTelemetry avec une app .net sous linux

Disclamer A l’heure ou j’écris cet article, le code source d’OpenTelemetry et Signoz sont en alpha/beta/pre-release.  Certaine lib sont en release officielle. J’édite au fur et à mesure certaine infos. Le code évolue et cet article aussi.  Il n’est certainement plus « à la page » lorsque vous lirez ces ligne.  Et de même, la doc officielle, celle de Microsoft et les ReadMe des repos ne sont pas tous mis à jours en temps et en heure.  C’est un sujet chaud pattate !!! Besoins Comme d’habitude, j’écris un article avec un vrai besoin et une application dans la vraie vie.  J’ai un serveur en prod et je souhaite le monitorer pour : observer son comportement (nombre de requêtes, % de CPU/RAM/Disk, periode d’activité/repos etc) analyser des problèmes, avoir accès aux logs sans ouvrir un terminal être alerté en cas de problème et pouvoir définir ces alertes avoir une vue d’ensemble avec des KPI de base   Contexte Depuis peu (qq années) on a la possibilité de faire tourner du .net sous linux. Ca change quoi allez vous me dire ?  Personnelement une question de coût. Un VPS (virual private server) sous linux c’est au moins deux fois moins cher que sous Windows (ça dépend avec quel fournisseur et les prix ont aussi évolué dans le temps). Mais aujourd’hui un VPS linux est utlra compétitif. Et j’ai pas de besoin cloud (même si j’y pense). Avec Windows on était habitué à installer des outils graphiques supplémentaires. Et meme de base on avait des outils de monitoring. Sous linux, c’est moins évident car on utilise principalement la ligne de commande. Et personnellement j’y retrouve pas mon compte. Même si on peut aussi mettre une interface graphique, c’est pas le but d’un serveur. Enfin, je voudrais pouvoir consulter ceci sans me loguer en ssh (depuis une interface web) et avoir des alertes email et sms serait top.  Actuellement je développe un nouveau produit (https://outquest.fr). Celui ci comporte un site web (game) et un site backoffice (qg). Le site officiel (outquest.fr) et le shop sont hébergés ailleurs (planethoster). J’ai une prod et un staging. (donc 4 site webs au final). J’ai commencé avec un serveur low cost à 2.99€/mois (Debian, 1 core,  2 Go Ram, 25Go SSD …) chez Ikoula. Franchement à ce prix la, ça marche bien pour faire tourner 4 sites webs.(avec que moi dessus hein !) Ces 4 sites web tournent sous 4 services kernel (autorestart) linux et géré par un serveur web frontal NGinx.  –> pour la config voir cet article J’ai de plus une CI/CD géré par azure devops (voir article Azure Devops) qui me permet via des pipelines de deployer automatiquement mon code sur les serveurs web respectif à chaque push git sur mes branches dev et master.  Ca a dla gueule ! Pour un mec tout seul (pour le moment) je sors la grosse artillerie. J’aurais pu partir direct avec un site web en prod et debuger dessus à l’ancienne. Mais j’aime bien apprendre à faire les choses bien :). Et justement, pour faire bien, la prochaine étape c’est le monitoring des serveurs (ya aussi les backups, je pense que j’en ferai un article à part).  Du coup j’ai voulu tester une solution qui me paraissait pas mal, un APM (Application Performance Management) : CheckMK.  Le souci c’est que j’ai vu trop gros (ce machin permet de gérer tout un parc informatique, plusieurs serveurs, node, kubernetes…) Et en l’installation, le machin à fait fondre mon serveur. Plus moyen d’y accéder pendant un temps et pas moyen de le redémarrer (j’ai contacté le support, ce qui m’a pris plusieurs jours, à ce prix la fallait pas attendre des miracles.) Le bon moment pour passer à un niveau supérieur.  A ce stade j’avais ma prod et mon staging sur la meme petite bécanne. Du coup je me dis qu’il faudra quand meme passer sur qq chose de plus sérieux pour la prod. J’ai donc opté pour un VPS OMGServ avec cette config :  Et une option payante supplémentaire de backup. (snapshots) CheckMK tourne déjà beaucoup mieux, mais comme je le disais c’est pas une solution pour moi. Ca install une bardé de trucs dont Apache2, qui fout la merde avec mon Nginx.  Après qq recherches, je suis tombé sur Signoz et OpenTelemetry. Et c’est ce qu’il me faut !   Signoz   Signoz est une interface web permettant de visualiser un ensemble de données sur votre serveur linux.  C’est une solution Open Source, récente et encore en dev. C’est un concurrent à DataDog (payant).  Elle permet de monitorer des applications et de fournir des éléments pertinents pour les devops.  Cette solution naît d’un constat. Les équipes techniques sont frustrées d’utiliser pleins d’outils différents provenants de sources de données elles aussi différentes pour voir leurs logs/metrics/traces …   De plus les outils existants sont « lourds », taillé pour de la grosse boite (faut bien vendre) avec des standards propriétaires et non générique.  Je n’ai pas de recul suffisant mais mon sentiment c’est que c’est compliqué et qu’un outil simple, uniformisé gratuit et open source manquait à ce niveau pour un niveau « intermediaire » (PME, TPME, indé) Un standard est en train d’émerger concernant toute ces données que l’on appelle OpenTelemetry. OpenTelemetry Encore un nouveau framework ? C’est quoi, une couche de plus ? OpenTelemetry c’est une collection d’outil, d’APIs et de SDKs permettant de mesurer, generer, collecter et exporter des données de télémetrie (metrics, logs et traces) afin de mieux analyser le comportement et les performances de nos applications.  Super mais qui porte le truc ? Est ce que c’est un projet qui va être adopté ? Oui, en tout cas par Microsoft : https://learn.microsoft.com/en-us/azure/azure-monitor/app/opentelemetry-overview Vu l’investissement de Microsoft pour les projets à succès Open Source, et vu le besoin, je pense qu’OpenTelemetry a de l’avenir.  Installer Signoz Il existe plusieurs façon d’installer Signoz, j’ai choisi pour ma part la version Standalone (https://signoz.io/docs/install/docker/) sur mon VPS linux Debian 11. Vous devrez télécharger le repo git : git clone -b main https://github.com/SigNoz/signoz.git puis vous rendre dans le répertoire suivant :…

Package Blazor

Communauté Même si j’expose pas mal de trucs au reste du monde (articles, démo, tutos…) j’ai jamais vraiment « contribué » à la communauté via des projets open source. Jusqu’à peu.  Faut bien commencer 🙂 En vrai, je m’en faisais tout une montagne. Pour moi faire un package nuget était compliqué. J’avais tord. En fait ça n’a rien de compliqué. Ce qui est vraiment chaud, c’est de gérer la maintenance et « animer » la communauté (répondre aux questions, faire un readme, corriger etc.) Blazor Je travaille sur un projet avec la techno Blazor depuis quelques mois. Je kiffe.  C’est un projet WASM. Donc qui utilise la WebAssembly. Pour moi c’est le futur. Je pense qu’on va vite se passer de Javascript d’ici 5 ans. Personnellement j’en ai plein le cul de ce language. Par contre respect, il a contribué à rendre nos app web carrément plus sympas.  Et donc on peut pas encore s »en passer vraiment, car l’essentiel des supers libs d’aujourd’hui son écrite en JS. Même si certain éditeur commence à sortir des versions WebAssembly. Mais c’est encore trop rare.  Donc faut encore faire avec. Et Blazor permet de faire un pont entre notre code C# et Javascript.  Ok certain vont me dire, à quoi ça sert, autant tout faire sur du JS. Oui. Mais sans moi, pour les raisons du dessus. Donc moi je veux faire du C#. Alors comment faire ? Faut coder un wrapper qui va nous servir d’intermediaire.  Mon premier package nuget J’avais besoin d’un lecteur de QR code dans mon appli. J’ai cherché et j’ai rien trouvé sur le gestionnaire de package Nuget. Alors j’ai décidé de faire le mien. Et puis je me suis dit que ce serait sympas de le partager. Et ça donne ça : Repo Github : https://github.com/YannVasseur35/ReactorBlazorQRCodeScanner Package Nuget : https://www.nuget.org/packages/ReactorBlazorQRCodeScanner/ Création d’une librairie Blazor La première chose à faire est de créer un nouveau projet « Bibliothèque de classes Razor » Si on ouvre le fichier projet, voici ce que j’ai  <Project Sdk= »Microsoft.NET.Sdk.Razor »> <PropertyGroup> <TargetFramework>net6.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup> <ItemGroup> <SupportedPlatform Include= »browser » /> </ItemGroup> <ItemGroup> <PackageReference Include= »Microsoft.AspNetCore.Components.Web » Version= »6.0.11″ /> </ItemGroup> </Project> Composition d’une lib razor (blazor) Voici un exemple de projet vide : Si on analyse une lib razor, voici ce qu’on y trouve : Component1.razor C’est votre composant visuel qui sera afficher dans vos pages. Suffira d’appeler <Component1/> dans votre page razor. Il affichera un cadre par défaut. A vous de customiser votre composant pour qu’il affiche ce que vous voulez qu’il affiche.  ExampleJsInterop.cs Comme son nom l’indique, c’est un exemple de ce que vous pouvez faire à minima avec du code C# qui utilise du javascript. Dans son contructeur : private readonly Lazy<Task<IJSObjectReference>> moduleTask; public ExampleJsInterop(IJSRuntime jsRuntime) { moduleTask = new(() => jsRuntime.InvokeAsync<IJSObjectReference>( « import », « ./_content/RazorClassLibrary1/exampleJsInterop.js »).AsTask()); } On voit que ça charge un fichier js. Notez aussi le chargement « Lazy » qui va permet de ne charger les éléments de notre lib qu’au moment où c’est nécessaire.  https://learn.microsoft.com/en-us/aspnet/core/blazor/webassembly-lazy-load-assemblies?view=aspnetcore-7.0 Donc quelque part, si vous n’utilisez pas le composant dans vos premières pages, il ne sera pas chargé (téléchargé pour le client). S’en suis dans le code une seule méthode : public async ValueTask<string> Prompt(string message) { var module = await moduleTask.Value; return await module.InvokeAsync<string>(« showPrompt », message); } Ici on nous présente un méthode très simple pour afficher un prompt JS. On appelle, via module.InvokeAsync la méthode javascript « showPrompt » et on lui passe un paramètre « message ».  exampleJsInterop.js export function showPrompt(message) { return prompt(message, ‘Type anything here’); } Le code JS est super simple. On lance un prompt tout bête avec le message qu’on a en paramètre. Voilà pour la présentation d’un composant blazor.  Intégration Maintenant que l’on a un composant blazor on va l’utiliser dans notre app web WASM.  Suffit d’ajouter une référence de projet dans notre projet client. ensuite dans une page, par exemple index.razor, on ajoute ceci :  @page « / » @using RazorClassLibrary1 <Component1 /> Visuellement ça donnera ceci : Ajoutons un peu de code à notre page pour jouer avec un bouton : @page « / » @using RazorClassLibrary1 @inject IJSRuntime _jSRuntime <Component1/> <button onclick= »@Show() »>Click me</button> @code{ private ExampleJsInterop? _exampleJsInterop; protected override void OnInitialized() { _exampleJsInterop = new ExampleJsInterop(_jSRuntime); } protected async Task Show() { await _exampleJsInterop.Prompt(« coucou »); } } On vient de lancer du js avec du C#. Scanner de QR Code. Pour revenir à mon besoin initiale, je dois pouvoir scanner un QR Code. Ya pas encore de lib nuget mais y’en a quelques une sous javascript, dont jsQR https://github.com/cozmo/jsQR La lib peut faire plein de chose, moi j’ai besoin de récuperer que la lecture du code QR. Pour cela j’ai ajouté une Action (delegate) à mon composant pour que lorsque le JS trouve un QR code et arrive à le lire, cela déclanche (un Invoke) une méthode dans mon code. Le but n’est pas de décrire comment j’ai fait, le code source est dispo ici : https://github.com/YannVasseur35/ReactorBlazorQRCodeScanner J’ai bossé comme avec le précendent projet, en « local » à savoir que mon projet « lib blazor » est ajouté à mon projet blazor client.  Pour que ce soit plus simple, pour moi et pour le reste du monde, il faudrait faire un package nuget et l’importer depuis nuget.org   Le Package Et c’est la que je me faisait tout une montagne (alors que c’est plus simple que de publier une app Android ou pire Apple). Il suffit de taper une commande : dotnet pack Et c’est tout 🙂 Bien entendu il faut aussi donner quelques informations sur le package. Ceci est fait dans le fichier projet de la bibliothèque de classe razor. Voici ce que j’ai mis pour mon package de scan de QR code. <Project Sdk= »Microsoft.NET.Sdk.Razor »> <PropertyGroup> <TargetFramework>net6.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> <PackageId>ReactorBlazorQRCodeScanner</PackageId> <Version>1.0.5</Version> <Authors>Yann Vasseur</Authors> <Company>reactor.fr</Company> <PackageTags>Blazor;Reactor;QRCode;ScannerQR Code</PackageTags> </PropertyGroup> <ItemGroup> <SupportedPlatform Include= »browser » /> </ItemGroup> <ItemGroup> <PackageReference Include= »Microsoft.AspNetCore.Components.Web » Version= »6.0.4″ /> </ItemGroup> </Project> Et bim on a un fichier ReactorBlazorQRCodeScanner.1.0.5.nupkg dans votre bin/debug Push sur nuget.org Pour publier en ligne, il vous faut un compte sur nuget.org. Ensuite il va vous falloir une clé api. https://www.nuget.org/account/apikeys Quand c’est fait, il restera une étape, taper cette commande (dans le dossier ou se trouve votre package) dotnet nuget push…

WooCommerce – configurations avancées (partie 3)

Intro Cet article fait suite aux articles : https://reactor.fr/un-site-e-commerce-en-moins-dune-heure  https://reactor.fr/woocommerce-configurations-avancees https://reactor.fr/woocommerce-configurations-avancees-partie-2/ J’ai reussi à couvrir 99% de mes besoins. Un utilisateur peut s’acheter une licence de jeu OutQuest. Le souci, c’est qu’il doit copier une clé de licence sur mon appli. J’aimerais un lien qui lui permette de ne pas le faire. Vu que mon app mobile est un site web, il devrait être simple de rediriger l’utilisateur vers mon site en cliquant sur cette clé de license. (ou un lien que j’aurais fait). Sauf que ca ne se fait pas par défaut. Les concepteurs du plugins me l’ont confirmé, ce n’est pas une fonctionnalité, ça le sera peut être un jour, inchallah. Autre besoin, même si j’ai cet email, ou que l’utilisateur saisie manuellement cette clé de licence sur mon app, comment je vérifie celle ci ? C’est l’objet de ce post. API Licences Manager for Woo Commerce Donc l’idée c’est de faire une requête depuis mon app (ou depuis n’importe où finalement) vers mon site web de e-commerce qui gère ces clés de licences. Le plugin précédément installé qui gère ces licences a justement une gestion par une API de ces clés. Dans les réglages de WooCommerces, Onglet « Gestion de licences » en base de page, on a la possibilité de gérer individuellement chaque endpoint de l’API. Le lien de la documentation est celui ci https://www.licensemanager.at/documentation/rest-api/#api-keys La première chose que l’on nous demande c’est de passer nos liens en permaliens. Dans un précédent article nous avons déjà fait cette manipulation et d’ailleurs je ne souvenais plus pourquoi je devais le faire… ba c’est pour l’API de gestion de licences. Ensuite il nous faut générer une clé d’API que l’on utilisera dans chacune de nos requêtes. Pensez à stocker ces clés car elles ne vous seront plus accessible par la suite. Ca y est notre API est prête ! L’API lmfwc (Licence Manager for Woo Commerce) est situé dans ce path par defaut : https://shop.outquest.fr/wp-json/lmfwc/ Si vous ne faites pas la modification des permaliens vous aurez une 404. Ensuite il faut rajouter la route de l’api que l’on souhaite, par exemple https://shop.outquest.fr/wp-json/lmfwc/v2/licenses/sdf Qui demande la clé « sdf » (qui n’existe pas). J’ai cette réponse 401 Unauthorized : { « code »: « lmfwc_rest_authentication_error », « message »: « Clé client ou secrète manquante. », « data »: { « status »: 401 } } J’utilise une extension Visual Studio Thunder Client (c’est comme Postman) qui me permet de faire des requêtes sur mesure. Il faut paramétrer une authorisation « Basic » avec username = clé client et password = clé secrète. En relancant la requête on obtient ceci : { « code »: « lmfwc_rest_data_error », « message »: « License Key: sdf could not be found. », « data »: { « status »: 404 } } On nous indique une 404 car la clé de licence « sdf » n’existe pas. Essayons maintenant avec une vraie clé : https://shop.outquest.fr/wp-json/lmfwc/v2/licenses/LBL-JVP { « success »: true, « data »: { « id »: 1, « orderId »: 40, « productId »: 29, « userId »: 1, « licenseKey »: « LBL-JVP », « expiresAt »: null, « validFor »: 0, « source »: 1, « status »: 2, « timesActivated »: null, « timesActivatedMax »: 0, « createdAt »: « 2022-09-30 16:00:10 », « createdBy »: 1, « updatedAt »: « 2022-09-30 16:00:10 », « updatedBy »: 1 } } Bingo on obtient nos informations de licence ! L’api lmfwc dispose de 3 autres endpoints en get : licenses/validate/ licenses/activate/ licenses/deactivate/ La première vous donne ce type de réponse : { « success »: true, « data »: { « timesActivated »: 0, « timesActivatedMax »: 0, « remainingActivations »: 0 } } En faisant une requete avec licenses/activate { « success »: true, « data »: { « id »: 1, « orderId »: 40, « productId »: 29, « userId »: 1, « licenseKey »: « LBL-JVP », « expiresAt »: null, « validFor »: 0, « source »: 1, « status »: 2, « timesActivated »: 1, « timesActivatedMax »: 0, « createdAt »: « 2022-09-30 16:00:10 », « createdBy »: 1, « updatedAt »: « 2022-10-10 13:04:29 », « updatedBy »: 1 } } puis en refaisant licenses/validate on obtient : { « success »: true, « data »: { « timesActivated »: 1, « timesActivatedMax »: 0, « remainingActivations »: -1 } } Notez qu’on a eu +1 sur timesActivated. Cela permettra de voir si la licence est utilisé plusieurs fois et éventuellement travailler sur de l’anti fraude. en utilisant licenses/deactivate on fait l’opération inverse. API Woo Commerce On vient de voir comment valider une licence. Le souci c’est qu’à ce stade, je n’ai qu’un numéro orderId et un productId. Je pourrais me démerder avec cela si je rentre en dur, coté application les références produits. Seulement si un jour je change de produit ca ne fonctionnera plus. Comment faire ? Il faut requêter l’API Woo Commerce, tout simplement. De la même manière on va devoir générer des clés d’API dans l’onglet « avancé » des réglages de Woo Commerce. Notre requête devra aussi avoir une authorisation basique avec ces clés. Le path api est wp-json/wc/ Voici une requête pour obtenir des informations sur la commande 40 :https://shop.outquest.fr/wp-json/wc/v2/orders/40 { « id »: 40, « parent_id »: 0, « status »: « completed », « currency »: « EUR », « version »: « 6.9.4 », « prices_include_tax »: true, « date_created »: « 2022-09-30T18:00:07 », « date_modified »: « 2022-09-30T18:00:10 », « discount_total »: « 0.00 », « discount_tax »: « 0.00 », « shipping_total »: « 0.00 », « shipping_tax »: « 0.00 », « cart_tax »: « 0.17 », « total »: « 1.00 », « total_tax »: « 0.17 », « customer_id »: 1, « order_key »: « wc_order_Px8132TVZef0E », « billing »: { « first_name »: « Yann », « last_name »: « Vasseur », « company »: «  », « address_1 »: « 2 la en face », « address_2 »: «  », « city »: « Partis », « state »: «  », « postcode »: « 35580 », « country »: « FR », « email »: « xxxxxxx@yahoo.fr », « phone »: « 06 66 66 6 6 6 » }, « shipping »: { « first_name »: «  », « last_name »: «  », « company »: «  », « address_1 »: «  », « address_2 »: «  », « city »: «  », « state »: «  », « postcode »: «  », « country »: «  », « phone »: «  » }, « payment_method »: « woocommerce_payments », « payment_method_title »: « Carte de crédit/carte de débit », « transaction_id »: « pi_3LnldEFq94z7RR2d10UTj3Te », « customer_ip_address »: « 79.95.127.132 », « customer_user_agent »: « Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 », « created_via »: « checkout », « customer_note »: «  », « date_completed »: « 2022-09-30T18:00:10 », « date_paid »: « 2022-09-30T18:00:10 », « cart_hash »: « 7c45d164e8db4f049f791a4cb6bfeded », « number »: « 40 », « meta_data »: [ { « id »: 645, « key »: « is_vat_exempt », « value »: « no » }, { « id »: 646, « key »: « _payment_method_id », « value »: « pm_1LnldCFq94z7RR2dn0VFdrDP » }, { « id »: 647, « key »: « _stripe_customer_id », « value »: « cus_MWiJXN4eXAa94X » }, { « id »: 648, « key »: « _wcpay_mode », « value »: « test » }, { « id »: 649, « key »: « _intent_id », « value »: « pi_3LnldEFq94z7RR2d10UTj3Te » }, { « id »: 650, « key »: « _charge_id », « value »: « ch_3LnldEFq94z7RR2d1CxGKYWX » }, { « id »: 651, « key »: « _intention_status », « value »: « succeeded » }, { « id »: 652, « key »: « _wcpay_intent_currency », « value »: « EUR » }, { « id »: 662, « key »: « lmfwc_order_complete », « value »: « 1 » }, { « id »: 663, « key »: « _wcpdf_invoice_settings », « value »: { « display_shipping_address »: «  », « display_customer_notes »: « 1 », « display_date »: « order_date », « header_logo »: « 19 », « header_logo_height »: «  », « shop_name »: { « default »: « Outquest » }, « shop_address »: { « default »: « 2 la basrn35580 Paris » }, « footer »: { « default »: «  » }, « extra_1 »: { « default »: «  » }, « extra_2 »: { « default »: «  » }, « extra_3 »:…

WooCommerce – configurations avancées (partie 2)

Intro Cet article fait suite à l’article https://reactor.fr/un-site-e-commerce-en-moins-dune-heure qui est une introduction à Woo Commerce et à son installation. On part donc avec un site WordPress qui a un plugin WooCommerce, un plugin WooCommerce Payments et un theme Virtue. Cet article fait aussi suite à celui la https://reactor.fr/woocommerce-configurations-avancees et je rappelle les besoins : Cet article va traiter des spécifications dont j’ai besoin pour mon site Ouquest. Je souhaite : permettre l’achat d’un jeu part Carte Bancaire / Paypal (fait dans le précédent article) envoyer une facture automatiquement après achat envoyer une clé de license permettant de jouer à un jeu Outquest forcer la quantité à 1 (on achète 1 licence pour 1 jeu)  (fait dans le précédent article) permettre de mettre en place des produits « Bientôt disponible » visible mais pas achetable.  (fait dans le précédent article) Facture PDF Je voudrais envoyer une facture automatiquement au client. J’utilise le plugin suivant :  WooCommerce PDF Invoices & Packing Slips Une fois installé et activé, j’ai changé qq settings, comme l’ajout d’un logo, le nom et l’adresse de la boutique. Ya un assistant qui vous aide.  J’ai choisi d’ajouter un PDF facture à chaque mail concernant une nouvelle commande Et voila, lorsqu’une commande est effectué, l’utilisateur reçois un email comme d’habitude, mais avec un PDF de facture en plus. C’est plus pro ! Clé de licence Le but de ce site e-commerce c’est de permettre l’achat d’un jeu sur OutQuest qui est réalisé via une app mobile.  Il faut donc pouvoir vérifier que l’achat effectué permet de jouer ou pas.  Pour cela j’utilise un autre plugin qui permet de gérer des licences. Comme un jeu vidéo !  Ce plugin c’est License Manager for WooCommerce  Une fois activé on peut se rendre dans les réglages de WooCommerce qui propose un nouvel onglet « Gestion de licences ». J’ai juste coché la case  Une clé de licence peut prendre plusieurs forme, souvent on voit une suite de lettres et de chiffres espacé de tiret comme ceci JHDS-OZINB-5DDF-97SF Pour faire cela, on va utiliser un générateur de clé, dans le menu WooCommerce – Générateurs. On en ajoute un : Je veux une clé facile à retenir pour pouvoir la mémoriser et l’écrire ensuite sur une app par exemple.  Mon format c’est XXX-XXX donc 3 lettres, tiret, 3 lettres. Ca représente 26 ^6 soit plus de 300 millions de combinaisons. Large, je suis pas Ubisoft. La carte des caractères c’est l’ensemble des caractères possible que vous souhaitez voir dans cette clé de licence. J’y ai mis que des lettres. C’est simple et surtout ça évite les confusions de type O 0, I 1, etc…  On enregistre. Et normalement c’est tout bon.  Par default, la livraison d’une commande se fait sur un état terminé. Ca nous servira plus tard.  Automatiquement, à l’installation du plugin, ça doit rajouter une ligne dans Email de WooCommerce ce qui va nous permettre de joindre la clé de licence directement dans l’email de confirmation de commande. (commande terminée) Il faut modifier notre produit pour qu’il gère une clé de licence. Un nouvel onglet est disponible.  Il faut cocher « Vendre des clés de licence pour ce produit ». Quantité 1.  Générer des clés de licence avec le générateur que l’on vient de paramétrer. Maintenant si on passe une commande, on verra une nouvelle ligne dans le résumé de la commande et aussi dans l’email de confirmation de commande. Page web Email : Problème des produits Virtuels et Téléchargeables. Je ne voulais pas parler de cette option avant pour éviter toute confusion. Mais maintenant cela a son importance.  Lorsque vous créer un produit, vous avez la possibilité de le déclarer Virtuel et/ou Téléchargeable.  Dans mes précédentes commande, j’ai un produit qui a les deux : Pourquoi ?  Car en faisant cela, lorsqu’un utilisateur finalise sa commande, le statut de la commande passe à « Terminé ». Et rappellez vous, le plugin ajoute la licence dans l’email sur ce statut.  Or si on ne coche pas « Téléchargeable », la commande de ce produit sera « en cours »  Et donc la license ne sera pas incluse ! Moi je coche la case Téléchargeable car pour moi c’est une commande terminé.  Mais l’autre option c’est de rajouter un statut « En cours » dans les settings de la licence (non testé)

WooCommerce – configurations avancées

Cet article fait suite à celui la https://reactor.fr/un-site-e-commerce-en-moins-dune-heure qui est une introduction à Woo Commerce et à son installation. On part donc avec un site WordPress qui a un plugin WooCommerce, un plugin WooCommerce Payments et un theme Virtue. Cet article va traiter des spécifications dont j’ai besoin pour mon site Ouquest. Je souhaite : permettre l’achat d’un jeu part Carte Bancaire / Paypal envoyer une facture automatiquement après achat envoyer une clé de license permettant de jouer à un jeu Outquest forcer la quantité à 1 (on achète 1 licence pour 1 jeu) permettre de mettre en place des produits « Bientôt disponible » visible mais pas achetable. Processus d’achat A ce stade, comment se passe le processus d’achat pour l’utilisateur ? Pour le moment la page d’accueil liste un ensemble de produit disponible à la vente. Chaque produit dispose de sa propre page détail.  L’utilisateur est invité à cliquer sur « Ajouter au Panier » ce qui permet, comme indiqué de rajouter le produit dans le panier.  Me concernant, les joueurs ne feront qu’un seul achat, donc je voudrais directement rediriger l’utilisateur vers la page « Validation de Panier », celle ci : Pour rediriger l’utilisateur directement vers la page panier après achat, il faut cocher la case suivante dans la section Produit des réglages de WooCommerce. J’aimerais aussi ne pas afficher le selecteur de quantité pour cela, il faut se rendre dans la page configuration du produit, données produit, Inventaire et cocher la case suivante : Payments Mode Test Avant toute chose, on va démarrer en mode « Test » pour rendre fictif le paiement. Cela permettra de valider le processus avec une carte banquaire bidon. Pour cela, rendez vous dans les réglages de WooCommerce section Paiements et cocher la case ci dessous. Lorsque l’utilisateur valide son panier il arrive sur une page qui lui demande ses informations personnelles nécéssaires pour editer une facture avec les éléments obligatoires légaux.  Ensuite la page résume la liste des produits du panier, affiche la TVA et le total. Si tous les champs sont corrects, au clic sur le bouton commander, l’utilisateur est rediriger vers une page validation de commande avec toutes les informations concernant son achat. De plus un email est automatiquement expédié à l’utilisateur lui validant sa commande. Un autre email est expédié à l’adresse email de l’administrateur de WooCommerce lui indiquant qu’une commande vient d’être effectuée. TVA Vous avez peut etre remarqué une erreur dans le screenshot ci dessus, la TVA est à 0%. C’est pas normal. (enfin ça se discute hein ! ) La solution pour cela est d’activer l’option des taxes automatiques dans les options de TVA dans les réglages de WooCommerce. Le problème (dans mon cas) c’est que ca bloque l’edition des tarifs TTC, on est obligé de saisir les tarrifs en HT.  Cependant, le fait de mettre cette option, puis de l’enlever (remise à default) à débloquer ce pb de TVA à 0%. Note :  J’ai travaillé sur 2 sites WooCommerce, un pour faire mes tests et un autre pour ma prod. Je rédige cet article en mettant en place la production (shop.outquest.fr) progressivement. Et je m’appercois que je n’ai pas les memes comportements vis à vis de cette TVA. (j’ai mis a jour depuis sur une version WooCommerce, c’est peut être lié) Ce que j’ai fait dans le didactel c’est d’abord constuire mes produits, puis changer ma méthode d’application de la TVA (HT à TTC) ensuite. Or, on a ce petit encart qui nous informe que cela n’impactera pas les produits existants.  Dans les faits, ça change rien. J’ai testé sur un « ancien » produit et un produit que j’ai fait apres ces changements. La ou ca change c’est au moment de faire les calculs, sur la page panier par exemple. (un produit anciennement à 1€ HT à qui faut rajouter 0.20€ de TVA devient un produit à 1€ TTC qui comprends la TVA) Donc pour un produit vendu 1€ TTC, j’ai un produit HT à 0.83€ (et pas 0.80€) et donc une TVA à 0.17€. (20% de 0.83€) C’est un « calcul à l’envers » qui est « bizarre » si on essai de calculer sur cette page les taxes. Cependant et c’est le but de cette façon de faire, c’est d’afficher les tarifs TTC.  Donc quand on affiche 1€, c’est 1€ pas 1.20€ au final.  C’est personnel, mais je suis toujours un peu déçu quand j’arrive sur une page qui me dit qu’en fait le prix que tu as vu avant c’était HT. Quand on est consomateur c’est frustrant. Si j’étais acheteur dans le privé, j’aurais mis HT bien entendu.  Mais par défaut, les prix sont affichés en HT. Il faut changer l’option dans les réglages de TVA : <– avant HT après TTC –> Pour Simplifier la lecture, je simplifie les tarifs sur la page panier et commande avec des tarifs TTC Voici au final ce que ça donne. Simple, clair.  La TVA est inscrite discrètement, c’est pas pour dissimuler, mais tout le monde sait qu’il y a de la TVA… Note : je ne sais pas ce qui s’est passé, mais depuis que j’ai fait la section suivante, les prix TTC ne sont plus affichés. Donc c’est pas stable st’histoire.  J’ai joué avec les réglages, en passant et repassant des fonctionalités « on/off », c’est presque redevenu normal. Sauf que j’ai plus de TVA. Fait chier ! Après une pause (d’énervement) j’ai trifouillé qq options dont « Disable automated taxes » et pouf, ca remarche… Produit indisponible J’ai besoin d’un moyen d’afficher des produits mais qui ne sont pas encore disponible à la vente. Ca permet de préparer le terrain et d’informer l’utilisateur que de nouveaux circuits vont être disponibles. Pour cela je vais utiliser un plugin (en fait 2, on verra plus tard pourquoi) qui va me permettre d’afficher ceci  Ce plugin permet de rajouter une bulle « Bientôt Disponible » sur l’image principale. Ce plugin c’est Coming Soon Badge for WooCommerce Une fois installé et activé, ce plugin vous propose tout un tas de customisation.  Il faut activer la fonctionalité par produit dans l’encart « Publier » du produit. Sympas…

Un site e-Commerce en moins d’une heure.

Pourquoi faire ? Pour vendre un bien numérique (un circuit d’OutQuest), j’ai besoin d’un site e-commerce qui me gère la partie vente.   Qui dit vente, dit emmerdes. Oui car on va devoir gérer des profils (user data, email nom prénom, adresse, tel etc) qui aujourd’hui sont sous le coup de lois (RGPD) et on a pas le droit de faire n’importe quoi avec. Et c’est normal. Mais pour ceux qui code un peu, cette partie est un gros morceau. (sécurité, intégrité, disponibilité…)   De plus on va demander un ou des moyens de paiements, enregistrer des commandes, gérer des factures, des remboursements et pour certain des stocks (et des ruptures de stocks), des bons de réduction etc. Coder une platerforme e-commerce est un boulot de dingue.   Mais heuresement on a des développeurs qui l’on fait déjà fait, et propose des solutions gratuites !!! Je vous aime, chères collègues !   J’ai testé WooCommerce, qui pour l’instant couvre 99% de mes besoins WooCommerce kick ass Le e-Commerce, c’est pas nouveau. Je dirais meme que les solutions sont c’est hyper matures. Woo Commerce en est une. J’ai pas été voir les autres, ni même tenté une étude de marché.  J’ai installé WooCommerce pour testé. Et j’ai couvert 99% de mes besoins. Il me manque un tout petit %, dont je parlerai en fin d’article.  Je vous montre ici une installation de woo commerce + plugins + skin pour mes besoins qui seront peut être les votres aussi.   La base Avant toute chose, il vous faut un nom de domaine et un site wordpress hébergé qq part.  Moi ça sera https://shop.outquest.fr Première chose à faire, modifier les réglages principaux avec vos données : N’oubliez pas de confirmer votre adresse email si vous la changez.   Ensuite il faut installer le plugin WooCommerce.   puis on l’active :, on passe alors à la configuration du site e-commerce.    Config On commence par des informations de base concernant votre site, pas vraiment utile que je détaille ceci ici. On vous demandera de choisir le type de produit. Prendre les deux, c’est un choix qui vous permettra de vendre différent type de produit, au moment d’en créer un. Enfin, on vous propose par défault quelques options complémentaires : Accepter les cartes de crédit et autres méthodes de paiement populaire avec WooCommerce Payments.  C’est un plugin spécial WooCommerce développé par WooCommerce Une fois installé, il va gérer tout ce qui concerne les paiments, les remboursements, les méthodes de paiement (stripe, pay pal…), l’intégration de ceux ci sur votre site web.  WooCommerce Tax, utile si vous vendez dans différents pays.  JetPack : utilitaire très connus qui fait plein d’optimisation MailPoet : je connais pas bien, je teste Google Listing & Ads : pas encore testé Facebook pour WooCommerce : pas encore testé     Pour finir, on nous demande de choisir un theme. Personnellement j’ai choisi le thème « Virtue » qui ne figure pas dans la liste qui vous est proposé. Si vous voulez le même suffit d’aller l’installer manuellement dans la section « theme ». Si vous avez opté pour l’option JetPack, on vous demandera de connecter votre compte JetPack sur votre site.    Mise en route Ca y est votre site e-commerce est configuré. Par défaut, votre site web ressemble à cela. On a un thème par defaut, aucun produit, rien a montrer à part une page principale afficher un pauvre article. Ca reste du WordPress from scratch.  A partir de maintenant, les screenshots suivant seront prit avec le theme Virtue. La page d’accueil ressemble à ça : L’interface d’admin de wordpress vous propose de commencer à alimenter votre site web Vous pouvez suivre toutes les étapes une à une. C’est un bon moyen de démarrer. A tout moment vous pouvez reprendre cette mise en route en cliquant sur Accueil du menu WooCommerce: Réglage apparence Note: vous n’êtes pas obliger de régler maintenant l’apparence, d’autant plus qu’en fin de configuration on vous propose de le faire.  Comme un site wordpress classique, il faut paramétrer un minimum pour démarrer. Cela concerne la home page et les menus. Dans mon cas l’apparence du site est basé sur un theme « Virtue » donc pas certain que vous ayez les memes options. Ce que je veux afficher sur ma home page c’est un logo, un menu et une liste de produit.  Insérer un logo se fait via l’assistance de personnalisation dans « réglage principaux » Pour mettre une liste de produit à la place d’un article de base, il faut se rendre dans « Réglages de la page d’accueil »   et modifier en page statique et choisir  « boutique » Dans la section Apparence – Menu sur l’admin wordpress, j’ai crée un menu comme ceci :  Pour au final un look qui ressemble à ça : Ce qui permet de naviguer sur nos produits et voir le détail d’un produit sur une page dédiée. Ajout de produits Depuis le didactel, choisir « ajouter un produit manuellement dans le cas d’une petite boutique ». Sinon Il existe un menu spécial produit :  On va rapidement créer un premier produit « Quête des Vallons de la Vilaine » qui sera notre premier produit numérique que l’on souhaite vendre. On va lui donner un nom, une description et une image. (on pourra mettre plus d’une image plus tard). Le cadre suivant est très important, c’est ici que l’on détermine quel type de produit et à quel tarif.  On commence par un tarif peu élevé de 1€ que l’on changera plus tard. Cela nous permettra de faire notre premier « auto achat » pour tester. En évitant de payer des impots et taxes inutiles.  On y reviendra plus tard. On publie notre premier produit. Et on en profite pour en faire un ou deux de plus, ce qui nous permettra de comparer plus tard quelques fonctionnalités intéressantes.   WooCommerce Payments On vient d’ajouter nos produits, on avance sur les paiements C’est pas la partie la plus simple. Mais c’est celle qui a été la plus simplifié depuis qq années. En gros ce plugin va nous faciliter. la…

Azure Devops

Qu’est ce qu’Azure Devops ? A quoi ça sert ? Comment l’utiliser ?  Je vais tenter d’expliquer par l’exemple et l’expérience ce que l’on peut faire avec Azure Devops Un bref historique Il est l’héritier de plusieurs anciens outils. Si je remonte loin on a VSS (visual source safe) qui était le svn de Microsoft, un gestionnaire de code source. Ensuite on a eu Team Foundation Server qui était un peu plus sérieux, on commençait à voir des outils annexes comme un board avec des work items. Git étant devenu une référence, Microsoft s’est adapté et a la intégré sur toutes ses plateformes. On a eu aussi VS Online (Visual Studio Online) et dans le même temps Microsoft rachetait HockeyApp qui deviendra App Center (spécialisé dans l’application mobile). C’est indépendant, mais j’imagine que demain tout ne fera qu’un. Et puis est né Azure Devops. Tout ça pour dire qu’il est pas arrivé comme ça. C’est le fruit d’années d’évolution et de savoir faire.   Azure Devops est gratuit.  Azure Devops est multi projets, multi utilisateurs, … voir ici pour le limites A quoi ça sert ? Alors qu’on soit bien clair, Azure Devops n’est pas indispenable… jusqu’à ce qu’on s’en serve… Azure Devops c’est une plateforme web qui regroupe plusieurs gros services : Board : un outil qui permet de créer des work items et de les organiser suivant des méthodes agile (scrum, kanban) Repos : un repo git, où l’on peut y voir les commits, pushes, branches, tags, pull requests Pipelines : orchestrateur automatique. Permet de lancer des « scripts » yaml et d’automatiser notre chaine de livraison continue.  Test Plans : La section test. Artefacts : ce que vous aller produire se retrouve ici.  Les deux derniers, j’en parlerai pas, je connais pas bien. Les 3 premiers sont des supers outils, ils sont liés.  En premier lieux on va utiliser Board pour s’organiser, créer des tâches et les répartir aux membres de l’équipe. Bien entendu il nous faut un repos Git. Ils nous permet de gérer notre code source. Enfin, quand le projet avance, on ajoute de l’automatisation pour que notre chaine de livraison continue fonctionne toute seule.  Comment l’utiliser ? Pour cela j’ai écris 9 articles qui se focalise sur la chaine de livraison/déploement continue CI/CD 1 – Première pipeline, On y apprend à faire un build tout simple : Azure Devops Pipeline (CI/CD) – First Build 2 – Deploiement via SSH Azure Devops Pipeline (CI/CD) – Deploy 3- Versioning Azure Devops Pipeline (CI/CD) – Versioning 4- Gestion des environnements Azure Devops Pipeline (CI/CD) – Environnement Azure Devops Pipeline (CI/CD) – Relancer les services 5- Git Flow Azure Devops – Git Flow intro 6- Pull Request Azure Devops – Pull Request Azure Devops – Pull Request (part 2) Voilà, j’espère que ça pourra servir à quelqu’un 🙂 

Azure Devops – Pull Request (part 2)

Cet article est la suite de https://reactor.fr/azure-devops-pull-request/ On avait créé des règles de branche sur la master : interdiction d’effacer cette branche pas de git push direct sur cette branche règle de Pull Request (light) Ceci nous permet de sécuriser la branche master. Faisons de même avec la branche develop. Rappels Git Flow On a vu la PR develop –> master.  Maintenant, on va ajouter une PR sur chaque commit vers la branche develop. Si on applique Git Flow, on aura une branche feature qui devra à un moment livrer son contenu sur la develop.  La PR intervient à ce moment.  Règle de branche develop sur Azure Devops On va donc fairre un clic sur le menu de la ligne représentant la branche develop dans Repos – Branches, puis on sélection "Branch Policies" Pour la branch dévelop, j’ai rajouté plus de contraintes que la master. En effet je veux qu’en premier lieu chaque commit sur la branch dévelop corresponde à un work item. Ensuite si il y a une intervention d’un reviewer, celle ci doit être résolut par un commentaire. Dans la pratique ça peut simplement être une question qui ne demande pas vraiment d’intervention. Mais ça peut aller jusqu’à ce que le reviewer demande un refacto voir refuse carrément le code (c’est rare…) Je limite aussi le type de merge afin d’avoir un historique lisible et en cohérence avec la branche master. Ensuite j’ajoute une règle de build. Je sélectionne une nouvelle Pipeline que je viens de juste de crée : pool: vmImage: ubuntu-latest variables: buildConfiguration: ‘Release’ projectBlazorWasmServer: ‘src/BlazorDemo/BlazorDemo/Server/BlazorDemo.Server.csproj’ steps: # Publish Blazor Demo Server – task: DotNetCoreCLI@2 displayName: Publish inputs: command: publish publishWebProjects: false projects: ‘$(projectBlazorWasmServer)’ arguments: ‘–configuration $(buildConfiguration) –output $(build.artifactstagingdirectory)’ zipAfterPublish: false modifyOutputPath: false La seule différence avec l’autre pipeline de build, c’est que je ne précise pas le trigger. En effet, je ne connais pas le nom de la branche feature. Donc par défault ce sera la source de la PR concernée. Mise en situation Mon tech lead m’a affecté une tâche. On va aller la créer pour la simuler, normalement elle est déjà existante : Je suis développeur, je dois donc créer une branche si elle n’existe pas déjà. Sut mon terminal je tape : git checkout -b feat/LoginPage Je développe, quand j’ai fini : git add . git commit -m « mon travail sur la page login » git push –set-upstream origin feat/LoginPage Je peux bien évidement avoir plusieurs commit et/ou avoir d’autre commit d’autre développeurs. D’ailleurs (si vous avez les droits) n’importe qui peut aller voir ce qu’il se passe sur cette branche depuis Azure Devops : La Pull Request feat -> develop Azure Devops sait qu’une branche feat/LoginPage est en cours et vous propose directement de choisir celle ci et de créer une pull request à partir de celle ci. Dans mon cas j’ai eu ceci : C’était pas voulu, mais j’ai eu la surprise de voir que j’ai un conflit de merge. Et c’est finalement un point intéressant à montrer.  J’ai pas récupéré la branche develop dans mon dev sur ma branche feature. Et honnetement ça arrive TOUT LE TEMPS.  Normal, qq a pu entre temps livrer qq chose sur la branche develop. Il faut donc s’assurer que ce nouveau code s’intègre au mien. Il faut alors lancer toute une série de commandes git: git checkout develop git pull git checkout feat/LoginPage git rebase develop git pull git push Explication : on change de branche pour aller sur develop. On récupère la dernière version de cette branche. On re bascule sur notre branche feat. On applique ces nouveautés (rebase permet de garder un historique chronlogique en mettant nos modifs après celle de develop). A ce stade on est iso en local. Faut faire un pull pour que ça lance un merge automatique (ca met au carré le repo local et le distant et prépare au push) Et enfin on push sur le repo distant.   Maintenant on retourne sur Azure devops : Ya plus de conflit ! 🙂 si on regarde de plus prêt Il ne reste plus qu’à associer notre PR à un Work Item : Ce qui résoud le problème : On peut valider le PR : Ceci effacera la branche feat/LoginPage Au final : Conclusion Pourquoi c’est génial ? C’est vrai qu’avant on publiait directement sur develop et tout allait bien. Et vous avez pas tort. Chacun travail comme il le souhaite.  Avec cette façon de faire, vous allez prendre un petit plus de temps à faire un "peu de paprasse". Mais on a un suivi très intéressant sur chaque étape de la construction de morceau d’application. Tout est lié, et tout le monde peu savoir ce qu’il se passe. Qui travaille sur quoi et quand. Attention, faut pas le voir comme un outil de flicage, mais plutot un outil d’orchestration dans une équipe logiciel.  L’élément que j’ai peu évoqué ici, et qui est relié à a chaque PR c’est le board. Le Board permet de suivre des work items de plusieurs types : Chacun s’organise comme il veut. On peut créer autant de work item que l’on veut et utiliser scrum ou kanban Le développeur se focalise sur sa feature et traite de bout en bout celle ci (jusqu’à la branche develop) Le tech lead suit tout ça. A chaque fin de sprint, ou quand il le souhaite, il peut faire une release. Le product owner est au courant des évolutions de son app.  Azure Devops est vraiment un super outil.  Et j’ai pas fait le tour de toutes ses possibilités.

Azure Devops – Pull Request

Dans mon dernier article, j’ai introduis Git Flow avec un exemple, la naissance d’une application.  A un moment, je raconte l’évolution de l’équipe de dev et de leur organisation autour du code source. On y parle de Pull Request.  La PR est une procédure de validation d’un ensemble de commits regroupés dans une branche feature (quand on applique Git Flow). On peut aussi appliquer une PR de la branche develop vers master. C’est ce qu’on appelle une "release".  Chacun ayant ses stratégies, je vous propose la mienne, qui va bien pour un petit/moyen projet :  Situation J’ai 2 branches principales : master. A considérer comme la branche release car c’est ce code qui part en prod. develop. Son code part en staging. Ca sert aux dev pour voir le résultat de leur travail sans influencer la prod. Quand j’estime que la branche develop a quelque chose d’intéressant, je pousse le code vers la master (merge).  Cette action est réalisé via une Pull Request depuis Azure Devops. Je ne fais aucune manipulation git. Tout ce passe sur Azure Devops. D’ailleurs j’ai interdit toute manipulation de la branche master en dehors d’une PR. Voyons voir comment faire cela : Règle de branche master Sur Azure Devops, il faut se rendre sur l’onglet "Repos" puis "Branches" : Cliquez sur le bouton à droite de la branche master, ce qui ouvre un menu. Cliquez sur Branch Policies. Nous y voila, si on lit la première ligne, elle nous dit que si une seule des options est cochée, alors la branche ne peut pas être effacée et toute modification devra passer par une PR. Quelque part, je pourrais m’arréter la car c’est tout ce dont j’ai besoin. Mais on va voir qu’il y a quelques options bien intéressantes : Require a minimum number of reviewers. J’ai une équipe de 1 dev, moi. donc je vais m’auto évalué, ça n’a pas de sens. Je n’ai pas coché cette case. Mais c’est intéressant dès lors qu’on valide par un second dev (lead tech pour la master).  – Check for linked work items. Cette option est intéressante dès lors que l’on travaille avec un backlog. Ce qui n’est pas mon cas pour ce projet "demo". Mais c’est conseillé. En effet, vous allez améliorer chaque PR avec un "work item" qui sera donné par votre product owner ou votre tech lead. C’est hyper quali de faire ça. Surtout intéressante depuis une branche feature vers la develop. Ici depuis la branche develop vers la master, on aurait plus un ensemble de feature. A voir avec les types de work item. Si ca se trouve ça peut coller.  Check for comment resolution option pas obligatoire. Si coché, cela force à valider tout commentaire dans le code. On le verra plus tard, mais si un reviewer constate un manquement, une erreur ou une objection dans le code, il le signifie par un "commentaire". Si celui ci n’est pas "résolut", alors on peut pas valider la PR. A tester avec votre équipe. La encore, c’est intéressant pour une PR vers la branche develop  Limit merge types cette option permet de laisser le choix lorsque la PR est validé, de choisir le type de merge que l’on souhaite appliquer à la branche cible. Pour mon cas, je ne laisse pas le choix, j’impose un squash merge. La encore, c’est les goûts et les couleurs. It’s up to you. Je pense qu’un article entier peut y être consacré. On en discute encore dans l’équipe où je bosse…  On va maintenant rajouter des règles de build : On ajoute une règle qui impose qu’un build s’execute correctement. Pour cela on doit construire une pipeline de build. Si la branche develop ne build pas, alors on ne fait pas le merge. Pour ma part, le build est un publish. Ce qui revient a peu prêt au même (un publish est un build + génération des fichiers statics web dans le cas d’une app Blazor WASM).  Ma première Pull Request On va tester tout ça. On va dans Repos – Pull request Cliquez sur New pull request : Il faut choisir sa source et sa destination, pour nous, develop –> master Notez que j’ai juste mis un titre. On peut ajouter des reviewers et bien sûr un work item. Tout ca on le verra dans une pull request de type feature –> develop. Cliquez sur Create. Voici ce qui se passe : Première chose, on a un élément requis qui doit se lancer. Celui ci c’est notre "règle de build" écrite juste avant.  Notez aussi qu’il y a un check "No merge conflict". Ce qui permet de vérifier en amont qu’on a pas foiré un merge/rebase malencontreux.  Si on attends qq secondes : On voit notre pipeline qui se lance et qui passe au vert si notre publish est ok.  En haut a droite on a un bouton approve qui va concerner des validations "humaines". Tout est vert. On a un pre-merge ok. Un build ok. Pas de reviewer, et pas d’autre règle (j’ai volontairement fait en sorte que ce soit pas trop compliqué pour cet exemple)  Si on clic sur Complete On a un message qui veut supprimer develop. On veut pas. Surtout pas. D’ailleurs on fera en sorte par la suite de rendre develop ineffacable.  Le squash commit est l’unique option, comme indiqué dans les règles de la branche master que l’on vient de définir. On peut si on veut rajouter un commentaire personalisé de commit.   On clique sur Complete merge, quand il est fini, on a cette info : Et si on vérifie nos pipeline, notre DEPLOY master to prod est lancée ! On vient d’automatiser notre branche master. Elle est sécurisée (personne hormis une PR peut la modifier). Elle est tracable et on peut échanger via une interface web sur une operation qui d’habitude se passe en ligne de commande dans un coin.  De plus en rajoutant une seconde pipeline, lorsque la PR est validé puis mergé, on a un deploy automatique vers la prod.…

Azure Devops – Git Flow intro

Intro Git Flow tu connais ? non ? Et Git tu connais ? non…ouais faut faire un effort la monsieur (ou madame). Alors git j’explique pas. Si tu connais pas reviens me voir, mais va tout de suite apprendre qq commandes car c’est juste une tuerie ce truc. Quand t’as connus vss, svn ou team foundation server, tu sais que git te sauve la vie. Il est juste incontournable aujourd’hui. Ho tu pourras faire semblant qq heures, mais tu vas vite te retrouver dans l’impasse. Un conseil, tarde pas trop, apprends git ! Et en ligne de commande, pas avec un outil (quoi qu’un outil peut éventuellement t’aider, mais crois moi, fait tout en ligne de commande…) J’ai personnellement tardé à y passer. Trop. Et j’ai aussi utilisé des outils graphiques. Personne n’est parfait ! Alors si tu es encore la, tu sais ce qu’est une branche, un merge ou un rebase, un commit…   C’est quoi Git Flow ? A lire, surtout le premier : voici 3 liens : https://danielkummer.github.io/git-flow-cheatsheet/index.fr_FR.html https://grafikart.fr/tutoriels/git-flow-742 https://git-flow.readthedocs.io/fr/latest/presentation.html Ca cause Git Flow mieux que moi. Je suis ici pour vulgariser. Alors Git Flow c’est un ensemble de commandes git qui permettent de s’organiser autour du code source d’une application. Git Flow propose une stratégie pour gérer le cycle de vie d’une application coté code source, du développement locale jusqu’aux versions releases finale en passant par des branches qui auront un but précis.  En vrai, c’est juste des commandes git ! C’est une surcouche qui facilite la vie. Enfin en théorie. Perso j’utilise les principes de Git Flow mais pas ses commandes.  Pour expliquer Git Flow, on va se mettre dans un contexte, imaginons la vie d’une application, par exemple Tonder, une app web pour flirter.   V0.0.1 alpha – naissance d’une app Il était une fois un développeur en recherche d’amour (il veut ken à donf) et il lui vient une idée d’application qu’il nomma Tonder. Le dev est tout seul sur son projet. Il bosse dessus comme un ouf et sort sa premiere app Tonder Alpha 0.0.1 Il est content, mais c’est une version alpha. Elle tourne sur un serveur à lui dans sa piaule, bancale, comme son code.  V0.1.0 bêta Arpès quelques jours de discussion avec son hamster, son app ressemble à quelque chose, il veut faire tester son app et la rend disponible en version bêta privé. Il a donc une « prod » (toujours dans sa piaule) et il s’appercoit qu’il devient difficile de travailler directement sur sa prod sans prendre le risque de tout péter. Alors il crée une version « staging » sur laquelle il bosse.  Mais pour le moment, il existe qu’une « version » de son code. Aucun historique, tout est en local sur un disque dur de sa machine. Un virus, un feu domestique, un coup de foudre, pire trouver une meuf et avoir des gosses… il peut tout perdre.  Notre dev se dit qu’il serait bien d’avoir un controleur de code source qui lui permettra de  sauvegarder son code sur un cloud le rendre accessible à d’autre dev via ce cloud pouvoir gérer l’historique de son code  Alors il crée son repo Git, qq part où il sait qu’il sera accessible et disponible.  V1.0.0 Première release officielle Ca y est, notre dev sort enfin au grand publique sa super App. Il est fiert. Il est content. Son poil brille (il a pas pris de douche depuis 72h, 15 cannettes de coca trainent sur le bureau, il ne sait même plus quel jour on est, et si d’ailleurs c’est le jour ou la nuit …) Les retours utilisateurs arrivent. Il les traite comme il peut, avec le mécanisme suivant : « je code en dev locale, puis si ca marche je passe sur staging puis si ca plante pas je balance sur la production ». Il fait tout à la main, pas d’automatisation, il se dit qu’il a pas le temps pour ça et que c’est qu’une petite release de plus, ça prendra 5 min… Ils se dit qu’il aimerait bien un peu d’aide… et prendre l’air… V1.0.547 Ca build à donf Notre développeur ne compte plus le nombre de build qu’il a fait. Toujours à la main. Ce coup ci il décide d’automatiser sa chaine de livraison/deploiement continue. Il passe par : son premier build automatisé : https://reactor.fr/azure-devops-pipeline-ci-cd-first-build son premier deploiement automatisé : https://reactor.fr/azure-devops-pipeline-ci-cd-deploy ses versions automatisées : https://reactor.fr/azure-devops-pipeline-ci-cd-versioning multi environnement : https://reactor.fr/azure-devops-pipeline-ci-cd-environnement Il est vraiment satisfait. Certe il vient d’y passé quelques heures. Mais a présent il ne s’occupe ni de son staging, ni de sa prod. Tout est fait automatiquement. Et du coup il peut prendre l’air… ça lui rappel d’ailleurs qu’il a un chien… mais il est où son chien ? V1.1.41 1er co développeur Enfin un peu d’aide ! Un nouveau dev arrive en renfort. Git devient indispensable.  Jusque là, le repo git contient 2 branches, une master et une develop.  La branche develop est celle que les développeurs utilisent.  La master sert de branche « release ». Quand on estime que l’on a quelque chose, on pousse du code depuis la branche develop vers la master.  Une pipeline s’occupe de mettre à jour le staging dès que la branche develop reçoit un commit. Une pipeline s’occupe de mettre à jour la prod dès que la branche master reçoit un commit. Nos deux devs travaillent en simultané sur la branche dev. A chaque commit, on a run de pipeline, ca fait bcp de deploiement pour parfois pas grand chose. Alors nos deux devs décident de travailler en branche.  Chacun aura sa branche au départ. Mais nos développeurs se rendront compte qu’avoir une branche chacun revient à avoir deux versions de la branche develop (en plus de celle ci). Il ne profite pas des avancés de chacun et attendent que la branche develop soit à jour pour récupérer le travail de l’autre, via des cherry-pick ou des rebases hasardeux. C’est un peu confu, et nos deux devs décident d’appliquer Git Flow avec des branches feature (fonctionalités).  Ainsi, ils peuvent travailler tous les deux sur une feature si il…

Azure Devops Pipeline (CI/CD) – Relancer les services

Services Debian systemctl Suite à mon dernier article, j’ai été confronté à un problème que j’ai mis longtemps à identifier. Lorsque je mets à jour mon site web, mettons celui du staging avec une nouvelle publication, je modifie les fichiers à la racine du projet, c’est à dire var/etc/www/staging.blazordemo.reactor.fr/ dans mon cas. Pour ma part j’applique une politique du "j’effface tout" et "j’upload tout". Pas de remplacement de fichier. C’est plus long mais je suis certain qu’il y a pas un mauvais fichier en ligne.  Hormis des pb de cache ou de rafraichissement, mon site web est bien à jour.  Mais pas mon service Kernel. En tout cas sur linux Nginx, lorsque je rajoute par exemple un controler "api/plateform" coté serveur, si je ne relance pas mon service avec les commandes suivantes : sudo systemctl stop kestrel-staging.blazordemo.reactor.fr.service sudo systemctl start kestrel-staging.blazordemo.reactor.fr.service sudo systemctl status kestrel-staging.blazordemo.reactor.fr.service mon api « plateform » ne sera pas accessible. En tapant ces commandes, l’api est accessible. Il serait bon d’inclure cela dans la pipeline, histoire qu’on est rien à faire à la main à chaque run de pipeline si le code c# est modifié coté serveur. Pour cela, il suffit de rajouter ces lignes : – task: SSH@0 displayName: ‘Restart Kestrel Service’ inputs: sshEndpoint: ‘SSH to Ikoula’ runOptions: ‘commands’ commands: | sudo systemctl stop kestrel-staging.blazordemo.reactor.fr.service sudo systemctl start kestrel-staging.blazordemo.reactor.fr.service sudo systemctl status kestrel-staging.blazordemo.reactor.fr.service readyTimeout: ‘20000’ Ca donne ça dans les ‘logs’ des jobs de l’execution du pipeline :

Azure Devops Pipeline (CI/CD) – Environnement

Problème du dernier post Je me suis bien pris la tête sur le dernier billet au sujet d’un nouveau problème qui est apparu lorsque j’ai voulu diviser mon site web en 2, une partie staging et une partie prod. Ca pourrait tout aussi bien être "preprod", "recette" etc… Avant j’avais qu’un seul site web: blazordemo.reactor.fr. Celui ci a sa config Nginx et son service systemd qui fait tourner Kernel via un proxy sur le port 7777. (voir article ) J’en ai créé un nouveau "staging.blazordemo.reactor.fr".  L’idée est de faire comme les pros, un site web de "staging" et un de "prod".  dev : locale, tambouille de developeur, avec une base de données crado, des machins bricolés, des trucs à jours ou pas… staging:  distante, même environnement que la prod (meme serveur de base de données, même OS, même TOUT, sauf les données qui sont normalement copiés et anonymisés dans le meilleurs des mondes) prod: distante, le site qu’on update le vendredi soir 🙂 Donc j’ai crée "staging.blazordemo.reactor.fr". Sauf que j’ai pas modifié mon service qui fait tourner Kestrel via proxy sur port 7777.  Et j’ai mis un temps fou à m’en apercevoir. (j’ai été jusqu’a faire un gros delete de mon repertoire www. Nginx continuait à me servir un beau site web… même après un reboot. car le service était le meme…) Donc il me faut 2 services… Un de staging, l’autre de prod. Le tout sur un port proxy différent bien évidement.  Bien entendu, ce problème n’existe pas si le staging et la prod ne sont pas sur le meme serveur, ce qui est TRES recommandé. Cependant, je trouve l’exercice intéressant car il pousse dans les retranchements et force à de bonnes pratiques. Mon ancienne technique Dans le projet Blazor Server, dans Program.cs j’ajoutais ceci  Une ligne de compilation conditionnelle qui me changait le port si on était en release (ce que je considèrais comme mon unique prod).  Je pourrais ajouter une condition STAGING avec un port 7776 et m’en servir pour la version staging. A mon sens une directive de compilation n’a rien a voir avec les environnements, je veux dire c’est liés, mais c’est pas son but de définir du paramétrage de port…  Je pense qu’on peut faire mieux, avec les fichiers de conf appsettings.js. Créeons deux autres fichiers de config, un pour la prod et l’autre pour le staging. Normalement vous avez déjà par défaut un fichier appsettings.Development.json launchSettings.json Si vous travaillez avec Visual Studio ou VS Code vous devez savoir que vous avez des options de lancement de votre app qui sont configurable dans le fichier Properties/launchSettings.json Encore un fichier de config qui sème le doute… { « iisSettings »: { « windowsAuthentication »: false, « anonymousAuthentication »: true, « iisExpress »: { « applicationUrl »: « http://localhost:54778 », « sslPort »: 44382 } }, « profiles »: { « BlazorDemo.Server »: { « commandName »: « Project », « dotnetRunMessages »: true, « launchBrowser »: true, « inspectUri »: « {wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri} », « applicationUrl »: « https://localhost:7249;http://localhost:5249 », « environmentVariables »: { « ASPNETCORE_ENVIRONMENT »: « Development » } }, « IIS Express »: { « commandName »: « IISExpress », « launchBrowser »: true, « inspectUri »: « {wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri} », « environmentVariables »: { « ASPNETCORE_ENVIRONMENT »: « Development » } } } } Comme on peut le voir dans la section "profiles", je peux lancer mon app soit : Via IIS Express  Via la commande dotnet run La première est historique, je pense qu’on en parlera plus dans qq temps. Avant .net core on était obliger de lancer un server utilisant le .net Framework sous IIS qui est le serveur de Windows. La version Express est la version de dévelopement. Pour moi c’est voué à mourrir, mais certains ont des habitudes et Microsoft les forces pas à les changers.  Depuis .net Core (et donc .net 5 et 6), on peut executer nos app sur n’importe quel OS et serveur web comme apache ou nginx sous linux. On a un serveur web intermédiaire appelé Kestrel qui fait le job. D’ailleurs c’est lui que l’on utilise en dévelopement.  En executant une commande dotnet run sur notre projet serveur, on lance un Kestrel. C’est lui que l’on veut paramétrer pour avoir une config dev, staging, prod.  C’est possible d’éditer en développement ce fichier pour changer de port. Mais c’est uniquement un fichier de conf pour une execution en dev local. C’est pas un fichier de configuration plateforme de prod.  Je place ça là car c’est un fichier qui peut vous semer le doute lors de vos devops et test local. AppSettings.{ENV}.json On va modifier le fichier appSettings.Developement.json et lui rajouter ceci  { « Plateform »: « Dev », « Kestrel »: { « EndPoints »: { « Http »: { « Url »: « http://localhost:1234 » } } }, « Logging »: { « LogLevel »: { « Default »: « Information », « Microsoft.AspNetCore »: « Warning » } } } Perso je rajoute une ligne "Environment" qui me permet de voir dans sur quel type d’environement je suis (et plus tard de l’afficher dans l’app).  Ce qui nous intéresse c’est la section Kestrel. On ajoute un EndPoints et on lui précise un port.  Faites un dotnet run sur votre projet à présent : On a un warning qui nous dit que l’adresse utilisé va écrasé celle du launchsetting.json. C’est ce qu’on veut. On voit bien la nouvelle adresse http://localhost:1234.  C’était pour la démo, en dev ça sert a rien de faire cela, autant utiliser le launchSettings.json qui est la pour ça. Donc enlever la ligne Kestrel, c’était pour la démo. Par contre on va mettre ces configs pour appsettings.staging.json  { « Plateform »: « Staging », « Kestrel »: { « EndPoints »: { « Http »: { « Url »: « http://localhost:7776 » } } }, « Logging »: { « LogLevel »: { « Default »: « Information », « Microsoft.AspNetCore »: « Warning » } } } et appsettings.prod.json { « Plateform »: « Prod », « Kestrel »: { « EndPoints »: { « Http »: { « Url »: « http://localhost:7777 » } } }, « Logging »: { « LogLevel »: { « Default »: « Information », « Microsoft.AspNetCore »: « Warning » } } } ASPNETCORE_ENVIRONMENT Encore une chose à savoir. Pour déterminer sur quel environement .net se trouve, il utilise une variable d’environement ASPNETCORE_ENVIRONMENT Elle est d’ailleurs clairement définie dans le fichier launchSettings.json à "Development". Donc en dev, le fichier de config appsettings utilisé sera appsettings.development.json Pour que ce mécanisme fonctionne en prod, soit on définie la variable ASPNETCORE_ENVIRONMENT à "Production" soit par défaut, si elle n’existe pas, c’est déjà le cas (attention moi j’ai nommé mon appsettings prod et non production). Le problème c’est que une variable d’environement est définie pour tout…

Azure Devops Pipeline (CI/CD) – Versioning

C’est quoi une version ? Je vais faire quelque chose de très basique et qui ne sera probablement pas appliqué tel quel dans un cas plus professionnel. D’ailleurs, chacun ayant ses méthodes de travail, ce post reste un example de "comment on pourrait faire" pour versionner une app.  C’est quoi une version ? La encore, je suis pas sûr que tout le monde utilise la même façon de versionner.  Par exemple les versions du navigateur Firefox utilise simplement un chiffre (https://blog.mozfr.org/pages/Calendrier-versions-Firefox). Mais si on regarde de plus prêt on a quand meme 98.0.1 et donc des points de séparations.  En fait, Pour le grand public on va utiliser "Firefox 98". Mais il faut savoir qu’il existe de nombreuses versions de la 98 ! Du moins en interne. Avant de livrer une version patché 98.0.1 qui va corrigé des bugs mineures.  D’après ce que j’ai pu voir, on utilise principalement ce style de nommage de version X.Y.Z X : Version Majeure (non rétro compatible) (nouvelles fonctionalités, gros correctif, ajout de techno, changement de look…) Y : Version Mineure (rétro compatible) (correctifs, patchs, en gros pas de grosse modif, mais qui répare) Z : Révisions.  (rétro compatible) Sert plutot au dev et product owner pour savoir de quelle version on parle en pre prod pour basculer vers la prod. Quelque part, ce dernier numéro ne devrait à mon sens pas être communiqué officiellement (un peu comme Firefox qq part) Sur la version X, on a je pense tous la même idée. On sort une version X rarement. Par contre, je suis pas certain qu’on utilise tous Y et Z de la même manière. Franchement, c’est freestyle, dans les versions mineures on peut voir de nouvelles (petites) fonctionalités. C’est vraiment selon vos préférences et ceux avec qui vous bosser.  Pour le coté retro compatible, c’est ce que j’ai lu sur le net. Intéressant mais pas du tout respecté par tous.  Autre style, voici un format intéressant ou l’on cumule en plus une date : V 2020.10.23.1629 Je trouve ce format particulièrement intéressant car on sait tout de suite de quand date la version. Mais ca fait bcp de chiffre.  Ce format est utilisé par Larsen Lance avec un scipt powershell qui "incrémente" ce format à chaque build en automatique (http://www.lancelarsen.com/blazor-tips-n-tricks-auto-increment-your-version-tag-with-powershell/) Pourquoi versionner ? La version d’une app sert tout simplement de référenciel. De quoi on parle ? De la version 1.12.665 ou ya un bug qui est corrigé dans la V1.13.005. C’est quand même plus pratique.  Le product owner sera aussi attentif à ces versions concernant l’ajout de nouvelles fonctionalités et communiquer dessus.  Ca permet de prévoir une roadmap large et dire par exemple, cette fonctionalité sera attendu pour la V2.3, pas avant.  En parlant de roadmap, je cite souvent Star Citizen qui est un jeux vidéo en béta depuis des années, et qui affiche ses avancés https://robertsspaceindustries.com/roadmap/release-view Il fixe des objectifs par trimestres sous forme de version avec une majeure et une mineure. C’est clair. Mais bon il sort quand ce jeu !!!! C’est une alpha. Et certain ajoute ce terme dans la version.  Alpha, Beta, Rc (Release Candidate), Nightly Build… On peut préciser le contexte de la version.  Versionner une app .net Core avec une Pipeline automatique Tout l’enjeu de cet article. Comment je peux modifier ma pipeline pour inclure un nouveau numéro de build par exemple à ma version et l’afficher en prod. (comme sur Firefox dans la rubrique aide ou a propos) ? Afficher la version dans l’app Pour que l’on voit directement la version dans mon app Blazor, je vais carrément l’afficher en haut a droite : Une page about avec ce numéro aurait été plus propre sur une vraie App. L’idée ici c’est de l’avoir en permanence sous les yeux.  Pour cela on va modifier MainLayout.razor comme ceci La ligne importante est celle ci : Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion; La version par défaut qui s’affiche est 1.0.0. Si vous faites (sous Visual Studio) un clic droit sur le projet client de Blazor, puis propriété et enfin dans la section Package vous verrez ce numéro. Par contre il n’est pas modifiable.  Pour le modifier, il suffit de rajouter dans le .csproj une ligne version. Easy. Bingo YAML comment gérer une version Je veux une version sous cette forme yyyy.mm.dd.xx, donc date + un numéro auto incrémenté. On commence par ajouter un compteur à une variable. Ce compteur sera automatiquement incrémenté à chaque execution de la pipeline. revision: $[counter(format(‘{0:dd}’, pipeline.startTime), 1)] Pour s’en assurer, on va afficher la valeur de notre variable : #display value – script: echo $(revision) displayName: ‘revision display’ Executez plusieurs fois votre pipeline et aller voir ce que ça donne. Par exemple chez moi : J’en suis à mon 24ième run. Il me faut aussi une date du jour. pour cela on va aussi utiliser une variable dateToday ainsi qu’une derniere variable  »versionString"  qui va concaténer ces deux dernières. (1 h pour trouver comment faire… le ‘>’ magique). Ce qui donne : dateToday: ‘Will be set dynamically’ revision: $[counter(format(‘{0:dd}’, pipeline.startTime), 1)] versionString: > $(dateToday).$(revision) Il suffit à présent de générer dateToday. On va utiliser un script PowerShell (pompé et adapté sur ce site) #Preparing Build Number – task: PowerShell@2 displayName: ‘Preparing Build Number’ inputs: targetType: ‘inline’ script: | $currentDate = $(Get-Date) $year = $currentDate.Year $month = $currentDate.Month $day = $currentDate.Day Write-Host $currentDate Write-Host $day Write-Host $env:revision Write-Host « ##vso[task.setvariable variable=dateToday]$year.$month.$day » On vérifie les données : #display value – script: echo $(revision) displayName: ‘revision display’ – script: echo $(dateToday) displayName: ‘dateToday display’ – script: echo $(versionString) displayName: ‘versionString display’ Normalement on a ce résulat : 2022.3.21.29, version numéro 29 faite le 3 mars 2022, elle est pas belle la vie ?  Publication avec la version J’ai légérement adapté mon script de publication qui était anciennement ceci : # Publish Blazor Demo Server – script: dotnet publish –configuration $(buildConfiguration) src/BlazorDemo/BlazorDemo/Server/BlazorDemo.Server.csproj displayName: ‘dotnet publish $(buildConfiguration)’ Remplacé par : # Publish Blazor Demo Server – task: DotNetCoreCLI@2 displayName: Publish inputs: command: publish publishWebProjects: false projects: ‘$(projectBlazorWasmServer)’ arguments: ‘–configuration $(buildConfiguration) –output $(build.artifactstagingdirectory) /p:Version=$(versionString)’ zipAfterPublish: false modifyOutputPath: false…

Azure Devops Pipeline (CI/CD) – Secrets

Cet article concerne le secret de certaine informations, comme un mot de passe, un clé privée etc.  Dutant mon apprentissage sur azure devops, je suis passé par cette étape. Cependant je ne me suis pas servi précisément de ces varibles/files secrets au final car j’ai utilisé le "service connexions" . Néanmoins je trouve cela instrucif, alors je partage. YAML – sécurité Vous avez remarqué, je ne vous ai pas communiqué ma passphrase ni ma clé privée. Sinon vous auriez accès a mon serveur. Ma clé est sur mon poste de dev. La passphrase lisible dans mes scripts d’upload automatique. C’est pas ouf question sécu. Mais vu que je bosse tout seul dessus… ça va, ça passe.  Qu’en est il lorsque l’on travaille à plusieurs dev, avec des sys admins, du cloisement et un niveau de sécurité qui nécessite de pas trop déconner ? Il faut trouver un moyen de sécuriser ces données. Azure Devops utilise des "secure files" et des "secure variables" pour faire cela.  https://docs.microsoft.com/en-us/azure/devops/pipelines/library/secure-files?view=azure-devops Ces données sont HORS repo git. Ainsi personne n’y aura accès en dehors de vous et des autorisations que vous leurs donnerez sur Azure Devops. Par contre elles seront stockées sur Azure Devops… les américains, la CIA, la NSA tout ça tout ça…   Commençons par enregistrer notre passphrase et lui donner la permission pour la pipeline du projet Azure Devops "Blazor Sandbox". Pour cela on va créer une nouveau groupe de variables que j’ai nommé IKoulaGroup. Il faut aller dans Pipelines/Library et cliquer sur Variable group.  Ajouter une variable, donner lui un nom (ex MyPassPhraseIkoula) et une valeur (dans l’exemple Bangali) Notez qu’à droite de la valeur d’une variable se trouve un petit bouton cadena qui permet de masquer celle ci. On y reviendra. Retour sur le YAML Maintenant que l’on a notre variable stockée sur Azure Devops on va pouvoir la récupérer dans notre pipeline Voici comment : On a une première variable qui était déjà là, celle qui concerne le type de build ‘Release’. Elle a un nom et une valeur. Celle ci ne concerne que la pipeline et ne sera vu que de l’agent qui s’occupe de cette pipeline.  Ensuite on a la déclaration du groupe IkoulaGroup qui contient une variable dont le nom est "MyPassPhrase" avec une valeur. Plus d’info sur la doc officielle ici. Plus loin on affiche ces variables avec un echo. Deux façons de récupérer notre variable MyPassPhrase.  tout simplement en l’appellant par $(MyPassPhrase) en utilisant une « expression de runtime » avec $[variables.MyPassPhraseIkoula]. Je pige pas trop ce truc, mais je pose ça la des fois que ça serve plus tard.  Concrètement, je n’arrive pas à récupérer la variable avec cette deuxième technique. Par contre j’ai bien ma variable avec la première façon :On a récupéré notre passphrase "Bangali" de tout à l’heure.  Maintenant un mot de passe ou une passphrase c’est pas censé être affiché tel quel. Vous vous souvenez du petit bouton cadena de tout à l’heure, qui se trouve a droite de votre variable dans la library de pipeline, cliquez dessus pour le vérouiller ainsi : penser à sauvegarder et relancer la même pipeline : notez que cette fois ci, le contenu de la variable est masqué par des **** On sait maintenant comment cacher des informations. 

Azure Devops Pipeline (CI/CD) – Deploy

Objectif : déploiement en production Dans la précédente partie on a déployé une pipeline sur Azure DevOps. Celle ci nous permet de lancer une build dès que la branche master de notre repo Blazor Sandbox reçoit un nouveau commit. De cette manière on s’assure que le build fonctionne ou pas. On est prévenu du résultat par email.  Ce qui serait intéressant, c’est de pouvoir la déployer sur un serveur web automatiquement en cas de succès.  Ma config J’ai un serveur VPS chez iKoula pour 4€/mois, avec une debian linux.  Ca tourne plutot bien. Mais bon, j’ai pas beaucoup de traffic 🙂 Donc j’ai un site web https://dev.blazordemo.reactor.fr et https://blazordemo.reactor.fr qui tournent tous les deux sous Nginx. Derrière chez deux services kestrel asp.net core sous .net 6.0. (pour faire bien, il aurait fallut dissocier la prod de mon dev (ou recette, staging). Petit budget… Dans /var/www/blazordemo.reactor.fr et /var/www/dev.blazordemo.reactor.fr j’ai mes publications de site web asp.net core Blazor WASM (le serveur et le client WASM "all in one"). L’idée est de dire à Azure Devops Pipeline, lorsque la branche master reçoit un nouveau commit, tu publies une version du serveur et tu balances le tout via SSH (sftp). Pipeline YAML On est fixé sur les objectifs. Maintenant il faut traduire cela en YAML. Voici un bout de doc : https://docs.microsoft.com/fr-fr/azure/devops/pipelines/tasks/deploy/copy-files-over-ssh?view=azure-devops En premier lieu, je vais reprendre la précédente pipeline et modifier build par publish. La différence est notable pour Blazor Server WASM. (voir mon article) Un petit commit + push et on voit que Azure Devops lance un nouveau job. On attend qu’il termine et passe au vert. Je pense qu’on va procédé ainsi, à taton. Petit pas par petit pas.  Une modif + commit + push + retour du Job.  Point SSH/SFTP Pour accéder à mon serveur en toute sécurité, je me connecte via SSH. Je prends donc la main à distance depuis mon poste windows sur mon serveur debian linux, qq part en France. J’ai un mot de passe et un login. Et roule ma poule.  Mais on peut faire mieux. J’ai ajouté une paire de clé privée/publique et une passphrase. Ainsi, il faut avoir la clé privée + la passphrase pour accéder.  C’est plus sécurisant pour moi. Je laisse l’accès SSH classique pour des opérations plus ponctuelles. J’ai de mon côté une serie de fichier .bat qui lance une commande de publication .net core et des commandes winscp (permet de lancer des commandes SFTP depuis Windows). La connection se fait via cette clé et cette passphrase. Ainsi, je peux en un double clic mettre à jour ma prod/staging/recette/dev depuis mon poste, sans lacher mon mdp. Au lieu de le faire à la main depuis un client sftp. Ca marche ! C’est moins rapide qu’un client sftp (car les fichiers uplodé ne sont pas lancés en parrallele). J’ai deux types de scripts. La totale, qui met a jour toute la publication : et un autre "rapide" qui ne mets a jours que le minimum pour aller vite : et son fichier .bat  Donc l’idée, c’est de faire pareil sous Azure Devops. Yaml On va rajouter une nouvelle tâche dans notre pipeline YAML avec CopyFilesOverSSH 4 éléments sont à renseigner : sshEndPoint : c’est le nom de notre connexion SSH que l’on va configurer plus loin sourceFolder : le chemin relatif de votre publish. L’agent de build va s’occuper de récupérer votre publish au bon endroit. Attention au majuscule et minuscule si l’agent est sur linux !!! targetFolder: le chemin de destination de votre publication sur la machine cible.  cleanTargetFolder : facultatif, mais effacer le contenu de la destination fait pas de mal.  Service Connections Le sshEndpoint de tout à l’heure est à configurer dans les "project settings" dans la section Pieplines/Service Connections  Il reste plus qu’à créer la votre en cliquant sur le bouton new connection Sélectionnez SSH : puis remplissez selon votre config, en uploadant votre clé privée. Attention, celle ci doit être au format .pem. Et voila. C’est tout.  Relancer votre pipeline avec un petit git add commit push.  Normalement vous devriez avoir que du vert !

Azure Devops Pipeline (CI/CD) – First Build

Intro En général, quand on découvre une techno, on fonce direct en dev local et on s’amuse. C’est ce que j’ai fait aussi, mais j’ai pas tardé à mettre en prod. Car par expérience,  mieux vaut avoir les problèmes au début, tant que le projet est pas trop gros ou trop compliqué.  Donc l’idée de ce billet, c’est voir comment on pourrait monter une chaine CI/CD (continious intergration/ continuious deployement) sur un projet blazor de base.  Projet de base Blazor Avec Visual Studio 2022 Community, on créer un projet Blazor WASM, avec Hebergement Asp.net core et PWA : Pour ma part je l’ai nommé BlazorDemo.  Je me suis permis de modifier qu’une seule ligne, dans program.cs du projet server. Je spécifie juste un port pour ma prod. Voir artile https://reactor.fr/net-core-sous-linux-nginx-80-http-443-https-firewall/ Azure DevOps Pipelines Azure Devops, c’est GitHub, Maven, Jenkins et j’en passe tout ça dans une appli web.  Ca nous permet de faire du CI/CD depuis nos propres repos (qu’ils soient sur BitBucket, Azure devops, GitHub, ou autre…) L’idée est de partir sur deux branches git, une master et une develop.  La master sera considéré comme la Prod. La develop comme la branche de travail.  A chaque fois que la branche master recevra un commit, on lancera une "pipeline" qui fera plusieurs actions, comme builder, lancer des tests et deployer.   A l’avenir, la branche master ne pourra plus recevoir de commit directement, ceci sera bloqué par defaut. Le seul moyen sera de faire une Pull Request depuis la branche develop vers la branche master. Ceci afin de mettre en place de bonne pratique de développement et de gestion de code source.  Bien sûr on pourrait pousser le concept plus loin, en pratiquant du Git Flow par exemple. Mais restons simple pour bien comprendre les mécanismes d’AzureDevOps 1ere pipeline Commençons par créer notre première pipeline. Menu Pipeline Cliquez sur New Pipeline Comme je le disais tout à l’heure, notre code source peut se situer sur différent repos, choisissez le votre : On choisit ensuite son repos, dans mon cas ceci :  Ensuite il faut choisir un modèle de script YAML. Alors ici, c’est pas clair je trouve. J’ai choisis "Asp.net Core" qui n’est pas présenté comme premier choix. Ce qui pourrait m’induire en erreur. Enfin de toute manière, c’est qu’un modèle, qu’on peut modifier par la suite. Voici le résultat : En cliquant sur Save and Run, puis valider l’écran suivant par defaut, vous allez ajouter un fichier "azure-pipelines.yml" a la racine de votre repo, sur la branche master. S’en suit un run automatique, qui au bout de qq seconde va échouer : En cliquant dessus pour voir le détail : Puis sur Job et sur l’élément en rouge : On a le détail du pourquoi le job a échoué. On a le détail du pourquoi le job a échoué. Ca nous dit que l’on a pas spécifier de projet à compiler… et c’est vrai MSBUILD : error MSB1003: Specify a project or solution file. The current working directory does not contain a project or solution file. Correctif de la 1ere pipeline Vous pouvez corriger directement depuis la plateforme azure devops pour bien le faire depuis votre editeur préféré et jouer qq commande git. Pour ma part je préfère cette derniere.  Je récupère donc via un git pull ma branche master sur mon visual studio code et je modifie le fichier azure-pipelines.yml avec cette ligne script: dotnet build –configuration $(buildConfiguration) src/BlazorDemo/BlazorDemo/Server/BlazorDemo.Server.csproj Le path ici peut différer selon votre répertoire repos. (moi j’ai mis tout ca dans un folder src, qui contient un répertoire  blazordemo qui contient un répertoire "solution" blazordemo. Quand votre modification est faites, il faut alors mettre a jour le repo distant avec un commit.  Rappelons que lorsque la branche master subit un nouveau commit, ca lance automatiquement cette pipeline. Et normalement vous obtenez un build vert :  Et voila, on a fait notre première pipelines qui fait qq chose de très basique pour le moment, builder !