[{"data":1,"prerenderedAt":1035},["ShallowReactive",2],{"/fr-fr/blog/categories/engineering/":3,"navigation-fr-fr":22,"banner-fr-fr":443,"footer-fr-fr":455,"engineering-category-page-fr-fr":667},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"seo":8,"content":11,"config":12,"_id":15,"_type":16,"title":17,"_source":18,"_file":19,"_stem":20,"_extension":21},"/fr-fr/blog/categories/engineering","categories",false,"",{"title":9,"description":10},"Ingénierie","Browse articles related to Ingénierie on the GitLab Blog",{"name":9},{"template":13,"slug":14,"hide":6},"BlogCategory","engineering","content:fr-fr:blog:categories:engineering.yml","yaml","Engineering","content","fr-fr/blog/categories/engineering.yml","fr-fr/blog/categories/engineering","yml",{"_path":23,"_dir":24,"_draft":6,"_partial":6,"_locale":7,"data":25,"_id":439,"_type":16,"title":440,"_source":18,"_file":441,"_stem":442,"_extension":21},"/shared/fr-fr/main-navigation","fr-fr",{"logo":26,"freeTrial":31,"sales":36,"login":41,"items":46,"search":380,"minimal":416,"duo":430},{"config":27},{"href":28,"dataGaName":29,"dataGaLocation":30},"/fr-fr/","gitlab logo","header",{"text":32,"config":33},"Commencer un essai gratuit",{"href":34,"dataGaName":35,"dataGaLocation":30},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":37,"config":38},"Contacter l'équipe commerciale",{"href":39,"dataGaName":40,"dataGaLocation":30},"/fr-fr/sales/","sales",{"text":42,"config":43},"Connexion",{"href":44,"dataGaName":45,"dataGaLocation":30},"https://gitlab.com/users/sign_in/","sign in",[47,91,190,195,301,361],{"text":48,"config":49,"cards":51,"footer":74},"Plateforme",{"dataNavLevelOne":50},"platform",[52,58,66],{"title":48,"description":53,"link":54},"La plateforme DevSecOps alimentée par l'IA la plus complète",{"text":55,"config":56},"Découvrir notre plateforme",{"href":57,"dataGaName":50,"dataGaLocation":30},"/fr-fr/platform/",{"title":59,"description":60,"link":61},"GitLab Duo (IA)","Créez des logiciels plus rapidement en tirant parti de l'IA à chaque étape du développement",{"text":62,"config":63},"Découvrez GitLab Duo",{"href":64,"dataGaName":65,"dataGaLocation":30},"/fr-fr/gitlab-duo/","gitlab duo ai",{"title":67,"description":68,"link":69},"Choisir GitLab","10 raisons pour lesquelles les entreprises choisissent GitLab",{"text":70,"config":71},"En savoir plus",{"href":72,"dataGaName":73,"dataGaLocation":30},"/fr-fr/why-gitlab/","why gitlab",{"title":75,"items":76},"Démarrer avec",[77,82,87],{"text":78,"config":79},"Ingénierie de plateforme",{"href":80,"dataGaName":81,"dataGaLocation":30},"/fr-fr/solutions/platform-engineering/","platform engineering",{"text":83,"config":84},"Expérience développeur",{"href":85,"dataGaName":86,"dataGaLocation":30},"/fr-fr/developer-experience/","Developer experience",{"text":88,"config":89},"MLOps",{"href":90,"dataGaName":88,"dataGaLocation":30},"/fr-fr/topics/devops/the-role-of-ai-in-devops/",{"text":92,"left":93,"config":94,"link":96,"lists":100,"footer":172},"Produit",true,{"dataNavLevelOne":95},"solutions",{"text":97,"config":98},"Voir toutes les solutions",{"href":99,"dataGaName":95,"dataGaLocation":30},"/fr-fr/solutions/",[101,127,150],{"title":102,"description":103,"link":104,"items":109},"Automatisation","CI/CD et automatisation pour accélérer le déploiement",{"config":105},{"icon":106,"href":107,"dataGaName":108,"dataGaLocation":30},"AutomatedCodeAlt","/fr-fr/solutions/delivery-automation/","automated software delivery",[110,114,118,123],{"text":111,"config":112},"CI/CD",{"href":113,"dataGaLocation":30,"dataGaName":111},"/fr-fr/solutions/continuous-integration/",{"text":115,"config":116},"Développement assisté par l'IA",{"href":64,"dataGaLocation":30,"dataGaName":117},"AI assisted development",{"text":119,"config":120},"Gestion du code source",{"href":121,"dataGaLocation":30,"dataGaName":122},"/fr-fr/solutions/source-code-management/","Source Code Management",{"text":124,"config":125},"Livraison de logiciels automatisée",{"href":107,"dataGaLocation":30,"dataGaName":126},"Automated software delivery",{"title":128,"description":129,"link":130,"items":135},"Securité","Livrez du code plus rapidement sans compromettre la sécurité",{"config":131},{"href":132,"dataGaName":133,"dataGaLocation":30,"icon":134},"/fr-fr/solutions/security-compliance/","security and compliance","ShieldCheckLight",[136,140,145],{"text":137,"config":138},"Sécurité et conformité",{"href":132,"dataGaLocation":30,"dataGaName":139},"Security & Compliance",{"text":141,"config":142},"Sécurité de la chaîne d'approvisionnement logicielle",{"href":143,"dataGaLocation":30,"dataGaName":144},"/fr-fr/solutions/supply-chain/","Software supply chain security",{"text":146,"config":147},"Conformité et gouvernance",{"href":148,"dataGaLocation":30,"dataGaName":149},"/fr-fr/solutions/continuous-software-compliance/","Compliance and governance",{"title":151,"link":152,"items":157},"Mesures",{"config":153},{"icon":154,"href":155,"dataGaName":156,"dataGaLocation":30},"DigitalTransformation","/fr-fr/solutions/visibility-measurement/","visibility and measurement",[158,162,167],{"text":159,"config":160},"Visibilité et mesures",{"href":155,"dataGaLocation":30,"dataGaName":161},"Visibility and Measurement",{"text":163,"config":164},"Gestion de la chaîne de valeur",{"href":165,"dataGaLocation":30,"dataGaName":166},"/fr-fr/solutions/value-stream-management/","Value Stream Management",{"text":168,"config":169},"Données d'analyse et informations clés",{"href":170,"dataGaLocation":30,"dataGaName":171},"/fr-fr/solutions/analytics-and-insights/","Analytics and insights",{"title":173,"items":174},"GitLab pour",[175,180,185],{"text":176,"config":177},"Entreprises",{"href":178,"dataGaLocation":30,"dataGaName":179},"/fr-fr/enterprise/","enterprise",{"text":181,"config":182},"PME",{"href":183,"dataGaLocation":30,"dataGaName":184},"/fr-fr/small-business/","small business",{"text":186,"config":187},"Secteur public",{"href":188,"dataGaLocation":30,"dataGaName":189},"/fr-fr/solutions/public-sector/","public sector",{"text":191,"config":192},"Tarifs",{"href":193,"dataGaName":194,"dataGaLocation":30,"dataNavLevelOne":194},"/fr-fr/pricing/","pricing",{"text":196,"config":197,"link":199,"lists":203,"feature":288},"Ressources",{"dataNavLevelOne":198},"resources",{"text":200,"config":201},"Afficher toutes les ressources",{"href":202,"dataGaName":198,"dataGaLocation":30},"/fr-fr/resources/",[204,237,260],{"title":205,"items":206},"Premiers pas",[207,212,217,222,227,232],{"text":208,"config":209},"Installation",{"href":210,"dataGaName":211,"dataGaLocation":30},"/fr-fr/install/","install",{"text":213,"config":214},"Guides de démarrage rapide",{"href":215,"dataGaName":216,"dataGaLocation":30},"/fr-fr/get-started/","quick setup checklists",{"text":218,"config":219},"Apprentissage",{"href":220,"dataGaLocation":30,"dataGaName":221},"https://university.gitlab.com/","learn",{"text":223,"config":224},"Documentation sur le produit",{"href":225,"dataGaName":226,"dataGaLocation":30},"https://docs.gitlab.com/","product documentation",{"text":228,"config":229},"Vidéos sur les bonnes pratiques",{"href":230,"dataGaName":231,"dataGaLocation":30},"/fr-fr/getting-started-videos/","best practice videos",{"text":233,"config":234},"Intégrations",{"href":235,"dataGaName":236,"dataGaLocation":30},"/fr-fr/integrations/","integrations",{"title":238,"items":239},"Découvrir",[240,245,250,255],{"text":241,"config":242},"Histoires de succès client",{"href":243,"dataGaName":244,"dataGaLocation":30},"/fr-fr/customers/","customer success stories",{"text":246,"config":247},"Blog",{"href":248,"dataGaName":249,"dataGaLocation":30},"/fr-fr/blog/","blog",{"text":251,"config":252},"Travail à distance",{"href":253,"dataGaName":254,"dataGaLocation":30},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"text":256,"config":257},"TeamOps",{"href":258,"dataGaName":259,"dataGaLocation":30},"/fr-fr/teamops/","teamops",{"title":261,"items":262},"Connecter",[263,268,273,278,283],{"text":264,"config":265},"Services GitLab",{"href":266,"dataGaName":267,"dataGaLocation":30},"/fr-fr/services/","services",{"text":269,"config":270},"Communauté",{"href":271,"dataGaName":272,"dataGaLocation":30},"/community/","community",{"text":274,"config":275},"Forum",{"href":276,"dataGaName":277,"dataGaLocation":30},"https://forum.gitlab.com/","forum",{"text":279,"config":280},"Événements",{"href":281,"dataGaName":282,"dataGaLocation":30},"/events/","events",{"text":284,"config":285},"Partenaires",{"href":286,"dataGaName":287,"dataGaLocation":30},"/fr-fr/partners/","partners",{"backgroundColor":289,"textColor":290,"text":291,"image":292,"link":296},"#2f2a6b","#fff","L'avenir du développement logiciel. Tendances et perspectives.",{"altText":293,"config":294},"carte promo The Source",{"src":295},"/images/navigation/the-source-promo-card.svg",{"text":297,"config":298},"Lire les articles les plus récents",{"href":299,"dataGaName":300,"dataGaLocation":30},"/fr-fr/the-source/","the source",{"text":302,"config":303,"lists":305},"Société",{"dataNavLevelOne":304},"company",[306],{"items":307},[308,313,319,321,326,331,336,341,346,351,356],{"text":309,"config":310},"À propos",{"href":311,"dataGaName":312,"dataGaLocation":30},"/fr-fr/company/","about",{"text":314,"config":315,"footerGa":318},"Emplois",{"href":316,"dataGaName":317,"dataGaLocation":30},"/jobs/","jobs",{"dataGaName":317},{"text":279,"config":320},{"href":281,"dataGaName":282,"dataGaLocation":30},{"text":322,"config":323},"Leadership",{"href":324,"dataGaName":325,"dataGaLocation":30},"/company/team/e-group/","leadership",{"text":327,"config":328},"Équipe",{"href":329,"dataGaName":330,"dataGaLocation":30},"/company/team/","team",{"text":332,"config":333},"Manuel",{"href":334,"dataGaName":335,"dataGaLocation":30},"https://handbook.gitlab.com/","handbook",{"text":337,"config":338},"Relations avec les investisseurs",{"href":339,"dataGaName":340,"dataGaLocation":30},"https://ir.gitlab.com/","investor relations",{"text":342,"config":343},"Centre de confiance",{"href":344,"dataGaName":345,"dataGaLocation":30},"/fr-fr/security/","trust center",{"text":347,"config":348},"Centre pour la transparence de l'IA",{"href":349,"dataGaName":350,"dataGaLocation":30},"/fr-fr/ai-transparency-center/","ai transparency center",{"text":352,"config":353},"Newsletter",{"href":354,"dataGaName":355,"dataGaLocation":30},"/company/contact/","newsletter",{"text":357,"config":358},"Presse",{"href":359,"dataGaName":360,"dataGaLocation":30},"/press/","press",{"text":362,"config":363,"lists":364},"Nous contacter",{"dataNavLevelOne":304},[365],{"items":366},[367,370,375],{"text":37,"config":368},{"href":39,"dataGaName":369,"dataGaLocation":30},"talk to sales",{"text":371,"config":372},"Aide",{"href":373,"dataGaName":374,"dataGaLocation":30},"/support/","get help",{"text":376,"config":377},"Portail clients GitLab",{"href":378,"dataGaName":379,"dataGaLocation":30},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":381,"login":382,"suggestions":389},"Fermer",{"text":383,"link":384},"Pour rechercher des dépôts et des projets, connectez-vous à",{"text":385,"config":386},"gitlab.com",{"href":44,"dataGaName":387,"dataGaLocation":388},"search login","search",{"text":390,"default":391},"Suggestions",[392,395,400,402,407,412],{"text":59,"config":393},{"href":64,"dataGaName":394,"dataGaLocation":388},"GitLab Duo (AI)",{"text":396,"config":397},"Suggestions de code (IA)",{"href":398,"dataGaName":399,"dataGaLocation":388},"/fr-fr/solutions/code-suggestions/","Code Suggestions (AI)",{"text":111,"config":401},{"href":113,"dataGaName":111,"dataGaLocation":388},{"text":403,"config":404},"GitLab sur AWS",{"href":405,"dataGaName":406,"dataGaLocation":388},"/fr-fr/partners/technology-partners/aws/","GitLab on AWS",{"text":408,"config":409},"GitLab sur Google Cloud ",{"href":410,"dataGaName":411,"dataGaLocation":388},"/fr-fr/partners/technology-partners/google-cloud-platform/","GitLab on Google Cloud",{"text":413,"config":414},"Pourquoi utiliser GitLab ?",{"href":72,"dataGaName":415,"dataGaLocation":388},"Why GitLab?",{"freeTrial":417,"mobileIcon":422,"desktopIcon":427},{"text":418,"config":419},"Commencer votre essai gratuit",{"href":420,"dataGaName":35,"dataGaLocation":421},"https://gitlab.com/-/trials/new/","nav",{"altText":423,"config":424},"Icône GitLab",{"src":425,"dataGaName":426,"dataGaLocation":421},"/images/brand/gitlab-logo-tanuki.svg","gitlab icon",{"altText":423,"config":428},{"src":429,"dataGaName":426,"dataGaLocation":421},"/images/brand/gitlab-logo-type.svg",{"freeTrial":431,"mobileIcon":435,"desktopIcon":437},{"text":432,"config":433},"En savoir plus sur GitLab Duo",{"href":64,"dataGaName":434,"dataGaLocation":421},"gitlab duo",{"altText":423,"config":436},{"src":425,"dataGaName":426,"dataGaLocation":421},{"altText":423,"config":438},{"src":429,"dataGaName":426,"dataGaLocation":421},"content:shared:fr-fr:main-navigation.yml","Main Navigation","shared/fr-fr/main-navigation.yml","shared/fr-fr/main-navigation",{"_path":444,"_dir":24,"_draft":6,"_partial":6,"_locale":7,"title":445,"titleMobile":445,"button":446,"config":450,"_id":452,"_type":16,"_source":18,"_file":453,"_stem":454,"_extension":21},"/shared/fr-fr/banner","La plateforme GitLab Duo Agent est maintenant en bêta publique !",{"text":70,"config":447},{"href":448,"dataGaName":449,"dataGaLocation":30},"/fr-fr/gitlab-duo/agent-platform/","duo banner",{"layout":451},"release","content:shared:fr-fr:banner.yml","shared/fr-fr/banner.yml","shared/fr-fr/banner",{"_path":456,"_dir":24,"_draft":6,"_partial":6,"_locale":7,"data":457,"_id":663,"_type":16,"title":664,"_source":18,"_file":665,"_stem":666,"_extension":21},"/shared/fr-fr/main-footer",{"text":458,"source":459,"edit":465,"contribute":470,"config":475,"items":480,"minimal":654},"Git est une marque déposée de Software Freedom Conservancy et notre utilisation de « GitLab » est sous licence",{"text":460,"config":461},"Afficher le code source de la page",{"href":462,"dataGaName":463,"dataGaLocation":464},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":466,"config":467},"Modifier cette page",{"href":468,"dataGaName":469,"dataGaLocation":464},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":471,"config":472},"Veuillez contribuer",{"href":473,"dataGaName":474,"dataGaLocation":464},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":476,"facebook":477,"youtube":478,"linkedin":479},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[481,504,558,591,625],{"title":48,"links":482,"subMenu":487},[483],{"text":484,"config":485},"Plateforme DevSecOps",{"href":57,"dataGaName":486,"dataGaLocation":464},"devsecops platform",[488],{"title":191,"links":489},[490,494,499],{"text":491,"config":492},"Voir les forfaits",{"href":193,"dataGaName":493,"dataGaLocation":464},"view plans",{"text":495,"config":496},"Pourquoi choisir GitLab Premium ?",{"href":497,"dataGaName":498,"dataGaLocation":464},"/fr-fr/pricing/premium/","why premium",{"text":500,"config":501},"Pourquoi choisir GitLab Ultimate ?",{"href":502,"dataGaName":503,"dataGaLocation":464},"/fr-fr/pricing/ultimate/","why ultimate",{"title":505,"links":506},"Solutions",[507,512,515,517,522,527,531,534,537,542,544,546,548,553],{"text":508,"config":509},"Transformation digitale",{"href":510,"dataGaName":511,"dataGaLocation":464},"/fr-fr/topics/digital-transformation/","digital transformation",{"text":137,"config":513},{"href":132,"dataGaName":514,"dataGaLocation":464},"security & compliance",{"text":124,"config":516},{"href":107,"dataGaName":108,"dataGaLocation":464},{"text":518,"config":519},"Développement agile",{"href":520,"dataGaName":521,"dataGaLocation":464},"/fr-fr/solutions/agile-delivery/","agile delivery",{"text":523,"config":524},"Transformation cloud",{"href":525,"dataGaName":526,"dataGaLocation":464},"/fr-fr/topics/cloud-native/","cloud transformation",{"text":528,"config":529},"SCM",{"href":121,"dataGaName":530,"dataGaLocation":464},"source code management",{"text":111,"config":532},{"href":113,"dataGaName":533,"dataGaLocation":464},"continuous integration & delivery",{"text":163,"config":535},{"href":165,"dataGaName":536,"dataGaLocation":464},"value stream management",{"text":538,"config":539},"GitOps",{"href":540,"dataGaName":541,"dataGaLocation":464},"/fr-fr/solutions/gitops/","gitops",{"text":176,"config":543},{"href":178,"dataGaName":179,"dataGaLocation":464},{"text":181,"config":545},{"href":183,"dataGaName":184,"dataGaLocation":464},{"text":186,"config":547},{"href":188,"dataGaName":189,"dataGaLocation":464},{"text":549,"config":550},"Formation",{"href":551,"dataGaName":552,"dataGaLocation":464},"/fr-fr/solutions/education/","education",{"text":554,"config":555},"Services financiers",{"href":556,"dataGaName":557,"dataGaLocation":464},"/fr-fr/solutions/finance/","financial services",{"title":196,"links":559},[560,562,564,566,569,571,575,577,579,581,583,585,587,589],{"text":208,"config":561},{"href":210,"dataGaName":211,"dataGaLocation":464},{"text":213,"config":563},{"href":215,"dataGaName":216,"dataGaLocation":464},{"text":218,"config":565},{"href":220,"dataGaName":221,"dataGaLocation":464},{"text":223,"config":567},{"href":225,"dataGaName":568,"dataGaLocation":464},"docs",{"text":246,"config":570},{"href":248,"dataGaName":249},{"text":572,"config":573},"Histoires de réussite client",{"href":574,"dataGaLocation":464},"/customers/",{"text":241,"config":576},{"href":243,"dataGaName":244,"dataGaLocation":464},{"text":251,"config":578},{"href":253,"dataGaName":254,"dataGaLocation":464},{"text":264,"config":580},{"href":266,"dataGaName":267,"dataGaLocation":464},{"text":256,"config":582},{"href":258,"dataGaName":259,"dataGaLocation":464},{"text":269,"config":584},{"href":271,"dataGaName":272,"dataGaLocation":464},{"text":274,"config":586},{"href":276,"dataGaName":277,"dataGaLocation":464},{"text":279,"config":588},{"href":281,"dataGaName":282,"dataGaLocation":464},{"text":284,"config":590},{"href":286,"dataGaName":287,"dataGaLocation":464},{"title":302,"links":592},[593,595,597,599,601,603,605,609,614,616,618,620],{"text":309,"config":594},{"href":311,"dataGaName":304,"dataGaLocation":464},{"text":314,"config":596},{"href":316,"dataGaName":317,"dataGaLocation":464},{"text":322,"config":598},{"href":324,"dataGaName":325,"dataGaLocation":464},{"text":327,"config":600},{"href":329,"dataGaName":330,"dataGaLocation":464},{"text":332,"config":602},{"href":334,"dataGaName":335,"dataGaLocation":464},{"text":337,"config":604},{"href":339,"dataGaName":340,"dataGaLocation":464},{"text":606,"config":607},"Sustainability",{"href":608,"dataGaName":606,"dataGaLocation":464},"/sustainability/",{"text":610,"config":611},"Diversité, inclusion et appartenance (DIB)",{"href":612,"dataGaName":613,"dataGaLocation":464},"/fr-fr/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":342,"config":615},{"href":344,"dataGaName":345,"dataGaLocation":464},{"text":352,"config":617},{"href":354,"dataGaName":355,"dataGaLocation":464},{"text":357,"config":619},{"href":359,"dataGaName":360,"dataGaLocation":464},{"text":621,"config":622},"Déclaration de transparence sur l'esclavage moderne",{"href":623,"dataGaName":624,"dataGaLocation":464},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"title":362,"links":626},[627,630,632,634,639,644,649],{"text":628,"config":629},"Échanger avec un expert",{"href":39,"dataGaName":40,"dataGaLocation":464},{"text":371,"config":631},{"href":373,"dataGaName":374,"dataGaLocation":464},{"text":376,"config":633},{"href":378,"dataGaName":379,"dataGaLocation":464},{"text":635,"config":636},"Statut",{"href":637,"dataGaName":638,"dataGaLocation":464},"https://status.gitlab.com/","status",{"text":640,"config":641},"Conditions d'utilisation",{"href":642,"dataGaName":643},"/terms/","terms of use",{"text":645,"config":646},"Déclaration de confidentialité",{"href":647,"dataGaName":648,"dataGaLocation":464},"/fr-fr/privacy/","privacy statement",{"text":650,"config":651},"Préférences en matière de cookies",{"dataGaName":652,"dataGaLocation":464,"id":653,"isOneTrustButton":93},"cookie preferences","ot-sdk-btn",{"items":655},[656,658,661],{"text":640,"config":657},{"href":642,"dataGaName":643,"dataGaLocation":464},{"text":659,"config":660},"Politique de confidentialité",{"href":647,"dataGaName":648,"dataGaLocation":464},{"text":650,"config":662},{"dataGaName":652,"dataGaLocation":464,"id":653,"isOneTrustButton":93},"content:shared:fr-fr:main-footer.yml","Main Footer","shared/fr-fr/main-footer.yml","shared/fr-fr/main-footer",{"featuredPost":668,"allPosts":692,"totalPages":1033,"initialPosts":1034},{"_path":669,"_dir":249,"_draft":6,"_partial":6,"_locale":7,"seo":670,"content":675,"config":685,"_id":688,"_type":16,"title":689,"_source":18,"_file":690,"_stem":691,"_extension":21},"/fr-fr/blog/inside-gitlabs-healthy-backlog-initiative",{"config":671,"title":672,"description":673,"ogImage":674},{"noIndex":6},"Amélioration de la gestion des tickets de la communauté","Nous avons amélioré la gestion des tickets pour prioriser le travail stratégique, optimiser la livraison et créer des boucles de rétroaction plus efficaces avec nos utilisateurs. ","https://res.cloudinary.com/about-gitlab-com/image/upload/f_auto,q_auto,c_lfill/v1749664458/Blog/Hero%20Images/Gartner_AI_Code_Assistants_Blog_Post_Cover_Image_1800x945.png",{"title":676,"description":677,"date":678,"body":679,"heroImage":674,"authors":680,"category":14,"tags":682},"Amélioration de la gestion des tickets créés par la communauté GitLab","Découvrez comment nous améliorons la gestion des tickets pour prioriser le travail stratégique, optimiser la livraison de logiciels et créer des boucles de rétroaction plus efficaces avec nos utilisateurs.","2025-07-30","Chez GitLab, nous sommes fiers de la relation solide et collaborative que nous entretenons avec notre communauté. Nous encourageons chacun à contribuer à GitLab. Au fil des années, ces contributions communautaires ont permis de renforcer notre plateforme. Mais au fur et à mesure de notre croissance, la participation de la communauté via les tickets GitLab a également augmenté, créant un backlog de tickets difficile à gérer.\n\nLes équipes chargées du produit et de l'ingénierie de GitLab ont récemment lancé [une initiative pour traiter ce backlog et affiner notre approche de la gestion des tickets](https://gitlab.com/groups/gitlab-org/-/epics/18639). \n\nLes tickets avec un engagement communautaire continu, une activité récente ou un alignement stratégique clair resteront ouverts. Nous fermerons les tickets qui ne sont plus pertinents, qui manquent d'intérêt ou qui ne correspondent plus à notre direction produit.\n\nCette approche ciblée conduira à une innovation accrue, à une meilleure définition des attentes et à des cycles de développement et de livraison plus rapides pour les fonctionnalités proposées par la communauté.\n\n## Présentation de l'initiative\n\nAu fil du temps, la communauté GitLab a soumis des dizaines de milliers de tickets, incluant des bogues, des demandes de fonctionnalités et des retours. Actuellement, [notre système principal de suivi des tickets](https://gitlab.com/gitlab-org/gitlab/-/issues) contient plus de 65 000 tickets. Certains ne sont plus applicables à la plateforme, tandis que d'autres restent toujours pertinents. \n\nAvec cette initiative, nos équipes chargées du produit et de l'ingénierie pourront réduire le backlog et établir un workflow afin de mettre en œuvre une approche plus ciblée de la gestion du backlog. Elles effectueront des évaluations hebdomadaires du backlog pour s'assurer que nous priorisons les tickets qui s'alignent avec notre stratégie produit et notre roadmap.\n\nRemarque : Si vous pensez qu’un ticket fermé s'aligne avec la stratégie produit et la roadmap de GitLab, ou si vous contribuez activement à cette demande, nous vous encourageons à commenter le ticket. Nous nous engageons à examiner ces tickets mis à jour dans le cadre de nos efforts d'évaluation réguliers.\n\n## Quels sont les avantages ?\n\nCette approche rationalisée apporte des améliorations directes et concrètes pour chaque utilisateur de GitLab :\n\n* **Un focus plus précis et une livraison plus rapide :** en recentrant notre backlog sur des fonctionnalités stratégiquement alignées, nous pouvons allouer nos ressources de développement plus efficacement. Cela signifie que vous pouvez vous attendre à des cycles de développement plus courts et à des améliorations plus significatives de votre expérience GitLab.\n* **Des attentes plus claires :** nous nous engageons à communiquer de manière transparente sur ce qui figure ou non dans notre roadmap, afin que vous puissiez prendre des décisions éclairées concernant vos workflows et vos contributions.\n* **Des boucles de rétroaction accélérées :** avec un backlog épuré, les nouveaux retours et demandes de fonctionnalités seront examinés et priorisés plus efficacement, réduisant le temps global de triage et garantissant que les tickets urgents reçoivent l'attention nécessaire. Cela crée une boucle de rétroaction plus réactive pour tous.\n\nCette initiative ne diminue pas l'importance des retours et des contributions de la communauté. Nous prenons cette mesure pour clarifier ce que les membres de l'équipe GitLab peuvent réellement s'engager à livrer, et pour garantir que tous les retours reçoivent la considération appropriée.\n\n## Perspectives d'avenir\n\nCette initiative reflète notre engagement à être des gestionnaires transparents et efficaces de la plateforme GitLab. En communiquant clairement nos priorités et en concentrant nos efforts sur ce que nous pouvons réellement livrer au cours de l'année à venir, nous sommes mieux positionnés pour répondre et dépasser vos attentes.\n\nVotre participation et vos retours continus contribuent à renforcer GitLab. Chaque commentaire, merge request, rapport de bogue et suggestion de fonctionnalité contribue à notre vision commune. Et nous continuons à vous récompenser pour cela, avec des initiatives comme notre programme mensuel Notable Contributor, des récompenses, et plus encore, via notre [portail dédié aux contributeurs](https://contributors.gitlab.com/).\n\nPour en savoir plus sur comment contribuer à GitLab, consultez notre [page Communauté](https://about.gitlab.com/community/). Pour partager vos retours sur cette initiative, veuillez ajouter vos commentaires sur [ce ticket](https://gitlab.com/gitlab-org/gitlab/-/issues/556865).",[681],"Stan Hu",[272,683,684],"product","news",{"featured":6,"template":686,"slug":687},"BlogPost","inside-gitlabs-healthy-backlog-initiative","content:fr-fr:blog:inside-gitlabs-healthy-backlog-initiative.yml","Inside Gitlabs Healthy Backlog Initiative","fr-fr/blog/inside-gitlabs-healthy-backlog-initiative.yml","fr-fr/blog/inside-gitlabs-healthy-backlog-initiative",[693,721,746,770,791,813,834,857,879,902,924,946,967,987,1012],{"_path":694,"_dir":249,"_draft":6,"_partial":6,"_locale":7,"seo":695,"content":703,"config":715,"_id":717,"_type":16,"title":718,"_source":18,"_file":719,"_stem":720,"_extension":21},"/fr-fr/blog/how-we-decreased-gitlab-repo-backup-times-from-48-hours-to-41-minutes",{"ogTitle":696,"schema":697,"ogImage":698,"ogDescription":699,"ogSiteName":700,"noIndex":6,"ogType":701,"ogUrl":702,"title":696,"canonicalUrls":702,"description":699},"Dépôts GitLab : forte diminution des temps de sauvegarde","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Dépôts GitLab : forte diminution des temps de sauvegarde\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Karthik Nayak\"},{\"@type\":\"Person\",\"name\":\"Manuel Kraft\"}],\n        \"datePublished\": \"2025-06-05\",\n      }","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097166/Blog/Hero%20Images/Blog/Hero%20Images/REFERENCE%20-%20display%20preview%20for%20blog%20images%20%282%29_2pKf8RsKzAaThmQfqHIaa7_1750097166565.png","L'optimisation d'une fonction Git vieille de 15 ans a permis d'augmenter la productivité, de renforcer les stratégies de sauvegarde et de réduire les risques.","https://about.gitlab.com","article","https://about.gitlab.com/blog/how-we-decreased-gitlab-repo-backup-times-from-48-hours-to-41-minutes",{"heroImage":698,"body":704,"authors":705,"updatedDate":708,"date":709,"title":710,"tags":711,"description":699,"category":14},"Les sauvegardes de dépôt sont un élément essentiel de toute stratégie de reprise après un sinistre important. Cependant, à mesure que les dépôts grossissent, garantir des sauvegardes fiables devient de plus en plus difficile. Notre propre [dépôt Rails](https://gitlab.com/gitlab-org/gitlab) mettait 48 heures à être sauvegardé, ce qui nous obligeait à faire un choix impossible entre la fréquence des sauvegardes et les performances du système. Nous avons donc décidé de trouver une solution à ce problème pour nos clients et pour nos propres équipes internes.\n\nAprès investigation, nous avons pu déterminer la cause du problème, qui remontait à une fonction Git vieille de 15 ans dont la complexité algorithmique O(N²) freinait lourdement les opérations. Nous l'avons corrigée en repensant l'algorithme et **avons ainsi réduit les temps de sauvegarde de manière exponentielle**. \n\nRésultat : des coûts réduits, des risques diminués, et surtout, des stratégies de sauvegarde désormais adaptées à la croissance de votre code source.\n\nCe problème d'évolutivité de [Git](https://about.gitlab.com/fr-fr/blog/what-is-git/ \"Qu'est-ce que Git ?\") affectait tout utilisateur disposant de grands dépôts. Découvrez dans cet article comment nous l'avons identifié et résolu.\n\n## Sauvegarde à grande échelle : enjeux et solutions\n\nÀ mesure que les entreprises développent leurs dépôts et que les sauvegardes se complexifient, elles sont confrontées aux défis suivants :\n\n* **Sauvegardes trop longues** : pour les très grands dépôts, la sauvegarde peut prendre plusieurs heures, ce qui rend impossible la planification de sauvegardes régulières.\n* **Utilisation intensive des ressources** : ces processus de sauvegarde prolongés mobilisent d'importantes ressources serveur, au risque d'impacter d'autres opérations critiques.\n* **Fenêtres de sauvegarde** : il peut être difficile de trouver des créneaux de maintenance adaptés à des processus aussi longs, en particulier pour les équipes qui fonctionnent 24 h/24 et 7 j/7.\n* **Risque accru d'échec** : les longues sauvegardes sont plus exposées aux interruptions causées par des problèmes réseau, des redémarrages de serveur ou des erreurs système, et obligent souvent les équipes à recommencer tout le processus depuis le début.\n* **Conditions de concurrence** : la durée allongée d'une sauvegarde augmente le risque que le dépôt ait beaucoup changé pendant le processus et peut conduire à une sauvegarde invalide ou à des interruptions liées à des objets devenus indisponibles.\n\nCes défis peuvent conduire à faire des compromis sur la fréquence ou l'exhaustivité des sauvegardes, ce qui est inacceptable en matière de protection des données. L'allongement des fenêtres de sauvegarde peut contraindre certains clients à adopter des solutions de contournement, comme l'utilisation d'outils externes ou la réduction de la fréquence des sauvegardes, ce qui fragilise les stratégies de protection des données au sein des entreprises.\n\nDécouvrez maintenant comment nous avons identifié ce goulot d'étranglement de performance, trouvé une solution et déployé une mesure corrective capable de réduire drastiquement les temps de sauvegarde.\n\n## Le défi technique\n\nLa fonctionnalité de sauvegarde des dépôts de GitLab repose sur la commande [`git bundle create`](https://git-scm.com/docs/git-bundle/fr), qui génère un aperçu complet du dépôt avec tous les objets et références comme les branches et les tags. Ce paquet sert de point de restauration pour recréer le dépôt dans son état exact.\n\nCependant, l'implémentation de cette commande souffrait d'un problème d'évolutivité lié au nombre de références et entraînait un véritable goulot d'étranglement en termes de performance. À mesure que les dépôts accumulaient un nombre croissant de références, le temps de traitement des données augmentait de façon exponentielle. Dans nos plus grands dépôts, contenant des millions de références, les opérations de sauvegarde pouvaient dépasser les 48 heures.\n\n### Analyse des causes profondes\n\nPour identifier la cause profonde de ce ralentissement, nous avons analysé un flame graph de la commande pendant son exécution.\n\n![Flame graph montrant la commande pendant son exécution](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097176/Blog/Content%20Images/Blog/Content%20Images/image1_aHR0cHM6_1750097176388.jpg)\n\nCe graphique illustre le parcours d'exécution d'une commande à travers sa trace de piles d'appels, où chaque barre correspond à une fonction dans le code, et sa largeur indique le temps que la commande a passé à s'exécuter dans cette fonction spécifique.\n\nLe flame graph de `git bundle create` exécuté sur un dépôt contenant 10 000 références révèle qu'environ 80 % du temps d'exécution est consommé par la fonction `object_array_remove_duplicates()`, introduite dans Git par le biais du [commit b2a6d1c686](https://gitlab.com/gitlab-org/git/-/commit/b2a6d1c686) (paquet : permettre à la même référence d'être spécifiée plusieurs fois, 17/01/2009).\n\nPour comprendre ce changement, il est important de savoir que la commande `git bundle create` permet de préciser les références à inclure dans le paquet et que, pour les paquets de dépôt complets, le flag `--all` compacte toutes les références.\n\nCe commit corrigeait un problème lié aux références dupliquées fournies via la ligne de commande, telles que `git bundle create main.bundle main main`, et créait un paquet sans gérer correctement la duplication de la référence « main ». Lors de la décompression, Git tentait d'écrire la même référence deux fois, ce qui provoquait une erreur. \n\nLe code ajouté pour éviter ces duplications utilise des boucles `for` imbriquées qui parcourent toutes les références afin de détecter les doublons. Cet algorithme de complexité O(N²) est un goulot d'étranglement majeur en termes de performance dans les dépôts car il contient un grand nombre de références et prolonge considérablement le temps de traitement des données.\n\n### La solution : d'O(N²) à un mappage efficace\n\nPour résoudre ce problème, nous avons proposé une correction en amont dans Git pour remplacer les boucles imbriquées par une structure de type map. Chaque référence y est ajoutée une seule fois, ce qui élimine automatiquement les doublons et optimise le traitement.\n\nCe changement améliore considérablement les performances de la commande `git bundle create` et garantit une bien meilleure évolutivité dans les dépôts avec un grand nombre de références. Des tests de benchmark effectués sur un dépôt contenant 10 000 références montrent une amélioration des performances par un facteur de 6.\n\n```shell\nBenchmark 1: bundle (refcount = 100000, revision = master)\n  Time (mean ± σ): \t14.653 s ±  0.203 s\t[User: 13.940 s, System: 0.762 s]\n  Range (min … max):   14.237 s … 14.920 s\t10 runs\n\nBenchmark 2: bundle (refcount = 100000, revision = HEAD)\n  Time (mean ± σ):  \t2.394 s ±  0.023 s\t[User: 1.684 s, System: 0.798 s]\n  Range (min … max):\t2.364 s …  2.425 s\t10 runs\n\nSummary\n  bundle (refcount = 100000, revision = HEAD) ran\n  6.12 ± 0.10 times faster than bundle (refcount = 100000, revision = master)\n```\n\nLe correctif a été accepté et [fusionné](https://gitlab.com/gitlab-org/git/-/commit/bb74c0abbc31da35be52999569ea481ebd149d1d) dans Git en amont. Chez GitLab, nous l'avons rétroporté afin que nos clients puissent en bénéficier immédiatement sans attendre la prochaine version officielle de Git.\n\n## Résultat : des temps de sauvegarde radicalement réduits\n\nLes gains de performance qui découlent de cette amélioration sont considérables :\n\n* **De 48 heures à 41 minutes** : la sauvegarde de notre plus grand dépôt (gitlab-org/gitlab) ne prend désormais plus que 1,4 % du temps initial.\n* **Performances constantes** : l'amélioration est stable et s'adapte efficacement, quelle que soit la taille du dépôt.\n* **Efficacité des ressources** : la charge du serveur lors des opérations de sauvegarde a été fortement réduite.\n* **Applicabilité étendue** : si le processus de sauvegarde est celui qui bénéficie le plus de cette amélioration, toutes les opérations basées sur des paquets avec un grand nombre de références en profitent également.\n\n## Avantages pour nos clients GitLab\n\nPour les clients GitLab, cette amélioration apporte des bénéfices immédiats et concrets en matière de sauvegarde de leurs dépôts et de leur planification de reprise après sinistre :\n\n* **Transformation des stratégies de sauvegarde**   \n\n  * Les équipes peuvent désormais planifier des sauvegardes complètes chaque nuit, sans impacter les workflows de développement ni nécessiter de longues fenêtres de maintenance.   \n  * Les sauvegardes s'exécutent désormais en arrière-plan, de manière fluide, pendant les créneaux nocturnes, sans processus longs ni dédiés.  \n* **Continuité des activités améliorée**  \n\n  * Avec des temps de sauvegarde réduits de plusieurs jours à quelques minutes, les objectifs de point de récupération (RPO) sont considérablement réduits, tout comme le risque métier : en cas de sinistre, ce sont potentiellement seulement quelques heures de travail qui sont perdues, au lieu de plusieurs jours.\n* **Réduction de la charge opérationnelle**   \n\n  * La consommation de ressources serveur diminue, tout comme la durée des fenêtres de maintenance.  \n  * Des sauvegardes plus rapides réduisent également les coûts de calcul, en particulier dans les environnements cloud où chaque minute de traitement des données se traduit directement en factures plus élevées.\n* **Pérennisation de l'infrastructure**   \n\n  * La croissance des dépôts ne contraint plus les entreprises à faire des choix difficiles entre la fréquence des sauvegardes et les performances du système.   \n  * À mesure que votre code source se développe, votre stratégie de sauvegarde peut désormais évoluer.\n\nLes entreprises peuvent à présent mettre en œuvre des stratégies de sauvegarde plus robustes sans compromettre les performances ou l'exhaustivité. Ce qui relevait autrefois d'un compromis difficile est devenu une pratique opérationnelle simple.\n\nÀ partir de la version [GitLab 18.0](https://about.gitlab.com/releases/2025/05/15/gitlab-18-0-released/), tous les clients GitLab, quelle que soit leur version de licence, profitent désormais pleinement de ces améliorations pour leur stratégie de sauvegarde et l'exécution de leurs [sauvegardes](https://docs.gitlab.com/administration/backup_restore/backup_gitlab/), sans aucune autre modification de la configuration.\n\n## Et après ?\n\nCette avancée s'inscrit dans notre engagement continu à proposer une infrastructure Git évolutive, adaptée aux exigences des entreprises. Bien que réduire le temps de sauvegarde de 48 heures à 41 minutes représente une étape majeure, nous poursuivons nos efforts pour identifier et éliminer d'autres goulots d'étranglement dans l'ensemble de notre pile.\n\nNous sommes particulièrement fiers que cette amélioration ait été intégrée en amont dans le projet Git afin de profiter non seulement aux utilisateurs de GitLab, mais aussi à l'ensemble de la communauté Git. Cette approche collaborative du développement garantit que les améliorations sont rigoureusement revues, largement testées et accessibles à tous.\n\n> Des travaux d'infrastructure en profondeur comme celui-ci illustrent notre approche de la performance chez GitLab. Consultez le [replay de notre événement virtuel de lancement de GitLab 18](https://about.gitlab.com/fr-fr/eighteen/) et découvrez les autres améliorations fondamentales que nous proposons.",[706,707],"Karthik Nayak","Manuel Kraft","2025-07-09","2025-06-05","Dépôts GitLab : diminution du temps de sauvegarde de 48 h à 41 min ",[712,713,714],"git","open source","performance",{"slug":716,"featured":93,"template":686},"how-we-decreased-gitlab-repo-backup-times-from-48-hours-to-41-minutes","content:fr-fr:blog:how-we-decreased-gitlab-repo-backup-times-from-48-hours-to-41-minutes.yml","How We Decreased Gitlab Repo Backup Times From 48 Hours To 41 Minutes","fr-fr/blog/how-we-decreased-gitlab-repo-backup-times-from-48-hours-to-41-minutes.yml","fr-fr/blog/how-we-decreased-gitlab-repo-backup-times-from-48-hours-to-41-minutes",{"_path":722,"_dir":249,"_draft":6,"_partial":6,"_locale":7,"seo":723,"content":729,"config":740,"_id":742,"_type":16,"title":743,"_source":18,"_file":744,"_stem":745,"_extension":21},"/fr-fr/blog/automating-container-image-migration-from-amazon-ecr-to-gitlab",{"title":724,"description":725,"ogTitle":724,"ogDescription":725,"noIndex":6,"ogImage":726,"ogUrl":727,"ogSiteName":700,"ogType":701,"canonicalUrls":727,"schema":728},"Comment automatiser la migration des images de conteneurs d'Amazon ECR vers GitLab","Suivez ce guide étape par étape pour automatiser le processus de migration de vos images de conteneurs d’Amazon ECR vers GitLab.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663129/Blog/Hero%20Images/blog-image-template-1800x945__28_.png","https://about.gitlab.com/blog/automating-container-image-migration-from-amazon-ecr-to-gitlab","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Comment automatiser la migration des images de conteneurs d'Amazon ECR vers GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Tim Rizzi\"}],\n        \"datePublished\": \"2025-02-13\",\n      }\n                  ",{"title":724,"description":725,"authors":730,"heroImage":726,"date":732,"body":733,"category":14,"tags":734,"updatedDate":739},[731],"Tim Rizzi","2025-02-13","« Nous devons migrer des centaines d'images de conteneurs d'Amazon Elastic Container Registry (ECR) vers GitLab. Pouvez-vous nous aider ? » Cette question revenait sans cesse lors de nos échanges avec des ingénieurs de plateforme. En pleine modernisation de leur chaîne d'outils DevSecOps avec GitLab, ils se retrouvaient bloqués au moment de déplacer leurs images de conteneurs. D’un point de vue technique, chaque transfert est simple. Mais, l'opération était longue et fastidieuse en raison du volume considérable d'images.\n\nUn ingénieur de plateforme a parfaitement résumé la situation : « Je connais parfaitement le processus : effectuer un pull, retagger, effectuer un push. Le problème, c'est que je gère 200 microservices, chacun contenant plusieurs tags. Je ne peux pas passer plusieurs semaines sur cette migration alors que j'ai des tâches critiques à effectuer au niveau de l'infrastructure. »\n\n## Le défi\n\nCette conversation nous a fait réfléchir et a donné naissance à une idée. Et si nous pouvions automatiser l'ensemble du processus ? Lorsqu'une équipe de plateforme DevOps transfère ses [pipelines CI/CD](https://about.gitlab.com/fr-fr/topics/ci-cd/cicd-pipeline/ \"Qu'est-ce qu'un pipeline CI/CD ?\") vers GitLab, la migration des images de conteneurs ne devrait pas poser de difficulté particulière. Le processus manuel est rudimentaire, mais répétitif : il s'agit d'effectuer un pull de chaque image, de la retagger et d'effectuer un push pour la migrer vers le registre de conteneurs de GitLab. Réaliser cette même opération pour des dizaines de dépôts et plusieurs tags par image requiert des jours ou des semaines de travail chronophage.\n\n## La solution\n\nNous avons donc entrepris de créer un pipeline GitLab qui effectuerait automatiquement cette lourde tâche. L'objectif était clair : fournir aux ingénieurs de plateforme un outil qu'ils pourraient configurer en quelques minutes et qui, en une seule nuit, parviendrait à migrer toutes leurs images.\n\n### Configuration des accès\n\nCommençons par l'essentiel : les aspects liés à la sécurité. Nous voulions nous assurer que les équipes puissent exécuter cette migration avec un minimum d'autorisations sur AWS. Voici la politique de gestion des identités et des accès (IAM) en lecture seule dont vous avez besoin :\n\n```json\n{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"ecr:GetAuthorizationToken\",\n                \"ecr:BatchCheckLayerAvailability\",\n                \"ecr:GetDownloadUrlForLayer\",\n                \"ecr:DescribeRepositories\",\n                \"ecr:ListImages\",\n                \"ecr:DescribeImages\",\n                \"ecr:BatchGetImage\"\n            ],\n            \"Resource\": \"*\"\n        }\n    ]\n}\n```\n\n### Configuration de GitLab\n\nUne fois la sécurité en place, l'étape suivante consiste à configurer GitLab. Nous avons volontairement réduit cela au strict minimum : il vous suffit de configurer les variables suivantes dans les paramètres CI/CD de votre projet :\n\n```\nAWS_ACCOUNT_ID: Your AWS account number\nAWS_DEFAULT_REGION: Your ECR region\nAWS_ACCESS_KEY_ID: [Masked]\nAWS_SECRET_ACCESS_KEY: [Masked]\nBULK_MIGRATE: true\n```\n\n### Le pipeline de migration \n\nPassons maintenant à la partie la plus intéressante. Nous avons créé le pipeline en utilisant Docker-in-Docker pour gérer toutes les opérations liées aux images de manière fiable :\n\n```yaml\nimage: docker:20.10\nservices:\n  - docker:20.10-dind\n\nbefore_script:\n  - apk add --no-cache aws-cli jq\n  - aws sts get-caller-identity\n  - aws ecr get-login-password | docker login --username AWS --password-stdin\n  - docker login -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD} ${CI_REGISTRY}\n```\n\nLe pipeline fonctionne en trois phases, chacune s'appuyant sur la précédente :\n\n1. Identification\n\nDans un premier temps, il détecte l'ensemble de vos dépôts :\n\n```bash\nREPOS=$(aws ecr describe-repositories --query 'repositories[*].repositoryName' --output text)\n```\n\n2. Énumération des tags\n\nEnsuite, pour chaque dépôt, il récupère l'ensemble des tags :\n\n```bash\nTAGS=$(aws ecr describe-images --repository-name $repo --query 'imageDetails[*].imageTags[]' --output text)\n```\n\n3. Transfert\n\nEnfin, il gère la migration proprement dite :\n\n```bash\ndocker pull ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${repo}:${tag}\ndocker tag ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${repo}:${tag} ${CI_REGISTRY_IMAGE}/${repo}:${tag}\ndocker push ${CI_REGISTRY_IMAGE}/${repo}:${tag}\n```\n\n## Résultats\n\nVoici ce que cette solution offre comme avantages aux ingénieurs de plateforme qui ne veulent pas passer plusieurs semaines sur la migration :\n\n- Identification et migration automatisées de l'ensemble des dépôts et tags\n- Dénomination cohérente des images entre ECR et GitLab\n- Gestion des échecs de transferts\n- Journalisation claire pour suivre la progression\n\nAu lieu d'écrire des scripts et de surveiller la migration, l'ingénieur de plateforme peut se concentrer sur des tâches à plus grande valeur ajoutée.\n\n## Utilisation\n\nLa première étape est très simple :\n\n1. Copiez le fichier `.gitlab-ci.yml` dans votre dépôt.\n2. Configurez les variables AWS et GitLab.\n3. Définissez `BULK_MIGRATE` sur « true » pour déclencher la migration.\n\n## Bonnes pratiques\n\nEn accompagnant plusieurs équipes dans leur migration, nous avons tiré quelques enseignements pratiques :\n\n- Exécutez la migration en dehors des heures de pointe pour réduire au maximum l'impact sur votre équipe.\n- Consultez les logs de pipeline qui vous indiqueront si un élément nécessite votre attention.\n- Ne désactivez pas votre registre ECR avant d'avoir vérifié que toutes les images ont bien été transférées.\n- Pour les migrations à grande échelle, envisagez d'ajouter une limite de débit pour éviter de saturer votre réseau.\n\nNous mettons ce pipeline à disposition en open source dans notre dépôt GitLab public, car nous sommes convaincus que les ingénieurs de plateforme devraient passer leur temps à créer de la valeur, plutôt qu'à copier des images de conteneurs. N'hésitez pas à l'adapter à vos besoins ou à poser vos questions sur sa mise en œuvre. Consultez notre documentation pour en savoir plus sur les [catalogues CI/CD](https://gitlab.com/explore/catalog/components/package \"Catalogues CI/CD\"). ",[111,735,736,737,683,738],"AWS","tutorial","DevSecOps platform","solutions architecture","2025-04-07",{"slug":741,"featured":93,"template":686},"automating-container-image-migration-from-amazon-ecr-to-gitlab","content:fr-fr:blog:automating-container-image-migration-from-amazon-ecr-to-gitlab.yml","Automating Container Image Migration From Amazon Ecr To Gitlab","fr-fr/blog/automating-container-image-migration-from-amazon-ecr-to-gitlab.yml","fr-fr/blog/automating-container-image-migration-from-amazon-ecr-to-gitlab",{"_path":747,"_dir":249,"_draft":6,"_partial":6,"_locale":7,"seo":748,"content":754,"config":764,"_id":766,"_type":16,"title":767,"_source":18,"_file":768,"_stem":769,"_extension":21},"/fr-fr/blog/using-child-pipelines-to-continuously-deploy-to-five-environments",{"ogTitle":749,"schema":750,"ogImage":751,"ogDescription":752,"ogSiteName":700,"noIndex":6,"ogType":701,"ogUrl":753,"title":749,"canonicalUrls":753,"description":752},"Déployer en continu dans de multiples environnements","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Déployer en continu dans de multiples environnements avec les pipelines enfants\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Olivier Dupré\"}],\n        \"datePublished\": \"2024-09-26\",\n      }","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097012/Blog/Hero%20Images/Blog/Hero%20Images/AdobeStock_397632156_3Ldy1urjMStQCl4qnOBvE0_1750097011626.jpg","Découvrez comment créer un workflow rationalisé dans GitLab pour gérer le déploiement continu dans de multiples environnements.","https://about.gitlab.com/blog/using-child-pipelines-to-continuously-deploy-to-five-environments",{"heroImage":751,"body":755,"authors":756,"updatedDate":758,"date":759,"title":760,"tags":761,"description":752,"category":14},"Les équipes DevSecOps doivent parfois coordonner le déploiement continu dans des environnements différents, tout en préservant leurs workflows. La [plateforme DevSecOps de GitLab](https://about.gitlab.com/fr-fr) répond à ce besoin, de manière simple et efficace, y compris avec des environnements sandbox temporaires créés à la demande. Découvrez dans cet article un exemple de mise en œuvre de ce processus en déployant une architecture avec Terraform sur plusieurs environnements cibles.\n\nCette stratégie s'adapte facilement qu'il s'agisse d'un projet d'Infrastructure as Code (IaC) utilisant une autre technologie comme [Pulumi](https://www.pulumi.com/) ou [Ansible](https://www.ansible.com/), d'un projet de code source ou d'un projet de dépôt monolithique combinant plusieurs langages.\n\nÀ la fin de ce tutoriel, le pipeline que vous aurez créé permettra de déployer :\n\n* Un environnement temporaire de **développement** pour chaque branche de fonctionnalité.\n* Un environnement d'**intégration**, qu'il est facile de supprimer et redéployer à partir de la branche principale.\n* Un environnement d'**assurance qualité (QA)**, également déployé à partir de la branche principale, pour exécuter les étapes de QA.\n* Un environnement de **préproduction** pour chaque tag, dernière étape avant la phase de production.\n* Un environnement de **production** qui dans cet exemple sera déployé manuellement, mais qui peut également être déployé en continu.\n\n> Légende des schémas figurant dans cet article :\n>\n> * Les encarts aux angles arrondis représentent les branches de GitLab.\n> * Les encarts rectangulaires représentent les environnements.\n> * Le texte sur les flèches représente les actions requises pour passer d'un encart à l'autre.\n> * Les encarts carrés représentent une prise de décision.\n\n\u003Cpre class=\"mermaid\">\nflowchart LR\n    A(main) -->|new feature| B(feature_X)\n\n    B -->|auto deploy| C[review/feature_X]\n    B -->|merge| D(main)\n    C -->|destroy| D\n\n    D -->|auto deploy| E[integration]\n    E -->|manual| F[qa]\n\n    D -->|tag| G(X.Y.Z)\n    F -->|validate| G\n\n    G -->|auto deploy| H[staging]\n    H -->|manual| I{plan}\n    I -->|manual| J[production]\n\u003C/pre>\n\nNous allons vous expliquer les [raisons](#why) des [actions](#what) présentées dans le flowchart ci-dessus, ainsi que [les étapes à suivre](#how) pour chacune d'elles. Ce tutoriel sera ainsi plus facile à suivre et vous pourrez le reproduire sans difficulté.\n\n## Raisons\n\n* [L'intégration continue (CI)](https://about.gitlab.com/fr-fr/topics/ci-cd/) constitue quasiment une norme établie. La plupart des entreprises implémentent des pipelines CI ou cherchent à standardiser leurs pratiques.\n* La [livraison continue (CD)](https://about.gitlab.com/fr-fr/topics/ci-cd/), qui consiste à effectuer la publication des artefacts vers un dépôt ou un registre à la fin du pipeline CI, est également courante.\n* L'étape suivante, le [déploiement continu](https://about.gitlab.com/fr-fr/topics/ci-cd/#what-is-continuous-deployment \"Qu'est-ce que le déploiement continu ? \"), qui automatise le déploiement de ces artefacts, est en revanche moins répandu. Il est essentiellement implémenté dans le domaine des applications. Le déploiement continu d'une infrastructure est plus compliqué et implique la gestion de plusieurs environnements. Tester, sécuriser et vérifier le code de l'infrastructure constitue un défi supplémentaire et c'est un domaine où le processus [DevOps](https://about.gitlab.com/fr-fr/topics/devops/ \"Que signifie DevOps ?\") n'a pas encore atteint sa pleine maturité. L'intégration de la sécurité en amont, qui nécessite l'implication des équipes de sécurité, représente également une difficulté. Et il est très important de prendre en compte les problèmes de sécurité dès les premières étapes du développement, afin de passer d'une approche DevOps à un processus **[DevSecOps](https://about.gitlab.com/fr-fr/topics/devsecops/ \"Qu'est-ce que DevSecOps ?\")**.\n\nCe tutoriel vous invite à tester une méthode simple et efficace pour adopter une approche DevSecOps pour votre infrastructure. Nous prendrons l'exemple du déploiement de ressources dans cinq environnements, du développement à la production.\n\n**Remarque :** même si je préconise l'adoption d'une [approche FinOps](https://about.gitlab.com/fr-fr/the-source/platform/finops-balancing-financial-responsibility-and-innovation/ \"Qu'est-ce que l'approche FinOps ? \") et la réduction du nombre d'environnements, il existe parfois d'excellentes raisons de ne pas se limiter aux simples étapes de développement, préproduction et production. N'hésitez pas à adapter les exemples en fonction de vos besoins.\n\n## Actions\n\nL’avènement du cloud a boosté l'utilisation de l'IaC. Ansible et Terraform ont ouvert la voie, suivis par OpenTofu, Pulumi, AWS CDK, Google Deploy Manager et bien d'autres.\n\nUne Infrastructure as Code est la solution parfaite pour déployer une infrastructure de manière sécurisée. Vous pouvez la tester, la déployer et la réappliquer autant de fois que nécessaire pour atteindre votre objectif.\n\nMalheureusement, les entreprises maintiennent souvent plusieurs branches, voire de multiples dépôts, pour chacun de leurs environnements cibles, ce qui crée des problèmes. Elles ne respectent plus un processus rigoureux. Elles ne s'assurent plus que chaque modification du code en production a été soigneusement testée dans les environnements précédents. Par conséquent, des décalages apparaissent peu à peu d'un environnement à l'autre.\n\nJ'ai réalisé que ce tutoriel était nécessaire lors d'une conférence à laquelle j'ai assisté : tous les participants ont déclaré que leur workflow n'imposait des tests rigoureux de l'infrastructure qu'avant le déploiement en production. Et ils ont tous convenu qu'ils appliquaient parfois des correctifs directement en production. Bien sûr, cette démarche permet d'aller vite, mais est-elle sûre ? Comment reporter les correctifs sur les environnements précédents ? Comment vérifier qu'il n'y a pas d'effets de bord ? Comment limiter les risques auxquels votre entreprise est exposée lorsque vous déployez votre code trop rapidement en production ?\n\nLa question essentielle est de savoir *pourquoi* les [équipes DevOps](https://about.gitlab.com/fr-fr/topics/devops/build-a-devops-team/ \"Créer une structure d'équipe DevOps idéale\") déploient directement en production. Le pipeline devrait-il être plus efficace ou plus rapide ? N'est-il pas possible d'automatiser le processus ? Ou, pire encore, n'y a-t-il *aucun moyen de tester le code en dehors de l'environnement de production* ?\n\nDans la section suivante, vous apprendrez à automatiser votre infrastructure et à garantir que votre équipe DevOps mène des tests efficaces avant d'effectuer un push vers un environnement qui affectera le reste du processus. Vous verrez comment sécuriser votre code et contrôler son déploiement de bout en bout.\n\n## Les étapes à suivre\n\nComme mentionné précédemment, de nombreux langages permettent actuellement de gérer l'IaC et nous ne pouvons pas *tous* les aborder ici. Je vais m'appuyer sur un code Terraform version 1.4. Ne prêtez pas attention au langage utilisé pour gérer l'IaC, mais plutôt au processus transposable à votre écosystème.\n\n### Le code Terraform\n\nCommençons par un code Terraform de base.\n\nNous allons déployer sur AWS, un cloud privé virtuel (VPC), qui est un réseau virtuel. Dans ce VPC, nous déploierons un sous-réseau public et un sous-réseau privé. Comme leur nom l'indique, il s'agit de sous-réseaux du VPC principal. Enfin, nous ajouterons une instance Elastic Cloud Compute (EC2) (une machine virtuelle) dans le sous-réseau public.\n\nNous allons ainsi déployer quatre ressources de manière relativement simple. L'idée est de se concentrer sur le pipeline, et non sur le code.\n\nVoici la cible que nous voulons atteindre pour votre dépôt.\n\n![cible du dépôt](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097033/Blog/Content%20Images/Blog/Content%20Images/image5_aHR0cHM6_1750097033415.png)\n\nDécomposons le processus.\n\nTout d'abord, nous déclarons toutes les ressources dans un fichier `terraform/main.tf` :\n\n```terraform\nprovider \"aws\" {\n  region = var.aws_default_region\n}\n\nresource \"aws_vpc\" \"main\" {\n  cidr_block = var.aws_vpc_cidr\n\n  tags = {\n    Name     = var.aws_resources_name\n  }\n}\n\nresource \"aws_subnet\" \"public_subnet\" {\n  vpc_id     = aws_vpc.main.id\n  cidr_block = var.aws_public_subnet_cidr\n\n  tags = {\n    Name = \"Public Subnet\"\n  }\n}\nresource \"aws_subnet\" \"private_subnet\" {\n  vpc_id     = aws_vpc.main.id\n  cidr_block = var.aws_private_subnet_cidr\n\n  tags = {\n    Name = \"Private Subnet\"\n  }\n}\n\nresource \"aws_instance\" \"sandbox\" {\n  ami           = var.aws_ami_id\n  instance_type = var.aws_instance_type\n\n  subnet_id = aws_subnet.public_subnet.id\n\n  tags = {\n    Name     = var.aws_resources_name\n  }\n}\n```\n\nComme vous pouvez le constater, ce code nécessite plusieurs variables. Nous les déclarons dans un fichier `terraform/variables.tf` :\n\n```terraform\nvariable \"aws_ami_id\" {\n  description = \"The AMI ID of the image being deployed.\"\n  type        = string\n}\n\nvariable \"aws_instance_type\" {\n  description = \"The instance type of the VM being deployed.\"\n  type        = string\n  default     = \"t2.micro\"\n}\n\nvariable \"aws_vpc_cidr\" {\n  description = \"The CIDR of the VPC.\"\n  type        = string\n  default     = \"10.0.0.0/16\"\n}\n\nvariable \"aws_public_subnet_cidr\" {\n  description = \"The CIDR of the public subnet.\"\n  type        = string\n  default     = \"10.0.1.0/24\"\n}\n\nvariable \"aws_private_subnet_cidr\" {\n  description = \"The CIDR of the private subnet.\"\n  type        = string\n  default     = \"10.0.2.0/24\"\n}\n\nvariable \"aws_default_region\" {\n  description = \"Default region where resources are deployed.\"\n  type        = string\n  default     = \"eu-west-3\"\n}\n\nvariable \"aws_resources_name\" {\n  description = \"Default name for the resources.\"\n  type        = string\n  default     = \"demo\"\n}\n```\n\nÀ ce stade, nous avons presque terminé la partie IaC. Il nous manque simplement une méthode pour partager les états Terraform. Si vous l'ignorez, Terraform fonctionne schématiquement comme suit :\n\n* La commande `plan` vérifie les différences entre l'infrastructure actuelle et celle définie dans le code. Elle génère ensuite un rapport des différences.\n* La commande `apply` exécute les modifications en fonction du rapport `plan` et met à jour l'état.\n\nLors du premier passage, l'état est vide. Il comporte ensuite les détails (ID, etc.) des ressources appliquées par Terraform.\n\nLe problème est le suivant : où cet état est-il stocké ? Comment le partager pour permettre à plusieurs développeurs et développeuses de collaborer sur le code ?\n\nLa solution est assez simple : stockez et partagez l'état dans GitLab via un [backend HTTP Terraform](https://docs.gitlab.com/ee/user/infrastructure/iac/terraform_state.html).\n\nLorsque vous utilisez ce backend, la première étape consiste à créer le fichier `terraform/backend.tf` le plus simple qui soit. La deuxième étape est prise en charge dans le pipeline.\n\n```terraform\nterraform {\n  backend \"http\" {\n  }\n}\n```\n\nEt voilà ! Nous disposons maintenant d'un code Terraform minimaliste pour déployer ces quatre ressources. Nous renseignerons les valeurs des variables lors de l'exécution à une étape ultérieure.\n\n### Le workflow\n\nMettons en œuvre le workflow suivant :\n\n\u003Cpre class=\"mermaid\">\nflowchart LR\n    A(main) -->|new feature| B(feature_X)\n\n    B -->|auto deploy| C[review/feature_X]\n    B -->|merge| D(main)\n    C -->|destroy| D\n\n    D -->|auto deploy| E[integration]\n    E -->|manual| F[qa]\n\n    D -->|tag| G(X.Y.Z)\n    F -->|validate| G\n\n    G -->|auto deploy| H[staging]\n    H -->|manual| I{plan}\n    I -->|manual| J[production]\n\u003C/pre>\n\n1. Créez une branche de **fonctionnalité**. Elle exécute tous les scanners en continu sur le code pour s'assurer qu'il est toujours conforme et sécurisé. Ce code est déployé en continu dans un environnement temporaire `review/feature_branch` portant le nom de la branche actuelle. Il s'agit d'un environnement sûr où les équipes de développement et d'opérations peuvent tester leur code sans impact sur le reste du Système d’Information (SI). Le processus, comme les revues de code et l'exécution de scanners, est imposé à cette étape pour assurer que la qualité et la sécurité du code sont suffisantes et ne mettent pas votre SI en danger. L'infrastructure déployée par cette branche est automatiquement détruite lorsque la branche est fermée. Vous pouvez ainsi contrôler votre budget.\n2. Une fois approuvée, la branche de fonctionnalité est **fusionnée** dans la branche principale. Il s'agit d'une [branche protégée](https://docs.gitlab.com/ee/user/project/protected_branches.html) où aucun push ne peut être effectué directement. Elle est nécessaire pour veiller à ce que chaque demande de modification de l'environnement de production soit minutieusement testée. Cette branche est également déployée en continu. La cible ici est l'environnement `integration`. La suppression de cet environnement n'est pas automatisée pour des questions de stabilité, mais elle peut être déclenchée manuellement.\n\n\u003Cpre class=\"mermaid\">\nflowchart LR\n    D(main) -->|auto deploy| E[integration]\n\u003C/pre>\n\n3. Une approbation manuelle est ensuite nécessaire pour déclencher le déploiement suivant. La branche principale sera déployée dans l'environnement `qa`. J'ai défini une règle ici pour empêcher la suppression depuis le pipeline. Cet environnement devrait être assez stable (après tout, c'est déjà le troisième) et je souhaite éviter une suppression accidentelle. N'hésitez pas à adapter les règles à vos processus.\n\n\u003Cpre class=\"mermaid\">\nflowchart LR\n    D(main)-->|auto deploy| E[integration]\n    E -->|manual| F[qa]\n\u003C/pre>\n\n4. Pour continuer, nous devons **ajouter un tag** au code. Nous utilisons les [tags protégés](https://docs.gitlab.com/ee/user/project/protected_tags.html) pour que seul un ensemble spécifique d'utilisateurs ait l'autorisation de déployer dans ces deux derniers environnements. Ce tag va immédiatement déclencher un déploiement dans l'environnement `staging`.\n\n\u003Cpre class=\"mermaid\">\nflowchart LR\n    D(main) -->|tag| G(X.Y.Z)\n    F[qa] -->|validate| G\n\n    G -->|auto deploy| H[staging]\n\u003C/pre>\n\n5. Nous arrivons enfin à l'environnement `production`. Il est souvent difficile de déployer l'infrastructure progressivement (10 %, 25 %, etc.). Nous la déployons donc dans son intégralité. Nous contrôlons toutefois ce déploiement à l'aide d'un déclencheur manuel intégré dans cette dernière étape. Afin de garder un contrôle maximal sur cet environnement hautement critique, nous le contrôlons en tant qu'[environnement protégé](https://docs.gitlab.com/ee/ci/environments/protected_environments.html).\n\n\u003Cpre class=\"mermaid\">\nflowchart LR\n    H[staging] -->|manual| I{plan}\n    I -->|manual| J[production]\n\u003C/pre>\n\n### Le pipeline\n\nPour mettre en œuvre le [workflow](#the-workflow) ci-dessus, nous allons maintenant implémenter un pipeline comportant deux [pipelines enfants](https://docs.gitlab.com/ee/ci/pipelines/downstream_pipelines.html).\n\n#### Le pipeline principal\n\nCommençons par le pipeline principal. Il est déclenché automatiquement par un **push effectué vers une branche de fonctionnalité**, une **fusion vers la branche par défaut** ou un **tag**. *Il* effectue un vrai **déploiement continu** dans les environnements suivants : `dev`, `integration` et `staging`. Il est déclaré dans le fichier `.gitlab-ci.yml` à la racine de votre projet.\n\n![la cible du dépôt](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097033/Blog/Content%20Images/Blog/Content%20Images/image1_aHR0cHM6_1750097033417.png)\n\n```yml\nstages:\n  - test\n  - environments\n\n.environment:\n  stage: environments\n  variables:\n    TF_ROOT: terraform\n    TF_CLI_ARGS_plan: \"-var-file=../vars/$variables_file.tfvars\"\n  trigger:\n    include: .gitlab-ci/.first-layer.gitlab-ci.yml\n    strategy: depend            # Wait for the triggered pipeline to successfully complete\n    forward:\n      yaml_variables: true      # Forward variables defined in the trigger job\n      pipeline_variables: true  # Forward manual pipeline variables and scheduled pipeline variables\n\nreview:\n  extends: .environment\n  variables:\n    environment: review/$CI_COMMIT_REF_SLUG\n    TF_STATE_NAME: $CI_COMMIT_REF_SLUG\n    variables_file: review\n    TF_VAR_aws_resources_name: $CI_COMMIT_REF_SLUG  # Used in the tag Name of the resources deployed, to easily differenciate them\n  rules:\n    - if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n\nintegration:\n  extends: .environment\n  variables:\n    environment: integration\n    TF_STATE_NAME: $environment\n    variables_file: $environment\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n\nstaging:\n  extends: .environment\n  variables:\n    environment: staging\n    TF_STATE_NAME: $environment\n    variables_file: $environment\n  rules:\n    - if: $CI_COMMIT_TAG\n\n#### TWEAK\n# This tweak is needed to display vulnerability results in the merge widgets.\n# As soon as this issue https://gitlab.com/gitlab-org/gitlab/-/issues/439700 is resolved, the `include` instruction below can be removed.\n# Until then, the SAST IaC scanners will run in the downstream pipelines, but their results will not be available directly in the merge request widget, making it harder to track them.\n# Note: This workaround is perfectly safe and will not slow down your pipeline.\ninclude:\n  - template: Security/SAST-IaC.gitlab-ci.yml\n#### END TWEAK\n```\n\nCe pipeline n'exécute que deux étapes : `test` et  `environments`. La première est nécessaire pour que le *TWEAK* exécute les scanners. La seconde déclenche un pipeline enfant contenant un ensemble de variables différent pour chaque cas défini ci-dessus (push vers la branche, fusion dans la branche par défaut ou tag).\n\nNous ajoutons ici une dépendance avec le mot-clé [strategy:depend](https://docs.gitlab.com/ee/ci/yaml/index.html#triggerstrategy) sur notre pipeline enfant afin que la vue du pipeline dans GitLab ne soit mise à jour qu'une fois le déploiement terminé.\n\nComme vous le voyez, nous définissons un job de base [masqué](https://docs.gitlab.com/ee/ci/jobs/#hide-jobs), puis nous ajoutons des variables et des règles spécifiques afin de déclencher un seul déploiement pour chaque environnement cible.\n\nOutre les [variables prédéfinies](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html), nous utilisons deux nouveaux éléments que nous devons définir :\n\n1. [Les variables spécifiques](#the-variable-definitions) à chaque environnement : `../vars/$variables_file.tfvars`\n2. [Le pipeline enfant](#the-child-pipeline), défini dans `.gitlab-ci/.first-layer.gitlab-ci.yml`\n\nCommençons par le plus rapide, les définitions des variables.\n\n### Les définitions des variables\n\nNous allons ici mélanger deux solutions pour fournir des variables à Terraform :\n\n* La première utilise des [fichiers .tfvars](https://developer.hashicorp.com/terraform/language/values/variables#variable-definitions-tfvars-files) pour tous les intrants ne contenant pas de données sensibles, qui doivent être stockées dans GitLab.\n\n![solution 1 pour fournir des variables à Terraform](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097034/Blog/Content%20Images/Blog/Content%20Images/image2_aHR0cHM6_1750097033419.png)\n\n* La seconde utilise des [variables d'environnement](https://developer.hashicorp.com/terraform/language/values/variables#environment-variables) avec le préfixe `TF_VAR`. Combinée à la capacité de GitLab à [masquer les variables](https://docs.gitlab.com/ee/ci/variables/#mask-a-cicd-variable), à [les protéger](https://docs.gitlab.com/ee/ci/variables/#protect-a-cicd-variable) et à les rendre [accessibles uniquement pour certains environnements](https://docs.gitlab.com/ee/ci/environments/index.html#limit-the-environment-scope-of-a-cicd-variable), cette deuxième façon d'injecter des variables est une solution puissante pour **empêcher les fuites d'informations contenant des données sensibles**. Par exemple, si vous considérez que le routage CIDR privé de votre environnement de production est une donnée sensible, vous pouvez le protéger de cette manière. Veillez à ce qu'il ne soit disponible que pour l'environnement `production`, pour les pipelines fonctionnant avec des branches et des tags protégés, et que sa valeur soit masquée dans les journaux du job.\n\n![solution 2 pour fournir des variables à Terraform](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097034/Blog/Content%20Images/Blog/Content%20Images/image4_aHR0cHM6_1750097033422.png)\n\nDe plus, chaque fichier de variables doit être contrôlé via un [fichier `CODEOWNERS`](https://docs.gitlab.com/ee/user/project/codeowners/) où sont définies les personnes ayant l'autorisation d'apporter des modifications.\n\n```\n[Production owners] \nvars/production.tfvars @operations-group\n\n[Staging owners]\nvars/staging.tfvars @odupre @operations-group\n\n[CodeOwners owners]\nCODEOWNERS @odupre\n```\n\nCet article n'a pas pour but d'expliquer Terraform, nous allons donc simplement montrer le fichier `vars/review.tfvars`. Les fichiers d'environnement suivants sont, bien sûr, très similaires. Il suffit de définir les variables ne contenant pas de données sensibles et leurs valeurs ici.\n\n```shell\naws_vpc_cidr = \"10.1.0.0/16\"\naws_public_subnet_cidr = \"10.1.1.0/24\"\naws_private_subnet_cidr = \"10.1.2.0/24\"\n```\n\n#### Le pipeline enfant\n\nC'est dans ce pipeline que le travail concret est effectué. Il est donc un peu plus complexe que le premier. Mais rien qu'on ne puisse surmonter ensemble !\n\nComme nous l'avons vu dans la définition du pipeline principal, ce pipeline enfant est déclaré dans le fichier `.gitlab-ci/.first-layer.gitlab-ci.yml`.\n\n![Pipeline downstream déclaré dans le fichier](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097033/Blog/Content%20Images/Blog/Content%20Images/image3_aHR0cHM6_1750097033424.png)\n\nDécomposons-le en petites étapes avant de revenir à une vue d'ensemble.\n\n##### Exécution des commandes Terraform et sécurisation du code\n\nNous allons d'abord mettre en place un pipeline pour Terraform. GitLab est une plateforme open source tout comme notre template de pipeline pour Terraform. Il vous suffit de l'inclure, en utilisant l'extrait de code suivant :\n\n```yml\ninclude:\n  - template: Terraform.gitlab-ci.yml\n```\n\nCe template exécute les vérifications Terraform sur le formatage et valide votre code, avant de le planifier et de l'appliquer. Il vous permet également de détruire ce que vous avez déployé.\n\nEn tant que plateforme DevSecOps unifiée, GitLab intègre deux scanners de sécurité directement dans ce template afin de détecter les menaces potentielles dans votre code et de vous avertir avant tout déploiement dans les environnements suivants.\n\nMaintenant que nous avons vérifié, sécurisé, compilé et déployé notre code, explorons quelques astuces supplémentaires.\n\n##### Partage du cache entre les jobs\n\nPour réutiliser les résultats des jobs dans les étapes suivantes du pipeline, nous allons activer la mise en cache. Il suffit d'ajouter le code suivant :\n\n```yml\ndefault:\n  cache:  # Use a shared cache or tagged runners to ensure terraform can run on apply and destroy\n    - key: cache-$CI_COMMIT_REF_SLUG\n      fallback_keys:\n        - cache-$CI_DEFAULT_BRANCH\n      paths:\n        - .\n```\n\nNous définissons ici un cache différent pour chaque commit, en revenant au nom de la branche principale si nécessaire.\n\nEn regardant de près les templates utilisés, on observe qu’ils contiennent des règles contrôlant l’exécution des jobs. Nous voulons exécuter tous les contrôles (assurance qualité et sécurité) sur toutes les branches. Nous allons donc personnaliser ces paramètres.\n\n##### Exécution des contrôles sur toutes les branches\n\nLes templates GitLab offrent une fonctionnalité puissante permettant de modifier uniquement certaines parties d’un template. Nous souhaitons seulement remplacer les règles de certains jobs afin de toujours exécuter des contrôles d'assurance qualité et de sécurité. Les autres paramètres de ces jobs resteront conformes au template.\n\n```yml\nfmt:\n  rules:\n    - when: always\n\nvalidate:\n  rules:\n    - when: always\n\nkics-iac-sast:\n  rules:\n    - when: always\n\niac-sast:\n  rules:\n    - when: always\n```\n\nMaintenant que nous avons appliqué les contrôles d'assurance qualité et de sécurité, nous voulons différencier le comportement des environnements principaux (intégration et préproduction) dans le [workflow](#the-workflow) par rapport aux environnements de revue. Commençons par définir le comportement des environnements principaux. Nous modifierons ensuite cette configuration pour les environnements de revue.\n\n##### Pipeline CD pour l'intégration et la préproduction\n\nComme indiqué, nous voulons déployer la branche principale et les tags dans ces deux environnements. Nous ajoutons des règles pour contrôler ce déploiement sur les jobs `build` et `deploy`. Ensuite, nous activons la fonction `destroy` uniquement pour `integration`, car l'environnement `staging` est trop critique pour être supprimé en un seul clic. Les erreurs sont possibles et nous souhaitons les éviter.\n\nEnfin, nous relions le job `deploy` au job `destroy`, afin de pouvoir déclencher un `stop` sur l'environnement directement à partir de l'interface utilisateur graphique de GitLab.\n\n`GIT_STRATEGY` positionné à `none` empêche la récupération du code de la branche source dans le runner lors de la destruction. L'opération échouerait si la branche avait été supprimée manuellement. Nous comptons donc sur le cache pour obtenir tout ce dont nous avons besoin pour exécuter les instructions Terraform.\n\n```yml\nbuild:  # terraform plan\n  environment:\n    name: $TF_STATE_NAME\n    action: prepare\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n    - if: $CI_COMMIT_TAG\n\ndeploy: # terraform apply --> automatically deploy on corresponding env (integration or staging) when merging to default branch or tagging. Second layer environments (qa and production) will be controlled manually\n  environment: \n    name: $TF_STATE_NAME\n    action: start\n    on_stop: destroy\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n    - if: $CI_COMMIT_TAG\n\ndestroy:\n  extends: .terraform:destroy\n  variables:\n    GIT_STRATEGY: none\n  dependencies:\n    - build\n  environment:\n    name: $TF_STATE_NAME\n    action: stop\n  rules:\n    - if: $CI_COMMIT_TAG  # Do not destroy production\n      when: never\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $TF_DESTROY == \"true\" # Manually destroy integration env.\n      when: manual\n```\n\nComme indiqué, cela nous permet de déployer sur les environnements `integration` et `staging`. Mais il manque toujours un environnement temporaire où les développeurs et développeuses peuvent expérimenter et valider leur code sans affecter le travail des autres. C'est tout l'intérêt du déploiement dans l'environnement `review`.\n\n##### Pipeline CD pour les environnements de revue\n\nLe déploiement dans l'environnement de revue n'est pas très différent du déploiement dans les environnements `integration` et `staging`. Nous allons une fois de plus tirer parti de la capacité de GitLab à remplacer uniquement des éléments de définition de job.\n\nTout d'abord, nous définissons des règles pour exécuter ces jobs uniquement sur les branches de fonctionnalités.\n\nEnsuite, nous relions le job `deploy_review` à `destroy_review`. Nous pouvons ainsi arrêter l'environnement **manuellement** à partir de l'interface utilisateur de GitLab. Plus important encore, ce job **déclenche automatiquement la destruction de l'environnement** lorsque la branche de fonctionnalité est fermée. Cette bonne pratique FinOps vous aide à contrôler vos dépenses opérationnelles.\n\nPuisque Terraform a besoin d'un fichier de plan pour la destruction d'une infrastructure, comme pour la compilation, nous ajoutons une dépendance de `destroy_review` à `build_review` afin de récupérer ses artefacts.\n\nEnfin, nous voyons ici que le nom de l'environnement est `$environment`. Il a été défini sur `review/$CI_COMMIT_REF_SLUG` dans le [pipeline principal](#the-main-pipeline) et transmis à ce pipeline enfant avec l'instruction `trigger:forward:yaml_variables:true`.\n\n```yml\nbuild_review:\n  extends: build\n  rules:\n    - if: $CI_COMMIT_TAG\n      when: never\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: on_success\n\ndeploy_review:\n  extends: deploy\n  dependencies:\n    - build_review\n  environment:\n    name: $environment\n    action: start\n    on_stop: destroy_review\n    # url: https://$CI_ENVIRONMENT_SLUG.example.com\n  rules:\n    - if: $CI_COMMIT_TAG\n      when: never\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: on_success\n\ndestroy_review:\n  extends: destroy\n  dependencies:\n    - build_review\n  environment:\n    name: $environment\n    action: stop\n  rules:\n    - if: $CI_COMMIT_TAG  # Do not destroy production\n      when: never\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH   # Do not destroy staging\n      when: never\n    - when: manual\n```\n\nPour récapituler, nous avons maintenant un pipeline qui peut :\n\n* Déployer des environnements de revue temporaires, qui sont automatiquement détruits lorsque la branche de fonctionnalité est fermée\n* Déployer en continu la **branche par défaut** sur `integration`\n* Déployer en continu les **tags** sur l'environnement `staging`\n\nAjoutons maintenant un niveau supplémentaire, où nous allons déployer sur les environnements `qa` et `production` avec un déclencheur manuel.\n\n##### Pipeline CD pour l'assurance qualité et la production\n\nComme tout le monde n'est pas prêt à effectuer des déploiements continus en production, nous ajoutons une validation manuelle pour les deux prochains déploiements. À strictement parler, nous ne devrions pas ajouter ce déclencheur dans un processus **CD**, mais profitons de cette occasion pour vous apprendre à exécuter des jobs à partir d'autres déclencheurs.\n\nJusqu'à présent, nous avons lancé un [pipeline enfant](#the-child-pipeline) à partir du [pipeline principal](#the-main-pipeline) pour exécuter tous les déploiements.\n\nComme nous voulons exécuter d'autres déploiements à partir de la branche par défaut et des tags, nous ajoutons un nouveau niveau pour ces étapes supplémentaires. Rien de bien nouveau. Nous allons répéter le processus utilisé pour le [pipeline principal](#the-main-pipeline). En procédant de cette façon, vous pouvez manipuler autant de niveaux que vous le souhaitez. J'ai déjà vu jusqu'à neuf environnements.\n\nSans revenir sur les avantages d'un nombre limité d'environnements, le processus que nous utilisons ici permet d'implémenter très facilement le même pipeline, de la phase initiale jusqu’à la livraison finale, tout en gardant la définition de votre pipeline simple et divisée en petits segments que vous pouvez maintenir facilement.\n\nPour éviter les conflits de variables, nous utilisons simplement de nouveaux noms pour identifier l'état Terraform et le fichier d'intrant.\n\n```yml\n.2nd_layer:\n  stage: 2nd_layer\n  variables:\n    TF_ROOT: terraform\n  trigger:\n    include: .gitlab-ci/.second-layer.gitlab-ci.yml\n    # strategy: depend            # Do NOT wait for the downstream pipeline to finish to mark upstream pipeline as successful. Otherwise, all pipelines will fail when reaching the pipeline timeout before deployment to 2nd layer.\n    forward:\n      yaml_variables: true      # Forward variables defined in the trigger job\n      pipeline_variables: true  # Forward manual pipeline variables and scheduled pipeline variables\n\nqa:\n  extends: .2nd_layer\n  variables:\n    TF_STATE_NAME_2: qa\n    environment: $TF_STATE_NAME_2\n    TF_CLI_ARGS_plan_2: \"-var-file=../vars/$TF_STATE_NAME_2.tfvars\"\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n\nproduction:\n  extends: .2nd_layer\n  variables:\n    TF_STATE_NAME_2: production\n    environment: $TF_STATE_NAME_2\n    TF_CLI_ARGS_plan_2: \"-var-file=../vars/$TF_STATE_NAME_2.tfvars\"\n  rules:\n    - if: $CI_COMMIT_TAG\n```\n\n**Un point important ici est la stratégie utilisée pour le nouveau pipeline enfant.** Nous maintenons la valeur par défaut du déclencheur `trigger:strategy`. Dans le cas contraire, le [pipeline principal](#the-main-pipeline) attend la fin de votre [pipeline de niveau « petit-enfant »](#the-grand-child-pipeline). Si vous utilisez un déclencheur manuel, cette opération peut prendre beaucoup de temps et rendre votre tableau de bord de pipeline plus difficile à lire et à comprendre.\n\nVous vous demandez probablement ce que contient le fichier `.gitlab-ci/.second-layer.gitlab-ci.yml` qui est inclus ici. Nous aborderons cette question dans la section suivante.\n\n##### Le premier niveau complet de définition de pipeline\n\nSi vous recherchez une vue complète de ce premier niveau (stocké dans `.gitlab-ci/.first-layer.gitlab-ci.yml`), consultez la section suivante.\n\n```yml\nvariables:\n  TF_VAR_aws_ami_id: $AWS_AMI_ID\n  TF_VAR_aws_instance_type: $AWS_INSTANCE_TYPE\n  TF_VAR_aws_default_region: $AWS_DEFAULT_REGION\n\ninclude:\n  - template: Terraform.gitlab-ci.yml\n\ndefault:\n  cache:  # Use a shared cache or tagged runners to ensure terraform can run on apply and destroy\n    - key: cache-$CI_COMMIT_REF_SLUG\n      fallback_keys:\n        - cache-$CI_DEFAULT_BRANCH\n      paths:\n        - .\n\nstages:\n  - validate\n  - test\n  - build\n  - deploy\n  - cleanup\n  - 2nd_layer       # Use to deploy a 2nd environment on both the main branch and on the tags\n\nfmt:\n  rules:\n    - when: always\n\nvalidate:\n  rules:\n    - when: always\n\nkics-iac-sast:\n  rules:\n    - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'\n      when: never\n    - if: $SAST_EXCLUDED_ANALYZERS =~ /kics/\n      when: never\n    - when: on_success\n\niac-sast:\n  rules:\n    - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'\n      when: never\n    - if: $SAST_EXCLUDED_ANALYZERS =~ /kics/\n      when: never\n    - when: on_success\n\n###########################################################################################################\n## Integration env. and Staging. env\n##  * Auto-deploy to Integration on merge to main.\n##  * Auto-deploy to Staging on tag.\n##  * Integration can be manually destroyed if TF_DESTROY is set to true.\n##  * Destroy of next env. is not automated to prevent errors.\n###########################################################################################################\nbuild:  # terraform plan\n  environment:\n    name: $TF_STATE_NAME\n    action: prepare\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n    - if: $CI_COMMIT_TAG\n\ndeploy: # terraform apply --> automatically deploy on corresponding env (integration or staging) when merging to default branch or tagging. Second layer environments (qa and production) will be controlled manually\n  environment: \n    name: $TF_STATE_NAME\n    action: start\n    on_stop: destroy\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n    - if: $CI_COMMIT_TAG\n\ndestroy:\n  extends: .terraform:destroy\n  variables:\n    GIT_STRATEGY: none\n  dependencies:\n    - build\n  environment:\n    name: $TF_STATE_NAME\n    action: stop\n  rules:\n    - if: $CI_COMMIT_TAG  # Do not destroy production\n      when: never\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $TF_DESTROY == \"true\" # Manually destroy integration env.\n      when: manual\n###########################################################################################################\n\n###########################################################################################################\n## Dev env.\n##  * Temporary environment. Lives and dies with the Merge Request.\n##  * Auto-deploy on push to feature branch.\n##  * Auto-destroy on when Merge Request is closed.\n###########################################################################################################\nbuild_review:\n  extends: build\n  rules:\n    - if: $CI_COMMIT_TAG\n      when: never\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: on_success\n\ndeploy_review:\n  extends: deploy\n  dependencies:\n    - build_review\n  environment:\n    name: $environment\n    action: start\n    on_stop: destroy_review\n    # url: https://$CI_ENVIRONMENT_SLUG.example.com\n  rules:\n    - if: $CI_COMMIT_TAG\n      when: never\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: on_success\n\ndestroy_review:\n  extends: destroy\n  dependencies:\n    - build_review\n  environment:\n    name: $environment\n    action: stop\n  rules:\n    - if: $CI_COMMIT_TAG  # Do not destroy production\n      when: never\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH   # Do not destroy staging\n      when: never\n    - when: manual\n###########################################################################################################\n\n###########################################################################################################\n## Second layer\n##  * Deploys from main branch to qa env.\n##  * Deploys from tag to production.\n###########################################################################################################\n.2nd_layer:\n  stage: 2nd_layer\n  variables:\n    TF_ROOT: terraform\n  trigger:\n    include: .gitlab-ci/.second-layer.gitlab-ci.yml\n    # strategy: depend            # Do NOT wait for the downstream pipeline to finish to mark upstream pipeline as successful. Otherwise, all pipelines will fail when reaching the pipeline timeout before deployment to 2nd layer.\n    forward:\n      yaml_variables: true      # Forward variables defined in the trigger job\n      pipeline_variables: true  # Forward manual pipeline variables and scheduled pipeline variables\n\nqa:\n  extends: .2nd_layer\n  variables:\n    TF_STATE_NAME_2: qa\n    environment: $TF_STATE_NAME_2\n    TF_CLI_ARGS_plan_2: \"-var-file=../vars/$TF_STATE_NAME_2.tfvars\"\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n\nproduction:\n  extends: .2nd_layer\n  variables:\n    TF_STATE_NAME_2: production\n    environment: $TF_STATE_NAME_2\n    TF_CLI_ARGS_plan_2: \"-var-file=../vars/$TF_STATE_NAME_2.tfvars\"\n  rules:\n    - if: $CI_COMMIT_TAG\n###########################################################################################################\n```\n\nÀ cette étape, nous avons déjà effectué des déploiements vers trois environnements en toute sécurité. Je trouve personnellement que cette démarche est idéale. Cependant, si vous avez besoin d'autres environnements, ajoutez-les à votre pipeline CD.\n\nVous avez sûrement remarqué que nous incluons un pipeline enfant avec le mot-clé `trigger:include`. Il inclut le fichier `.gitlab-ci/.second-layer.gitlab-ci.yml`. Nous souhaitons exécuter un pipeline très similaire, son contenu ressemble donc évidemment beaucoup à celui présenté ci-dessus. Le principal avantage de ce [pipeline de niveau « petit-enfant »](#the-grand-child-pipeline) est qu'il existe par lui-même, ce qui facilite la définition des variables et des règles.\n\n### Le pipeline de niveau « petit-enfant »\n\nCe pipeline de deuxième couche est tout nouveau. Par conséquent, il doit imiter la définition de la première couche, à savoir :\n\n* [Il doit inclure le template Terraform](#run-terraform-commands-and-secure-the-code).\n* [Il doit exécuter des contrôles de sécurité](#run-controls-on-all-branches). La validation Terraform dupliquerait le premier niveau, mais les scanners de sécurité peuvent identifier des menaces qui n'existaient pas encore lors des précédents scans (par exemple, si vous déployez en production quelques jours après votre déploiement en préproduction).\n* [Il doit remplacer les jobs de compilation et de déploiement pour définir des règles spécifiques](#cd-to-review-environments). Notez que l'étape `destroy` n'est plus automatisée pour éviter des suppressions accidentelles.\n\nComme expliqué ci-dessus, les variables `TF_STATE_NAME` et `TF_CLI_ARGS_plan` sont copiées du pipeline principal au pipeline enfant. Nous avions besoin d'un nom de variable différent pour transférer ces valeurs du pipeline enfant au pipeline « petit-enfant ». C'est pourquoi, dans le pipeline enfant, les noms de ces variables incluent le suffixe `_2`. La valeur est ensuite copiée dans la variable correspondante appropriée lors de l'exécution de la section `before_script`.\n\nComme nous avons déjà décomposé chaque étape, nous pouvons passer directement à la vue d'ensemble du deuxième niveau (codé dans `.gitlab-ci/.second-layer.gitlab-ci.yml`).\n\n```yml\n# Use to deploy a second environment on both the default branch and the tags.\n\ninclude:\n  template: Terraform.gitlab-ci.yml\n\nstages:\n  - validate\n  - test\n  - build\n  - deploy\n\nfmt:\n  rules:\n    - when: never\n\nvalidate:\n  rules:\n    - when: never\n\nkics-iac-sast:\n  rules:\n    - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'\n      when: never\n    - if: $SAST_EXCLUDED_ANALYZERS =~ /kics/\n      when: never\n    - when: always\n\n###########################################################################################################\n## QA env. and Prod. env\n##  * Manually trigger build and auto-deploy in QA\n##  * Manually trigger both build and deploy in Production\n##  * Destroy of these env. is not automated to prevent errors.\n###########################################################################################################\nbuild:  # terraform plan\n  cache:  # Use a shared cache or tagged runners to ensure terraform can run on apply and destroy\n    - key: $TF_STATE_NAME_2\n      fallback_keys:\n        - cache-$CI_DEFAULT_BRANCH\n      paths:\n        - .\n  environment:\n    name: $TF_STATE_NAME_2\n    action: prepare\n  before_script:  # Hack to set new variable values on the second layer, while still using the same variable names. Otherwise, due to variable precedence order, setting new value in the trigger job, does not cascade these new values to the downstream pipeline\n    - TF_STATE_NAME=$TF_STATE_NAME_2\n    - TF_CLI_ARGS_plan=$TF_CLI_ARGS_plan_2\n  rules:\n    - when: manual\n\ndeploy: # terraform apply\n  cache:  # Use a shared cache or tagged runners to ensure terraform can run on apply and destroy\n    - key: $TF_STATE_NAME_2\n      fallback_keys:\n        - cache-$CI_DEFAULT_BRANCH\n      paths:\n        - .\n  environment: \n    name: $TF_STATE_NAME_2\n    action: start\n  before_script:  # Hack to set new variable values on the second layer, while still using the same variable names. Otherwise, due to variable precedence order, setting new value in the trigger job, does not cascade these new values to the downstream pipeline\n    - TF_STATE_NAME=$TF_STATE_NAME_2\n    - TF_CLI_ARGS_plan=$TF_CLI_ARGS_plan_2\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n    - if: $CI_COMMIT_TAG && $TF_AUTO_DEPLOY == \"true\"\n    - if: $CI_COMMIT_TAG\n      when: manual\n###########################################################################################################\n```\n\nVoilà qui est fait. **Tout est prêt.** N'hésitez pas à changer la façon dont vous contrôlez l'exécution de vos jobs, en tirant parti, par exemple, de la capacité de GitLab à [retarder un job](https://docs.gitlab.com/ee/ci/jobs/job_control.html#run-a-job-after-a-delay) avant de le déployer en production.\n\n## Essayez par vous-même\n\nCe tutoriel est maintenant terminé. Nous savons désormais comment contrôler les **déploiements vers cinq environnements différents** en utilisant uniquement les **branches de fonctionnalités**, la **branche principale** et les **tags**.\n\n* Nous réutilisons intensivement les templates open source GitLab pour assurer la productivité et la sécurité de nos pipelines.\n* Nous tirons parti des capacités du template GitLab pour remplacer uniquement les blocs nécessitant un contrôle personnalisé.\n* Nous avons divisé le pipeline en petits segments et contrôlons les pipelines enfants afin qu'ils correspondent exactement à nos besoins.\n\nÀ vous de jouer maintenant. Vous pouvez, par exemple, facilement mettre à jour le pipeline principal afin de déclencher des pipelines enfants, pour votre code source logiciel, avec le mot-clé [trigger:rules:changes](https://docs.gitlab.com/ee/ci/yaml/#ruleschanges). Vous pouvez utiliser un autre [template](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/ci/templates/) en fonction des changements qui se sont produits. Mais c'est une autre histoire.",[757],"Olivier Dupré","2025-01-09","2024-09-26","Déployer en continu dans de multiples environnements avec les pipelines enfants",[111,762,763,737,736],"CI","CD",{"slug":765,"featured":6,"template":686},"using-child-pipelines-to-continuously-deploy-to-five-environments","content:fr-fr:blog:using-child-pipelines-to-continuously-deploy-to-five-environments.yml","Using Child Pipelines To Continuously Deploy To Five Environments","fr-fr/blog/using-child-pipelines-to-continuously-deploy-to-five-environments.yml","fr-fr/blog/using-child-pipelines-to-continuously-deploy-to-five-environments",{"_path":771,"_dir":249,"_draft":6,"_partial":6,"_locale":7,"seo":772,"content":778,"config":785,"_id":787,"_type":16,"title":788,"_source":18,"_file":789,"_stem":790,"_extension":21},"/fr-fr/blog/building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way",{"title":773,"description":774,"ogTitle":773,"ogDescription":774,"noIndex":6,"ogImage":775,"ogUrl":776,"ogSiteName":700,"ogType":701,"canonicalUrls":776,"schema":777},"GitLab CI/CD : comment créer facilement un pipeline pour un monorepo","Découvrez comment configurer un pipeline CI/CD dans GitLab pour un dépôt monorepo et simplifier l'hébergement de plusieurs applications dans un seul dépôt.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749660151/Blog/Hero%20Images/blog-image-template-1800x945__26_.png","https://about.gitlab.com/blog/building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLab CI/CD : comment créer facilement un pipeline pour un monorepo\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Sam Morris\"}],\n        \"datePublished\": \"2024-07-30\",\n      }\n                  ",{"title":773,"description":774,"authors":779,"heroImage":775,"date":781,"body":782,"category":14,"tags":783,"updatedDate":784},[780],"Sam Morris","2024-07-30","Les monorepos permettent d’héberger le code de plusieurs applications au sein d'un seul dépôt. Dans GitLab, cela consiste à organiser le code source de chaque application dans des répertoires distincts au sein d'un même projet. Bien que cette approche facilite le [contrôle de version](https://about.gitlab.com/fr-fr/topics/version-control/ \"Qu'est-ce que le contrôle de version ? \") pour l'ensemble du code, tirer parti des capacités avancées des [pipelines CI/CD](https://about.gitlab.com/fr-fr/topics/ci-cd/cicd-pipeline/ \"Qu'est-ce qu'un pipeline CI/CD ? \") de GitLab pouvait s'avérer complexe... jusqu'à l'arrivée d'une nouvelle fonctionnalité dans GitLab 16.4 !\n\n## Le cas idéal : des pipelines CI/CD indépendants pour un monorepo\n\nLorsque plusieurs applications coexistent dans un même dépôt, il est logique de vouloir disposer de pipelines CI/CD distincts pour chacune d'elles. Par exemple, si l'un de vos projets regroupe une application .NET et une application Spring, chacune d'elle nécessitera des jobs de compilation et de test différents. L'idéal serait donc de pouvoir découpler ces pipelines pour qu'ils s'exécutent uniquement lorsque des modifications sont apportées au code source de l'application concernée.\n\nTechniquement, cela revient à configurer un fichier de pipeline `.gitlab-ci.yml` au niveau du projet, qui inclut des fichiers YAML spécifiques basés sur les modifications détectées dans certains répertoires. Le fichier de pipeline `.gitlab-ci.yml` agit comme un plan de contrôle qui déclenche le pipeline approprié en fonction des modifications apportées au code.\n\n## Ancienne approche : le contournement\n\nAvant l'introduction de nouvelles fonctionnalités dans GitLab 16.4, il n'était pas possible d'inclure directement un fichier YAML en fonction des modifications apportées à un répertoire ou un fichier spécifique. Une solution de contournement était toutefois disponible. \n\nPrenons un exemple concret : un monorepo avec deux répertoires, `java` et `python`, contenant respectivement le code source d'une application Java et d'une application Python. Chaque répertoire disposait d'un fichier YAML propre à l'application pour gérer sa compilation. Le fichier de pipeline principal du projet incluait simplement les deux fichiers YAML des applications, mais une logique de gestion des modifications devait être directement intégrée dans ces fichiers.\n\n`.gitlab-ci.yml` :\n\n```\nstages:\n  - build\n  - test\n  - deploy\n\ntop-level-job:\n  stage: build\n  script:\n    - echo \"Hello world...\"\n\ninclude:\n  - local: '/java/j.gitlab-ci.yml'\n  - local: '/python/py.gitlab-ci.yml'\n\n```\n\nPour chaque application, il était nécessaire de créer un job masqué (par exemple, .java-common ou .python-common), qui ne s'exécutait qu'en présence de modifications apportées au répertoire correspondant. Les [jobs masqués](https://docs.gitlab.com/ee/ci/jobs/#hide-jobs) ne s'exécutaient pas par défaut. Ils servaient à centraliser la logique de déclenchement et à la réutiliser dans d'autres jobs. Cependant, cela impliquait d'étendre le job masqué dans chaque pipeline afin de respecter les règles de détection des modifications, qui déclenchaient alors le job d'exécution du pipeline. \n\n'j.gitlab-ci.yml':\n\n'''\nstages:\n  - build\n  - test\n  - deploy\n\n.java-common:\n  rules:\n    - changes:\n      - ../java/*'\n\njava-build-job:\n  extends: .java-common\n  stage: build\n  script:\n    - echo \"Building Java\"\n\njava-test-job:\n  extends: .java-common\n  stage: test\n  script:\n    - echo \"Testing Java\"\n\n'''\n\n'py.gitlab-ci.yml':\n\n'''\nstages:\n  - build\n  - test\n  - deploy\n\n.python-common:\n  rules:\n    - changes:\n      - \"../python/*\"\n\npython-build-job:\n  extends: .python-common\n  stage: build\n  script:\n    - echo \"Building Python\"\n\npython-test-job:\n  extends: .python-common\n  stage: test\n  script:\n    - echo \"Testing Python\"\n\n'''\n\nCette méthode fonctionnait, mais présentait des inconvénients majeurs. En effet, chaque pipeline devait étendre le job masqué pour chaque autre job dans le fichier YAML afin de respecter les règles de déclenchement. Elle avait pour conséquence la création de code redondant et l'augmentation du risque d'erreur humaine. De plus, les jobs étendus n'acceptaient pas de clés en double. Vous ne pouviez donc pas définir votre propre logique de règles (`rules`), car cela entraînait des conflits de clés et leurs [valeurs n'étaient pas fusionnées](https://docs.gitlab.com/ee/ci/yaml/index.html#extends). \n\nMalgré tout, avec cette méthode, le pipeline est opérationnel, incluant les jobs j.gitlab-ci.yml dès que le répertoire `java/` est mis à jour, et les jobs py.gitlab-ci.yml dès que le répertoire `python/` est mis à jour. \n\n## Nouvelle approche : l'inclusion conditionnelle des fichiers de pipeline\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/6phvk8jioAo?si=y6ztZODvUtM-cHmZ\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line ->\n\nAvec le lancement de GitLab 16.4, nous avons introduit une nouvelle fonctionnalité : la possibilité d'utiliser le terme [`include` avec `rules:changes` dans les pipelines CI/CD](https://docs.gitlab.com/ee/ci/yaml/includes.html#include-with-ruleschanges). Auparavant, vous pouviez utiliser l'option `include` avec `rules:if`, mais pas avec `rules:changes`. Cette nouvelle version est donc une amélioration majeure. Désormais, vous pouvez simplement utiliser le terme `include` et définir les règles du monorepo dans la configuration du pipeline de votre projet. \n\nNouveau fichier `.gitlab-ci.yml` :\n\n```\nstages:\n  - build\n  - test\n\ntop-level-job:\n  stage: build\n  script:\n    - echo \"Hello world...\"\n\ninclude:\n  - local: '/java/j.gitlab-ci.yml'\n    rules:\n      - changes:\n        - 'java/*'\n  - local: '/python/py.gitlab-ci.yml'\n    rules:\n      - changes:\n        - 'python/*'\n\n```\n\nAinsi, le fichier YAML de chaque application se concentre exclusivement sur les jobs nécessaires à cette application, comme la compilation et le test du code, sans avoir à étendre à plusieurs reprises un job masqué. Cette approche permet une plus grande flexibilité dans les définitions de job et les ingénieurs n'ont plus besoin de réécrire le code des configurations.\n\nNouveau fichier `j.gitlab-ci.yml` (Java) :\n\n```\nstages:\n  - build\n  - test\n  - deploy\n\njava-build-job:\n  stage: build\n  script:\n    - echo \"Building Java\"\n\njava-test-job:\n  stage: test\n  script:\n    - echo \"Testing Java\"\n\n```\n\nNouveau fichier `py.gitlab-ci.yml` (Python) :\n```\nstages:\n  - build\n  - test\n  - deploy\n\npython-build-job:\n  stage: build\n  script:\n    - echo \"Building Python\"\n\npython-test-job:\n  stage: test\n  script:\n    - echo \"Testing Python\"\n\n```\n\nCette méthode permet d'inclure les jobs Java et Python uniquement lorsque leurs répertoires respectifs sont modifiés. Cependant, il convient de noter que [les jobs peuvent s'exécuter de manière inattendue lors de l'utilisation de `changes`](https://docs.gitlab.com/ee/ci/jobs/job_troubleshooting.html#jobs-or-pipelines-run-unexpectedly-when-using-changes). La règle de déclenchement des modifications est toujours évaluée comme vraie lors du push d'une nouvelle branche ou d'un nouveau tag dans GitLab. Ainsi, tous les jobs inclus dans le pipeline s'exécuteront lors du premier push d'une branche, même si des règles `rules:changes` spécifiques sont définies. Vous pouvez résoudre ce problème en créant d'abord votre branche de fonctionnalité, puis en ouvrant une merge request pour commencer votre développement, car le premier push vers la branche lors de sa création forcera l'exécution de tous les jobs.\n\nEn fin de compte, les monorepos constituent une stratégie adaptée à GitLab et à l'approche CI/CD. La fonctionnalité `include` avec `rules:changes` est une bonne pratique que nous recommandons lors de l'utilisation de GitLab CI avec des monorepos. Pour utiliser les monorepos, commencez par essayer Gitlab Ultimate gratuitement dès aujourd'hui.\n",[111,736],"2025-05-27",{"slug":786,"featured":6,"template":686},"building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way","content:fr-fr:blog:building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way.yml","Building A Gitlab Ci Cd Pipeline For A Monorepo The Easy Way","fr-fr/blog/building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way.yml","fr-fr/blog/building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way",{"_path":792,"_dir":249,"_draft":6,"_partial":6,"_locale":7,"seo":793,"content":799,"config":807,"_id":809,"_type":16,"title":810,"_source":18,"_file":811,"_stem":812,"_extension":21},"/fr-fr/blog/how-to-deploy-react-to-amazon-s3",{"title":794,"description":795,"ogTitle":794,"ogDescription":795,"noIndex":6,"ogImage":796,"ogUrl":797,"ogSiteName":700,"ogType":701,"canonicalUrls":797,"schema":798},"Comment déployer une application React sur Amazon S3 avec GitLab CI/CD","Vous souhaitez déployer une application React sur Amazon S3 avec GitLab CI/CD ? Suivez notre guide étape par étape.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663291/Blog/Hero%20Images/cover1.jpg","https://about.gitlab.com/blog/how-to-deploy-react-to-amazon-s3","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Comment déployer une application React sur Amazon S3 avec GitLab CI/CD\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Jeremy Wagner\"}],\n        \"datePublished\": \"2023-03-01\",\n      }",{"title":794,"description":795,"authors":800,"heroImage":796,"date":802,"body":803,"category":14,"tags":804,"updatedDate":806},[801],"Jeremy Wagner","2023-03-01","Amazon S3 dispose d'une fonctionnalité d'hébergement qui vous permet d'héberger un site Web statique directement à partir d'un bucket S3, également appelé compartiment. Lorsque vous hébergez votre site Web sur Amazon S3, son contenu est stocké dans un bucket S3 et servi directement à vos utilisateurs, sans besoin de ressources supplémentaires. \n\nCombinez cela avec Amazon CloudFront et vous obtiendrez une solution rentable et évolutive pour l'hébergement de vos sites Web statiques. Une fonctionnalité particulièrement utile pour les applications à page unique.\n\nDans cet article, nous vous guidons dans la configuration de votre bucket Amazon S3, la configuration d'OpenID Connect ([OIDC](https://openid.net/developers/how-connect-works/ \"OpenID Connect\")) dans AWS et le déploiement de votre application sur Amazon S3 à l'aide d'un pipeline GitLab [CI/CD](https://about.gitlab.com/fr-fr/topics/ci-cd/ \"Qu'est-ce que le CI/CD ?\").\n\nÀ la fin de cet article, vous disposerez d'un [pipeline CI/CD](https://about.gitlab.com/fr-fr/topics/ci-cd/cicd-pipeline/ \"Qu'est-ce qu'un pipeline CI/CD ?\") construit dans GitLab qui se déploie automatiquement dans votre bucket Amazon S3. \n\n## Prérequis\n\nPour ce guide, vous aurez besoin des éléments suivants :\n\n- [Node.js](https://nodejs.org/fr) >= 14.0.0 et npm >= 5.6 installés sur votre système\n- [Git](https://git-scm.com/) installé sur votre système\n- Un [compte GitLab](https://gitlab.com/-/trials/new)\n- Un [compte AWS](https://aws.amazon.com/fr/free/)\n\nDans un [précédent tutoriel](https://about.gitlab.com/blog/how-to-automate-testing-for-a-react-application-with-gitlab/) nous vous avons expliqué comment : \n- créer une nouvelle application React,\n- exécuter des tests unitaires dans le cadre du processus CI dans GitLab,\n- générer les résultats des tests ainsi que la couverture de code dans le pipeline.\n\nCet article constitue la [suite de ce projet](https://gitlab.com/guided-explorations/engineering-tutorials/react-unit-testing). Libre à vous de le parcourir et de le dupliquer (fork). \n\n## Configuration de votre bucket S3 \n\nPour commencer, vous devez configurer votre bucket Amazon S3. \n\n### Créez votre compartiment\n\nAprès vous être connecté à votre compte AWS, recherchez « S3 » à l'aide de la barre de recherche et sélectionnez le service S3. Cela ouvrira la page d'accueil du service.\n\nVous devriez immédiatement voir l'option permettant de créer un bucket (compartiment). Ce compartiment est l'endroit où vous allez stocker votre application React une fois créée. Cliquez sur le bouton « Créer un compartiment » pour continuer.\n\n![Création d'un bucket S3](https://about.gitlab.com/images/blogimages/2023-02-10-how-to-deploy-react-to-amazon-s3/create_bucket.png){: .shadow}\n\nDonnez un nom à votre compartiment, sélectionnez votre région, laissez le reste des paramètres par défaut (nous y reviendrons plus tard) et continuez en cliquant sur le bouton « Créer un compartiment ». \n\nLorsque vous nommez votre compartiment, il est important de se rappeler que le nom doit être unique et suivre les règles de nommage des compartiments. Nous avons nommé le nôtre `jw-gl-react`.\n\nUne fois votre compartiment créé, vous devriez être redirigé vers une liste de vos compartiments, comme montré ci-dessous. \n\n![Liste bucket S3 AWS](https://about.gitlab.com/images/blogimages/2023-02-10-how-to-deploy-react-to-amazon-s3/bucket_list.png){: .shadow}\n\n### Configurez l'hébergement de site web statique \n\nL'étape suivante consiste à configurer l'hébergement de site web statique. Ouvrez votre compartiment en cliquant sur son nom. Sélectionnez l'onglet « Propriétés »  et faites défiler vers le bas pour trouver l'option d'hébergement de site web statique.\n\n![Configuration de l'hébergement de site web statique](https://about.gitlab.com/images/blogimages/2023-02-10-how-to-deploy-react-to-amazon-s3/static_hosting_1.png){: .shadow}\n\nCliquez sur « Modifier », puis activez l'hébergement de site web statique. Pour les documents d’index et d’erreur, saisissez `index.html`, puis cliquez sur « Enregistrer les modifications ».\n\n![Activation de l'hébergement de site web statique sur Amazon S3](https://about.gitlab.com/images/blogimages/2023-02-10-how-to-deploy-react-to-amazon-s3/static_hosting_2.png){: .shadow}\n\n### Configurez les autorisations de votre application React\n\nMaintenant que vous avez activé l'hébergement de site web statique, vous devez mettre à jour vos autorisations afin que votre audience puisse accéder à votre site web. Revenez à votre compartiment et sélectionnez l'onglet « Autorisations ».\n\nSous « Bloquer l'accès public » (paramètres du compartiment), cliquez sur « Modifier », décochez « Bloquer tous les accès publics » et continuez en cliquant sur « Enregistrer les modifications ».\n\n![Bloquer l'accès public](https://about.gitlab.com/images/blogimages/2023-02-10-how-to-deploy-react-to-amazon-s3/block_access_1.png){: .shadow}\n\nVotre page devrait maintenant ressembler à ceci : \n\n![Configurer permission bucket S3 AWS](https://about.gitlab.com/images/blogimages/2023-02-10-how-to-deploy-react-to-amazon-s3/block_access_2.png){: .shadow}\n\nMaintenant, vous devez modifier la stratégie de compartiment. Pour cela, cliquez sur le bouton « Modifier » dans la section « Stratégie de compartiment » et collez le code suivant :\n\n```javascript\n{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"PublicReadGetObject\",\n            \"Effect\": \"Allow\",\n            \"Principal\": \"*\",\n            \"Action\": \"s3:GetObject\",\n            \"Resource\": \"arn:aws:s3:::jw-gl-react/*\"\n        }\n    ]\n}\n```\n\nÀ la ligne « Ressource », remplacez `jw-gl-react`  par le nom de votre compartiment et enregistrez les modifications.\n\nVotre compartiment devrait ressembler à ceci : \n\n![Bucket S3 accès public](https://about.gitlab.com/images/blogimages/2023-02-10-how-to-deploy-react-to-amazon-s3/block_access_3.png){: .shadow}\n\n## Chargement de votre application React\n\nMaintenant, créons votre application React et publions-la manuellement dans votre bucket S3.\n\nPour créer l'application, assurez-vous que votre projet soit cloné sur votre machine locale et exécutez la commande suivante dans votre terminal à l'intérieur du répertoire de votre dépôt :\n\n```\nnpm run build\n```\nCela créera un dossier `build` à l'intérieur du répertoire de votre dépôt. \n\nDans votre compartiment, cliquez sur le bouton « Charger »\n\n![Chargement de l'application React](https://about.gitlab.com/images/blogimages/2023-02-10-how-to-deploy-react-to-amazon-s3/upload_1.png){: .shadow}\n\nFaites glisser le contenu de votre dossier nouvellement créé (et non le dossier lui-même) dans la zone de chargement. Cela chargera le contenu de votre application React dans votre compartiment. Assurez-vous de cliquer sur « Charger » en bas de la page pour démarrer le chargement.\n\nRevenez maintenant à l'onglet « Propriétés » de votre compartiment et faites défiler vers le bas pour trouver l'URL de votre site web statique.\n\n![URL du site web statique](https://about.gitlab.com/images/blogimages/2023-02-10-how-to-deploy-react-to-amazon-s3/upload_2.png){: .shadow}\n\nCliquez sur le lien et vous devriez voir votre application React nouvellement créée s'ouvrir dans votre navigateur.\n\n![Application React déployée](https://about.gitlab.com/images/blogimages/2023-02-10-how-to-deploy-react-to-amazon-s3/manual_deploy.png){: .shadow}\n\n## Configuration d’OpenID Connect dans AWS\n\nPour déployer sur votre bucket S3 depuis GitLab, nous allons utiliser un job GitLab CI/CD pour  recevoir des informations d'identification temporaires d'AWS sans avoir besoin de stocker des secrets. Pour ce faire, nous allons configurer OpenID Connect pour la fédération d'identité entre GitLab et AWS. Nous suivrons la [documentation de GitLab associée](https://docs.gitlab.com/ee/ci/cloud_services/aws/).\n\n### Ajoutez un fournisseur d'identité \n\nLa première étape consiste à ajouter GitLab en tant que fournisseur d’identité OpenID Connect (OIDC) dans IAM. AWS fournit des [instructions](https://docs.aws.amazon.com/fr_fr/IAM/latest/UserGuide/id_roles_providers_create_oidc.html), mais nous allons les parcourir étape par étape dans ce guide.\n\nOuvrez tout d'abord la console IAM dans AWS.\n\n![Console IAM dans AWS](https://about.gitlab.com/images/blogimages/2023-02-10-how-to-deploy-react-to-amazon-s3/iam_1.png){: .shadow} \n\nDans le volet de navigation de gauche, sous « Gestion des accès », choisissez « Fournisseurs d'identité », puis « Ajouter un fournisseur ». Pour le type de fournisseur, sélectionnez « OpenID Connect ».\n\nPour l'URL du fournisseur, saisissez l'adresse de votre instance GitLab, telle que `https://gitlab.com` ou `https://gitlab.example.com`.\n\nPour « Audience », saisissez quelque chose de générique mais spécifique à votre application React. Dans notre cas, nous allons utiliser `react_s3_gl`. Veillez à choisir quelque chose qui ne soit pas facile à deviner et prenez note de cette valeur, car vous l'utiliserez pour définir l'`ID_TOKEN` dans votre fichier `.gitLab-ci.yml`.\n\nAprès avoir saisi l'URL du fournisseur, cliquez sur « Obtenir une empreinte numérique »  pour vérifier le certificat du serveur de votre fournisseur d'identité. Ensuite, continuez et cliquez sur « Ajouter un fournisseur » pour terminer.\n\n### Créez une politique d’autorisations\n\nAprès avoir créé le fournisseur d'identité, vous devez créer une politique d’autorisations. \n\nDepuis le tableau de bord IAM, sous « Gestion des accès », sélectionnez « Politiques » puis « Créer une politique ». Sélectionnez l'onglet JSON et collez le code suivant en remplaçant `jw-gl-react` par le nom de votre compartiment à la ligne « Ressource ».\n\n```javascript\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\"s3:ListBucket\"],\n      \"Resource\": [\"arn:aws:s3:::jw-gl-react\"]\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"s3:PutObject\",\n        \"s3:GetObject\",\n        \"s3:DeleteObject\"\n      ],\n      \"Resource\": [\"arn:aws:s3:::jw-gl-react/*\"]\n    }\n  ]\n}\n```\n\nSélectionnez le bouton « Suivant : Balises » , ajoutez les balises souhaitées, puis sélectionnez le bouton « Suivant : Confirmer ». Entrez un nom pour votre politique avant de terminer sa création.\n\n### Configurez le rôle\n\nIl est maintenant temps d'ajouter le rôle. Depuis le tableau de bord IAM, sous « Gestion des accès  », sélectionnez « Rôles », puis cliquez sur « Créer un rôle » et choisissez « Identité Web ».\n\nDans la section « Identité Web », sélectionnez le fournisseur d'identité que vous avez créé précédemment. Pour l'audience, sélectionnez également l'audience que vous avez créée précédemment. Cliquez sur le bouton « Suivant » pour continuer.\n\nSi vous souhaitez limiter l'autorisation à un groupe, un projet, une branche ou une balise spécifique, vous pouvez créer une « Politique d’approbation personnalisée » (Custom Trust Policy) au lieu d'une « Identité Web ».\n\nPour une liste complète des types de filtres qu'il est possible d'appliquer, [consultez notre documentation](https://docs.gitlab.com/ee/ci/cloud_services/index.html#configure-a-conditional-role-with-oidc-claims). \n\n![Configuration du rôle dans l'IAM](https://about.gitlab.com/images/blogimages/2023-02-10-how-to-deploy-react-to-amazon-s3/iam_2.png){: .shadow}\n\nAu cours de l'étape « Ajout des autorisations », sélectionnez la politique que vous avez créée, puis cliquez sur « Suivant » pour continuer. Donnez un nom à votre rôle et cliquez sur « Créer un rôle ».\n\nOuvrez le rôle que vous venez de créer. Dans la section « Récapitulatif », recherchez le nom de ressource Amazon (ARN) et enregistrez-le dans un endroit sécurisé. Vous l'utiliserez dans votre pipeline.\n\n![Déployer le rôle dans l'IAM](https://about.gitlab.com/images/blogimages/2023-02-10-how-to-deploy-react-to-amazon-s3/iam_3.png){: .shadow}\n\n## Déploiement sur votre compartiment Amazon S3 à l'aide d'un pipeline GitLab CI/CD\n\nDans votre projet, créez deux [variables CI/CD](https://docs.gitlab.com/ci/variables/#define-a-cicd-variable-in-the-ui) :\n\n- La première variable doit être nommée `ROLE_ARN`. Pour la valeur, collez l'ARN du rôle que vous venez de créer.\n- La deuxième variable doit être nommée `S3_BUCKET`. Pour la valeur, collez le nom du compartiment que vous avez créé plus tôt.\n\nPour des raisons de sécurité, dans cet article nous avons choisi de masquer nos variables.\n\n### Récupérez vos identifiants temporaires\n\nDans votre fichier `.gitlab-ci.yml`, collez le code suivant :\n\n```\n.assume_role: &assume_role\n    - >\n      STS=($(aws sts assume-role-with-web-identity\n      --role-arn ${ROLE_ARN}\n      --role-session-name \"GitLabRunner-${CI_PROJECT_ID}-${CI_PIPELINE_ID}\"\n      --web-identity-token $ID_TOKEN\n      --duration-seconds 3600\n      --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]'\n      --output text))\n    - export AWS_ACCESS_KEY_ID=\"${STS[0]}\"\n    - export AWS_SECRET_ACCESS_KEY=\"${STS[1]}\"\n    - export AWS_SESSION_TOKEN=\"${STS[2]}\"\n```\n\nCela va utiliser le service de jeton de sécurité AWS (AWS Security Token Service) pour générer des identifiants temporaires (3 600 secondes) en utilisant le rôle OpenID Connect que vous avez créé précédemment.\n\n### Créez le job de déploiement pour votre application React\n\nMaintenant, ajoutons un job de compilation et de déploiement pour créer votre application et la déployer sur votre bucket S3.\n\nTout d'abord, mettez à jour les étapes dans votre fichier `.gitlab-ci.yml` pour inclure une étape `build` et `deploy`, comme indiqué ci-dessous :\n\n```\nstages:\n  - build\n  - test\n  - deploy\n```\n\nEnsuite, ajoutons un job pour créer votre application. Collez le code suivant dans votre fichier `.gitLab-ci.yml` :\n\n```\nbuild artifact:\n  stage: build\n  image: node:latest\n  before_script:\n    - npm install\n  script:\n    - npm run build\n  artifacts:\n    paths:\n      - build/\n    when: always\n  rules:\n    - if: '$CI_COMMIT_REF_NAME == \"main\"'\n      when: always\n```\n\nCela va exécuter `npm run build` si le changement se produit sur la branche `main` et télécharger le répertoire de compilation (build directory) en tant qu'artefact à utiliser lors de l'étape suivante.\n\nEnsuite, ajoutons un job qui sera réellement déployé sur votre bucket S3. Collez le code suivant dans votre fichier `.gitLab-ci.yml` :\n\n```\ndeploy s3:\n  stage: deploy\n  image:\n    name: amazon/aws-cli:latest\n    entrypoint: \n      - '/usr/bin/env'\n  id_tokens:\n      ID_TOKEN:\n        aud: react_s3_gl\n  script:\n    - *assume_role\n    - aws s3 sync build/ s3://$S3_BUCKET\n  rules:\n    - if: '$CI_COMMIT_REF_NAME == \"main\"'\n      when: always\n```\n\nCela utilise les [ancres YAML](https://docs.gitlab.com/ee/ci/yaml/yaml_optimization.html#yaml-anchors-for-scripts) pour exécuter le script `assume_role`, puis utilise `aws cli` pour télécharger votre artefact de compilation dans le compartiment que vous avez défini en tant que variable. Ce job ne s'exécute que si le changement se produit sur la branche `main`.\n\nAssurez-vous que la valeur `aud` correspond à celle que vous avez saisie pour votre audience au moment de la configuration du fournisseur d'identité. Dans notre cas, nous avons saisi `react-s3_gl`.\n\nVotre fichier `.gitLab-ci.yml` complet devrait ressembler à ceci :\n\n```\nstages:\n  - build\n  - test\n  - deploy\n\n.assume_role: &assume_role\n    - >\n      STS=($(aws sts assume-role-with-web-identity\n      --role-arn ${ROLE_ARN}\n      --role-session-name \"GitLabRunner-${CI_PROJECT_ID}-${CI_PIPELINE_ID}\"\n      --web-identity-token $ID_TOKEN\n      --duration-seconds 3600\n      --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]'\n      --output text))\n    - export AWS_ACCESS_KEY_ID=\"${STS[0]}\"\n    - export AWS_SECRET_ACCESS_KEY=\"${STS[1]}\"\n    - export AWS_SESSION_TOKEN=\"${STS[2]}\"\n\nunit test:\n  image: node:latest\n  stage: test\n  before_script:\n    - npm install\n  script:\n    - npm run test:ci\n  coverage: /All files[^|]*\\|[^|]*\\s+([\\d\\.]+)/\n  artifacts:\n    paths:\n      - coverage/\n    when: always\n    reports:\n      junit:\n        - junit.xml\n\nbuild artifact:\n  stage: build\n  image: node:latest\n  before_script:\n    - npm install\n  script:\n    - npm run build\n  artifacts:\n    paths:\n      - build/\n    when: always\n  rules:\n    - if: '$CI_COMMIT_REF_NAME == \"main\"'\n      when: always\n\ndeploy s3:\n  stage: deploy\n  image:\n    name: amazon/aws-cli:latest\n    entrypoint: \n      - '/usr/bin/env'\n  id_tokens:\n      ID_TOKEN:\n        aud: react_s3_gl\n  script:\n    - *assume_role\n    - aws s3 sync build/ s3://$S3_BUCKET\n  rules:\n    - if: '$CI_COMMIT_REF_NAME == \"main\"'\n      when: always\n```\n\n### Testez votre pipeline\n\nPour tester votre pipeline, dans `App.js`, modifiez cette ligne `Edit \u003Ccode>src/App.js\u003C/code> and save to reload.` par ceci :  `This was deployed from GitLab`. Maintenant, validez vos modifications dans la branche `main`. Le pipeline devrait se lancer et une fois terminé avec succès, vous devriez voir votre application mise à jour avec l'URL de votre site web statique.\n\n![Application React mise à jour](https://about.gitlab.com/images/blogimages/2023-02-10-how-to-deploy-react-to-amazon-s3/auto_deploy.png){: .shadow}\n\nVous disposez désormais d'un pipeline CI/CD construit dans GitLab qui reçoit des informations d'identification temporaires d'AWS à l'aide d'OpenID Connect et qui se déploie automatiquement dans votre compartiment Amazon S3. Pour aller plus loin, vous pouvez [sécuriser votre application](https://docs.gitlab.com/ee/user/application_security/secure_your_application.html) avec les outils de sécurité intégrés de GitLab.\n\nDécouvrez [tout le code](https://gitlab.com/guided-explorations/engineering-tutorials/react-s3) de ce projet.",[805,111],"DevOps","2025-03-27",{"slug":808,"featured":6,"template":686},"how-to-deploy-react-to-amazon-s3","content:fr-fr:blog:how-to-deploy-react-to-amazon-s3.yml","How To Deploy React To Amazon S3","fr-fr/blog/how-to-deploy-react-to-amazon-s3.yml","fr-fr/blog/how-to-deploy-react-to-amazon-s3",{"_path":814,"_dir":249,"_draft":6,"_partial":6,"_locale":7,"seo":815,"content":821,"config":828,"_id":830,"_type":16,"title":831,"_source":18,"_file":832,"_stem":833,"_extension":21},"/fr-fr/blog/efficient-devsecops-workflows-hands-on-python-gitlab-api-automation",{"title":816,"description":817,"ogTitle":816,"ogDescription":817,"noIndex":6,"ogImage":818,"ogUrl":819,"ogSiteName":700,"ogType":701,"canonicalUrls":819,"schema":820},"Utiliser l'API python-gitlab pour améliorer vos workflows DevSecOps","Vous souhaitez améliorer vos workflows DevSecOps ? Découvrez dans ce tutoriel des exemples et bonnes pratiques d’utilisation de l’API python-gitlab.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659883/Blog/Hero%20Images/post-cover-image.jpg","https://about.gitlab.com/blog/efficient-devsecops-workflows-hands-on-python-gitlab-api-automation","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Utiliser l'API python-gitlab pour améliorer vos workflows DevSecOps\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Michael Friedrich\"}],\n        \"datePublished\": \"2023-02-01\",\n      }",{"title":816,"description":817,"authors":822,"heroImage":818,"date":824,"body":825,"category":14,"tags":826},[823],"Michael Friedrich","2023-02-01","Un jour, un ami m’a dit : « Le travail manuel est un bug ». Depuis, face à des tâches répétitives, j’ai pris l’habitude de les automatiser autant que possible. \n\nPar exemple, en interrogeant une [API REST](https://about.gitlab.com/fr-fr/blog/what-is-rest-api/ \"API REST\") pour faire un inventaire des paramètres, ou en effectuant des appels d’API pour créer de nouveaux commentaires dans les tickets ou les merge requests de GitLab. L'interaction avec l'API REST de GitLab peut se faire de différentes manières, en utilisant des requêtes HTTP avec curl (ou [hurl](https://about.gitlab.com/blog/how-to-continously-test-web-apps-apis-with-hurl-and-gitlab-ci-cd/ \"hurl\")) en ligne de commande, ou en écrivant un script dans un langage de programmation. \n\nDans ce dernier cas, il faut effectuer des tâches fastidieuses avec le code brut des requêtes HTTP et l'analyse des réponses JSON. Grâce à la communauté GitLab, de nombreux langages sont pris en charge par les bibliothèques d'abstraction d'API. Elles prennent en charge tous les attributs de l’API, ajoutent des fonctions d'aide pour obtenir, créer et supprimer des objets, et facilitent ainsi la tâche des équipes de développement. La [bibliothèque python-gitlab](https://python-gitlab.readthedocs.io/en/stable/ \"Bibliothèque python-gitlab\") est une bibliothèque écrite en Python, riche en fonctionnalités et facile à utiliser.\n\nDans cet article, vous apprendrez les bases de l’utilisation de la bibliothèque python-gitlab en vous familiarisant avec les objets de l’API, les attributs, la pagination et les ensembles de résultats. Vous découvrirez également des cas d'utilisation concrets tels que la collecte de données, la génération de synthèses et l’écriture de données dans l'API pour créer des commentaires et des validations. \n\nIl y a encore beaucoup à apprendre, avec de nombreux cas d'utilisation inspirés des questions posées par la communauté sur le forum, Hacker News, des tickets, et bien plus encore.\n\n## Premiers pas\n\nLa [documentation python-gitlab](https://python-gitlab.readthedocs.io/en/stable/api-usage.html \"Documentation python-gitlab\") est une excellente ressource pour débuter. Elle offre un aperçu des types d'objets et de leurs méthodes, ainsi que des exemples de workflows combinés. Cette ressource est idéale pour faire vos premiers pas, en plus de la [documentation sur les ressources de l'API GitLab](https://docs.gitlab.com/ee/api/api_resources.html \"Documentation sur les ressources de l'API GitLab\") qui fournit les attributs d'objet associés.\n\nLes exemples de code présentés dans cet article nécessitent Python 3.8+ et la bibliothèque `python-gitlab`. Des exigences supplémentaires sont spécifiées dans le fichier `requirements.txt`. Un exemple nécessite `pyyaml` pour l'analyse de la configuration YAML. Pour suivre et mettre en pratique le code des cas d'utilisation, il est recommandé de cloner le projet, d'installer les prérequis et d'exécuter les scripts. \n\nExemple avec Homebrew sur macOS :\n\n```shell\ngit clone https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python.git\n\ncd gitlab-api-python\n\nbrew install python\n\npip3 install -r requirements.txt\n\npython3 \u003Cscriptname>.py\n```\n\nLes scripts n'utilisent pas de bibliothèque partagée commune fournissant des fonctions génériques pour la lecture des paramètres ou d’autres fonctionnalités d'aide supplémentaires. L’objectif est de montrer des exemples faciles à suivre, qui peuvent être utilisés de manière autonome pour des tests, et qui nécessitent uniquement l'installation de la bibliothèque python-gitlab.\n\nNous recommandons d'améliorer le code pour une utilisation en production. Cela vous aidera à créer un projet d’API tooling maintenu, incluant par exemple des images de conteneurs et des modèles CI/CD que les équipes de développement peuvent utiliser au sein d'une plateforme [DevSecOps](https://about.gitlab.com/fr-fr/topics/devsecops/ \"Qu'est-ce que DevSecOps ?\").\n\n## Configuration\n\nSans configuration, python-gitlab exécutera des requêtes non authentifiées sur le serveur par défaut : `https://gitlab.com`. Les paramètres de configuration les plus courants concernent l'instance GitLab à laquelle se connecter, et la méthode d'authentification en spécifiant les jetons d'accès. Python-gitlab prend en charge différents types de configuration : un fichier de configuration ou des variables d'environnement.\n\nLe [fichier de configuration](https://python-gitlab.readthedocs.io/en/stable/cli-usage.html#cli-configuration \"Fichier de configuration CLI\") est disponible pour les liaisons de bibliothèque d’API et pour l'interface de ligne de commande (que nous n’aborderons pas dans cet article). Le fichier de configuration prend en charge les [credential helpers](https://python-gitlab.readthedocs.io/en/stable/cli-usage.html#credential-helpers \"Credential helpers\") pour accéder directement aux jetons.\n\nLes variables d'environnement, en tant que méthode de configuration alternative, vous offrent un moyen simple d'exécuter le script dans un terminal, de l'intégrer dans des images de conteneurs et de le préparer à être exécuté dans des [pipelines CI/CD](https://about.gitlab.com/fr-fr/topics/ci-cd/cicd-pipeline/ \"Pipeline CI/CD\").\n\nVous devez lancer la configuration dans le contexte du script Python. Importez la bibliothèque `os` pour récupérer les variables d'environnement à l'aide de la méthode `os.environ.get()`. Le premier paramètre spécifie la clé, le second paramètre définit la valeur par défaut lorsque la variable n'est pas disponible dans l'environnement.\n\n```python\nimport os\n\ngl_server = os.environ.get('GL_SERVER', 'https://gitlab.com')\n\nprint(gl_server)\n```\n\nLe paramétrage dans le terminal peut se faire directement pour la commande uniquement, ou être exporté dans l'environnement shell.\n\n```shell\n$ GL_SERVER=’https://gitlab.company.com’ python3 script.py\n\n$ export GL_SERVER=’https://gitlab.company.com’\n$ python3 script.py\n```\n\nNous recommandons d'ajouter des contrôles de sécurité pour s’assurer que toutes les variables sont définies avant de continuer l'exécution du programme. L'extrait de code suivant importe les bibliothèques requises, lit la variable d'environnement `GL_SERVER`, et attend de l'utilisateur qu'il définisse la variable `GL_TOKEN`. Si ce n'est pas le cas, le script affiche et génère des erreurs, puis appelle `sys.exit(1)`, pour indiquer un statut d’erreur. \n\n```python\nimport gitlab\nimport os\nimport sys\n\nGITLAB_SERVER = os.environ.get('GL_SERVER', 'https://gitlab.com')\nGITLAB_TOKEN = os.environ.get('GL_TOKEN')\n\nif not GITLAB_TOKEN:\n    print(\"Please set the GL_TOKEN env variable.\")\n    sys.exit(1)\n```\n\nExaminons maintenant un exemple plus détaillé, qui crée une connexion à l'API et effectue une requête de données.\n\n## Gestion des objets : l'objet GitLab\n\nToute interaction avec l'API nécessite une instanciation de l'objet GitLab. C'est le point d'entrée pour configurer le serveur GitLab auquel se connecter et s'authentifier à l'aide de jetons d'accès, et définir d’autres paramètres globaux pour la pagination, le chargement d’objets, et plus encore. \n\nL'exemple suivant exécute une requête non authentifiée sur GitLab.com. Il est possible d'accéder aux points de terminaison d’API publique, et d'obtenir par exemple un [modèle .gitignore pour Python](https://python-gitlab.readthedocs.io/en/stable/gl_objects/templates.html#gitignore-templates \"Modèle .gitignore pour Python\").\n\n[python_gitlab_object_unauthenticated.py](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python/-/blob/main/python_gitlab_object_unauthenticated.py)\n\n```python\nimport gitlab\n\ngl = gitlab.Gitlab()\n\n# Get .gitignore templates without authentication\ngitignore_templates = gl.gitignores.get('Python')\n\nprint(gitignore_templates.content)\n```\n\nDans les sections suivantes, nous vous partageons des informations détaillées sur : \n\n- La gestion et le chargement des objets,\n- La pagination des résultats,\n- Le travail avec les relations entre objets,\n- Le travail avec différents scopes de collection d'objets.\n\n### La gestion et le chargement des objets\n\nLa bibliothèque python-gitlab donne accès aux ressources GitLab en utilisant ce que l’on appelle des « [Gestionnaires](https://python-gitlab.readthedocs.io/en/stable/api-usage.html#managers) ». Chaque type de gestionnaire implémente des méthodes pour travailler avec les ensembles de données (list, get, etc.).\n\nLe script ci-dessous montre comment accéder aux sous-groupes, aux projets directs et à tous les projets, y compris les sous-groupes, aux tickets, aux epics et aux tâches. Une authentification est nécessaire pour accéder à tous les attributs. L'extrait de code utilise donc des variables pour obtenir le jeton d'authentification, et utilise également la variable `GROUP_ID` pour spécifier un groupe principal à partir duquel il faut commencer la recherche.\n\n```python\n#!/usr/bin/env python\n\nimport gitlab\nimport os\nimport sys\n\nGITLAB_SERVER = os.environ.get('GL_SERVER', 'https://gitlab.com')\n# https://gitlab.com/gitlab-de/use-cases/\nGROUP_ID = os.environ.get('GL_GROUP_ID', 16058698)\nGITLAB_TOKEN = os.environ.get('GL_TOKEN')\n\nif not GITLAB_TOKEN:\n    print(\"Please set the GL_TOKEN env variable.\")\n    sys.exit(1)\n\ngl = gitlab.Gitlab(GITLAB_SERVER, private_token=GITLAB_TOKEN)\n\n# Main\nmain_group = gl.groups.get(GROUP_ID)\n\nprint(\"Sub groups\")\nfor sg in main_group.subgroups.list():\n    print(\"Subgroup name: {sg}\".format(sg=sg.name))\n\nprint(\"Projects (direct)\")\nfor p in main_group.projects.list():\n    print(\"Project name: {p}\".format(p=p.name))\n\nprint(\"Projects (including subgroups)\")\nfor p in main_group.projects.list(include_subgroups=True, all=True):\n     print(\"Project name: {p}\".format(p=p.name))\n\nprint(\"Issues\")\nfor i in main_group.issues.list(state='opened'):\n    print(\"Issue title: {t}\".format(t=i.title))\n\nprint(\"Epics\")\nfor e in main_group.issues.list():\n    print(\"Epic title: {t}\".format(t=e.title))\n\nprint(\"Todos\")\nfor t in gl.todos.list(state='pending'):\n    print(\"Todo: {t} url: {u}\".format(t=t.body, u=t.target_url\n```\n\nVous pouvez exécuter le script `python_gitlab_object_manager_methods.py` en remplaçant la variable `GROUP_ID` sur GitLab.com SaaS pour analyser votre propre groupe. Vous devez spécifier la variable `GL_SERVER` pour les instances auto-gérées. `GL_TOKEN` doit fournir le jeton d'accès personnel.\n\n```shell\nexport GL_TOKEN=xxx\n\nexport GL_SERVER=”https://gitlab.company.com”\n\nexport GL_SERVER=”https://gitlab.com”\n\nexport GL_GROUP_ID=1234\n\npython3 python_gitlab_object_manager_methods.py\n```\n\nÀ partir de maintenant, les exemples n'affichent plus les en-têtes Python et l'analyse des variables d'environnement, afin de se concentrer sur l'algorithme et les fonctionnalités. Tous les scripts sont open source sous licence MIT, et sont disponibles dans [ce projet](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python).\n\n### La pagination des résultats\n\nPar défaut, l’API GitLab ne renvoie pas tous les ensembles de résultats et exige que les clients utilisent la [pagination](https://docs.gitlab.com/ee/api/rest/index.html#pagination \"Pagination GitLab\") pour parcourir toutes les pages de résultats. La bibliothèque python-gitlab permet aux utilisateurs de [définir les paramètres](https://python-gitlab.readthedocs.io/en/stable/api-usage.html#pagination) globalement dans l'objet GitLab, ou sur chaque appel `list()`. Cela permet d'éviter que tous les ensembles de résultats déclenchent des requêtes API, ce qui peut ralentir l'exécution du script. Utilisez `iterator=True`, et les appels d'API sont déclenchés à la demande lors de l'accès à l'objet.\n\nL'exemple suivant recherche le nom de groupe `everyonecancontribute` et utilise la pagination du jeu de clés pour afficher 100 résultats sur chaque page. L'itérateur est défini sur true dans `gl.groups.list(iterator=True)` pour récupérer de nouveaux ensembles de résultats à la demande. Si le nom du groupe recherché est trouvé, la boucle s'interrompt et affiche un résumé, incluant la mesure de la durée totale de la requête de recherche.\n\n```python\nSEARCH_GROUP_NAME=\"everyonecancontribute\"\n\n# Use keyset pagination\n# https://python-gitlab.readthedocs.io/en/stable/api-usage.html#pagination\ngl = gitlab.Gitlab(GITLAB_SERVER, private_token=GITLAB_TOKEN,\n    pagination=\"keyset\", order_by=\"id\", per_page=100)\n\n# Iterate over the list, and fire new API calls in case the result set does not match yet\ngroups = gl.groups.list(iterator=True)\n\nfound_page = 0\nstart = timer()\n\nfor group in groups:\n    if SEARCH_GROUP_NAME == group.name:\n        # print(group) # debug\n        found_page = groups.current_page\n        break\n\nend = timer()\n\nduration = f'{end-start:.2f}'\n\nif found_page > 0:\n    print(\"Pagination API example for Python with GitLab{desc} - found group {g} on page {p}, duration {d}s\".format(\n        desc=\", the DevSecOps platform\", g=SEARCH_GROUP_NAME, p=found_page, d=duration))\nelse:\n    print(\"Could not find group name '{g}', duration {d}\".format(g=SEARCH_GROUP_NAME, d=duration))\n```\nL'exécution de `python_gitlab_pagination.py` a permis de trouver le groupe [everyonecancontribute](https://gitlab.com/everyonecancontribute) à la page 5.\n\n```shell\n$ python3 python_gitlab_pagination.py\nPagination API example for Python with GitLab, the DevSecOps platform - found group everyonecancontribute on page 5, duration 8.51s\n```\n\n### Le travail avec les relations entre objets\n\nLorsque vous travaillez avec des relations entre objets, par exemple pour collecter tous les projets dans un groupe donné, vous devez envisager des étapes supplémentaires. Par défaut, les objets de projet renvoyés présentent des attributs limités. Les objets gérables nécessitent un appel supplémentaire `get()` pour obtenir l'objet de projet complet de l'API en arrière-plan. Ce workflow permet de réduire les temps d’attente et le trafic en limitant les attributs immédiatement renvoyés.\n\nL'exemple suivant illustre le problème en parcourant tous les projets d'un groupe et en essayant d'appeler la fonction `project.branches.list()`. Cela génère une exception dans le flux try/except. Le deuxième exemple obtient un objet de projet gérable et tente à nouveau d'appeler la fonction.\n\n```python\n# Main\ngroup = gl.groups.get(GROUP_ID)\n\n# Collect all projects in group and subgroups\nprojects = group.projects.list(include_subgroups=True, all=True)\n\nfor project in projects:\n    # Try running a method on a weak object\n    try:\n       print(\"🤔 Project: {pn} 💡 Branches: {b}\\n\".format(\n        pn=project.name,\n        b=\", \".join([x.name for x in project.branches.list()])))\n    except Exception as e:\n        print(\"Got exception: {e} \\n ===================================== \\n\".format(e=e))\n\n    # Retrieve a full manageable project object\n    # https://python-gitlab.readthedocs.io/en/stable/gl_objects/groups.html#examples\n    manageable_project = gl.projects.get(project.id)\n\n    # Print a method available on a manageable object\n    print(\"🤔 Project: {pn} 💡 Branches: {b}\\n\".format(\n        pn=manageable_project.name,\n        b=\", \".join([x.name for x in manageable_project.branches.list()])))\n```\n\nLe gestionnaire d'exceptions dans la bibliothèque python-gitlab affiche le message d'erreur et renvoie à la documentation. Pour le débogage, notez que les objets peuvent ne pas être disponibles pour la gestion lorsque vous ne pouvez pas accéder aux attributs de l'objet ou aux appels de fonction.\n\n```shell\n$ python3 python_gitlab_manageable_objects.py\n\n🤔 Project: GitLab API Playground 💡 Branches: cicd-demo-automated-comments, docs-mr-approval-settings, main\n\nGot exception: 'GroupProject' object has no attribute 'branches'\n\n\u003Cclass 'gitlab.v4.objects.projects.GroupProject'> was created via a\nlist() call and only a subset of the data may be present. To ensure\nall data is present get the object using a get(object.id) call. For\nmore details, see:\n\nhttps://python-gitlab.readthedocs.io/en/v3.8.1/faq.html#attribute-error-list\n =====================================\n```\n\n[Consultez le script complet](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python/-/blob/main/python_gitlab_manageable_objects.py).\n\n### Le travail avec différents scopes de collection d'objets\n\nParfois, le script doit collecter tous les projets d'une instance auto-gérée, d'un groupe avec des sous-groupes, ou d'un projet unique. Ce dernier cas est utile pour accélérer les tests sur les attributs requis, et la récupération du groupe facilite les tests à grande échelle par la suite. L'extrait de code suivant collecte tous les objets de projet dans la liste `projects` et y ajoute les objets provenant des différentes configurations entrantes. Vous retrouverez également à nouveau le modèle d'objet gérable pour le projet dans les groupes.\n\n```python\n    # Collect all projects, or prefer projects from a group id, or a project id\n    projects = []\n\n    # Direct project ID\n    if PROJECT_ID:\n        projects.append(gl.projects.get(PROJECT_ID))\n\n    # Groups and projects inside\n    elif GROUP_ID:\n        group = gl.groups.get(GROUP_ID)\n\n        for project in group.projects.list(include_subgroups=True, all=True):\n            # https://python-gitlab.readthedocs.io/en/stable/gl_objects/groups.html#examples\n            manageable_project = gl.projects.get(project.id)\n            projects.append(manageable_project)\n\n    # All projects on the instance (may take a while to process)\n    else:\n        projects = gl.projects.list(get_all=True)\n```\n\nL'exemple complet se trouve dans [ce script](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python/-/blob/main/get_mr_approval_rules.py) pour lister les paramètres des règles d'approbation des merge requests pour les cibles de projet spécifiées.\n\n## Utilisation de l’approche DevSecOps pour les actions de lecture API\n\nLe jeton d'accès authentifié nécessite un scope `read_api`.\n\nLes cas d’utilisation suivants seront abordés :\n- Lister les branches par état de fusion,\n- Afficher les paramètres du projet pour révision : règles d'approbation des merge requests,\n- Inventaire : obtenir toutes les variables CI/CD protégées ou masquées,\n- Télécharger un fichier depuis le dépôt,\n- Aide à la migration : lister tous les clusters Kubernetes basés sur des certificats,\n- Productivité des équipes : vérifier si les merge requests existantes nécessitent un rebase après avoir fusionné une merge request de refactorisation majeure.  \n\n### Lister les branches par état de fusion \n\nPour nettoyer un projet [Git](https://about.gitlab.com/fr-fr/blog/what-is-git/ \"Qu'est-ce que Git ?\"), il est courant d'évaluer le nombre de branches fusionnées et non fusionnées. En réponse à une [question sur le forum de la communauté GitLab](https://forum.gitlab.com/t/python-gitlab-project-branch-list-filter/80257) concernant le filtrage des listes de branches, j'ai écrit un [script](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python/-/tree/main) aidant à cela. La méthode `branches.list()` renvoie tous les objets de branche stockés dans une liste temporaire, pour un traitement ultérieur en deux boucles : la collecte des noms de branches fusionnées, et celle des noms de branches non fusionnées. L'attribut `merged` sur l'objet `branch` est une valeur booléenne qui indique si la branche a été fusionnée ou non.\n\n```python\nproject = gl.projects.get(PROJECT_ID, lazy=False, pagination=\"keyset\", order_by=\"updated_at\", per_page=100)\n\n# Get all branches\nreal_branches = []\nfor branch in project.branches.list():\n    real_branches.append(branch)\n\nprint(\"All branches\")\nfor rb in real_branches:\n    print(\"Branch: {b}\".format(b=rb.name))\n\n# Get all merged branches\nmerged_branches_names = []\nfor branch in real_branches:\n    if branch.default:\n        continue # ignore the default branch for merge status\n\n    if branch.merged:\n        merged_branches_names.append(branch.name)\n\nprint(\"Branches merged: {b}\".format(b=\", \".join(merged_branches_names)))\n\n# Get un-merged branches\nnot_merged_branches_names = []\nfor branch in real_branches:\n    if branch.default:\n        continue # ignore the default branch for merge status\n\n    if not branch.merged:\n        not_merged_branches_names.append(branch.name)\n\nprint(\"Branches not merged: {b}\".format(b=\", \".join(not_merged_branches_names)))\n```\n\nLe workflow est destiné à être lu étape par étape. Vous pouvez vous entraîner à optimiser le code Python pour la collecte conditionnelle des noms de branches.\n\n### Afficher les paramètres du projet pour examen : règles d'approbation des merge requests\n\nLe [script](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python/-/blob/main/get_mr_approval_rules.py) suivant parcourt tous les objets de projet collectés et vérifie si des règles d'approbation sont spécifiées. Si la longueur de la liste est supérieure à zéro, il parcourt la liste en boucle et affiche les paramètres avec la méthode JSON pretty print.\n\n```python\n    # Loop over projects and print the settings\n    # https://python-gitlab.readthedocs.io/en/stable/gl_objects/merge_request_approvals.html\n    for project in projects:\n        if len(project.approvalrules.list()) > 0:\n            #print(project) #debug\n            print(\"# Project: {name}, ID: {id}\\n\\n\".format(name=project.name_with_namespace, id=project.id))\n            print(\"[MR Approval settings]({url}/-/settings/merge_requests)\\n\\n\".format(url=project.web_url))\n\n            for ar in project.approvalrules.list():\n                print(\"## Approval rule: {name}, ID: {id}\".format(name=ar.name, id=ar.id))\n                print(\"\\n```json\\n\")\n                print(json.dumps(ar.attributes, indent=2)) # TODO: can be more beautiful, but serves its purpose with pretty print JSON\n                print(\"\\n```\\n\")\n\n```\n\n### Inventaire : obtenir toutes les variables CI/CD protégées ou masquées\n\nLes [variables CI/CD](https://docs.gitlab.com/ee/ci/variables/ \"Variables CI/CD\") sont utiles au paramétrage des pipelines et peuvent être configurées globalement sur l'instance, dans les groupes et dans les projets. Nous pouvons aussi y stocker des informations confidentielles, des mots de passe ou encore des secrets. Il peut parfois être nécessaire d’avoir une vue d'ensemble de toutes les variables CI/CD protégées ou masquées pour estimer le nombre de variables à actualiser, lors de la rotation des jetons par exemple.\n\nLe [script](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python/-/blob/main/get_all_cicd_variables_masked_or_protected.py) suivant récupère tous les groupes et projets, puis tente de collecter les variables CI/CD de l'instance globale (cela nécessite des autorisations d'administrateur), des groupes et des projets (cela nécessite des autorisations de chargé de maintenance/propriétaire). Il affiche toutes les variables CI/CD qui sont soit protégées, soit masquées, en précisant qu'une valeur potentiellement secrète y est stockée.\n\n```python\n#!/usr/bin/env python\n\nimport gitlab\nimport os\nimport sys\n\n# Helper function to evaluate secrets and print the variables\ndef eval_print_var(var):\n    if var.protected or var.masked:\n        print(\"🛡️🛡️🛡️ Potential secret: Variable '{name}', protected {p}, masked: {m}\".format(name=var.key,p=var.protected,m=var.masked))\n\nGITLAB_SERVER = os.environ.get('GL_SERVER', 'https://gitlab.com')\nGITLAB_TOKEN = os.environ.get('GL_TOKEN') # token requires maintainer+ permissions. Instance variables require admin access.\nPROJECT_ID = os.environ.get('GL_PROJECT_ID') #optional\nGROUP_ID = os.environ.get('GL_GROUP_ID', 8034603) # https://gitlab.com/everyonecancontribute\n\nif not GITLAB_TOKEN:\n    print(\"🤔 Please set the GL_TOKEN env variable.\")\n    sys.exit(1)\n\ngl = gitlab.Gitlab(GITLAB_SERVER, private_token=GITLAB_TOKEN)\n\n# Collect all projects, or prefer projects from a group id, or a project id\nprojects = []\n# Collect all groups, or prefer group from a group id\ngroups = []\n\n# Direct project ID\nif PROJECT_ID:\n    projects.append(gl.projects.get(PROJECT_ID))\n\n# Groups and projects inside\nelif GROUP_ID:\n    group = gl.groups.get(GROUP_ID)\n\n    for project in group.projects.list(include_subgroups=True, all=True):\n        # https://python-gitlab.readthedocs.io/en/stable/gl_objects/groups.html#examples\n        manageable_project = gl.projects.get(project.id)\n        projects.append(manageable_project)\n\n    groups.append(group)\n\n# All projects/groups on the instance (may take a while to process, use iterators to fetch on-demand).\nelse:\n    projects = gl.projects.list(iterator=True)\n    groups = gl.groups.list(iterator=True)\n\nprint(\"# List of all CI/CD variables marked as secret (instance, groups, projects)\")\n\n# https://python-gitlab.readthedocs.io/en/stable/gl_objects/variables.html\n\n# Instance variables (if the token has permissions)\nprint(\"Instance variables, if accessible\")\ntry:\n    for i_var in gl.variables.list(iterator=True):\n        eval_print_var(i_var)\nexcept:\n    print(\"No permission to fetch global instance variables, continueing without.\")\n    print(\"\\n\")\n\n# group variables (maintainer permissions for groups required)\nfor group in groups:\n    print(\"Group {n}, URL: {u}\".format(n=group.full_path, u=group.web_url))\n    for g_var in group.variables.list(iterator=True):\n        eval_print_var(g_var)\n\n    print(\"\\n\")\n\n# Loop over projects and print the settings\nfor project in projects:\n    # skip archived projects, they throw 403 errors\n    if project.archived:\n        continue\n\n    print(\"Project {n}, URL: {u}\".format(n=project.path_with_namespace, u=project.web_url))\n    for p_var in project.variables.list(iterator=True):\n        eval_print_var(p_var)\n\n    print(\"\\n\")\n```\n\nLe script n’affiche pas les valeurs des variables, cela étant réservé comme exercice pour les environnements sécurisés. Pour stocker des secrets, faites plutôt appel à des [fournisseurs externes](https://docs.gitlab.com/ee/ci/secrets/).\n\n### Télécharger un fichier depuis le dépôt\n\nL'objectif de ce [script](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python/-/blob/main/get_raw_file_content.py) est de télécharger un fichier à partir d’un chemin spécifié dans une branche donnée, et de stocker son contenu dans un nouveau fichier.\n\n```python\n# Goal: Try to download README.md from https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/README.md\nFILE_NAME = 'README.md'\nBRANCH_NAME = 'main'\n\n# Search the file in the repository tree and get the raw blob\nfor f in project.repository_tree():\n    print(\"File path '{name}' with id '{id}'\".format(name=f['name'], id=f['id']))\n\n    if f['name'] == FILE_NAME:\n        f_content = project.repository_raw_blob(f['id'])\n        print(f_content)\n\n# Alternative approach: Get the raw file from the main branch\nraw_content = project.files.raw(file_path=FILE_NAME, ref=BRANCH_NAME)\nprint(raw_content)\n\n# Store the file on disk\nwith open('raw_README.md', 'wb') as f:\n    project.files.raw(file_path=FILE_NAME, ref=BRANCH_NAME, streamed=True, action=f.write)\n```\n\n### Aide à la migration : lister tous les clusters Kubernetes basés sur des certificats\n\nL'intégration des clusters [Kubernetes](https://about.gitlab.com/fr-fr/blog/kubernetes-the-container-orchestration-solution/ \"Qu'est-ce que Kubernetes ?\") basée sur des certificats dans GitLab [a été dépréciée](https://docs.gitlab.com/ee/update/deprecations.html#self-managed-certificate-based-integration-with-kubernetes). Pour faciliter les plans de migration, l'inventaire des groupes et projets existants peut être automatisé à l'aide de l'API GitLab.\n\n```python\ngroups = [ ]\n\n# get GROUP_ID group\ngroups.append(gl.groups.get(GROUP_ID))\n\nfor group in groups:\n    for sg in group.subgroups.list(include_subgroups=True, all=True):\n        real_group = gl.groups.get(sg.id)\n        groups.append(real_group)\n\ngroup_clusters = {}\nproject_clusters = {}\n\nfor group in groups:\n    #Collect group clusters\n    g_clusters = group.clusters.list()\n\n    if len(g_clusters) > 0:\n        group_clusters[group.id] = g_clusters\n\n    # Collect all projects in group and subgroups and their clusters\n    projects = group.projects.list(include_subgroups=True, all=True)\n\n    for project in projects:\n        # https://python-gitlab.readthedocs.io/en/stable/gl_objects/groups.html#examples\n        manageable_project = gl.projects.get(project.id)\n\n        # skip archived projects\n        if project.archived:\n            continue\n\n        p_clusters = manageable_project.clusters.list()\n\n        if len(p_clusters) > 0:\n            project_clusters[project.id] = p_clusters\n\n# Print summary\nprint(\"## Group clusters\\n\\n\")\nfor g_id, g_clusters in group_clusters.items():\n    url = gl.groups.get(g_id).web_url\n    print(\"Group ID {g_id}: {u}\\n\\n\".format(g_id=g_id, u=url))\n    print_clusters(g_clusters)\n\nprint(\"## Project clusters\\n\\n\")\nfor p_id, p_clusters in project_clusters.items():\n    url = gl.projects.get(p_id).web_url\n    print(\"Project ID {p_id}: {u}\\n\\n\".format(p_id=p_id, u=url))\n    print_clusters(p_clusters)\n```\n\n[Consultez le script complet](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python/-/blob/main/list_cert_based_kubernetes_clusters.py).\n\n### Productivité des équipes : vérifier si les merge requests existantes nécessitent un rebase après avoir fusionné une merge request de refactorisation majeure\n\nLe dépôt du [manuel GitLab](https://about.gitlab.com/handbook/ \"Manuel de GitLab\") est un large monorepo qui contient de nombreuses merge requests créées, examinées, approuvées et fusionnées. Certaines revues prennent plus de temps que d'autres, et certaines merge requests impactent plusieurs pages, lorsqu'il s'agit par exemple de renommer une chaîne de caractères ou [toutes les pages du manuel](https://about.gitlab.com/handbook/about/#count-handbook-pages). Le manuel Marketing avait besoin d’une restructuration (pensez à une refactorisation du code), et de nombreux répertoires et chemins d'accès ont été déplacés ou renommés. \n\nLes [tâches liées aux tickets](https://gitlab.com/gitlab-com/www-gitlab-com/-/issues/13991#tasks) ont augmenté au fil du temps, et nous craignons que des conflits sur d'autres merge requests apparaissent après avoir fusionné des changements importants. Avec python-gitlab vous pouvez récupérer toutes les merge requests dans un projet donné, y compris les détails sur la branche Git, sur les chemins sources modifiés, et bien plus encore.\n\nLe script résultant configure une liste des sources touchées par toutes les merge requests, vérifie si la merge request diffère avec `mr.diffs.list()`, et si un modèle correspond à la valeur dans `old_path`. Si une correspondance est trouvée, le script l'enregistre et sauvegarde la merge request dans le dictionnaire `seen_mr`, pour un résumé ultérieur. Des attributs supplémentaires sont collectés pour afficher une liste de tâches en Markdown contenant des URL, afin de faciliter le copier-coller dans les [descriptions des tickets](https://gitlab.com/gitlab-com/www-gitlab-com/-/issues/13991#additional-tasks). [Consultez le script complet](https://gitlab.com/gitlab-da/use-cases/gitlab-api/gitlab-api-python/-/blob/main/search_mr_contains_updated_path.py).\n\n```python\nPATH_PATTERNS = [\n    'path/to/handbook/source/page.md',\n]\n\n# Only list opened MRs\n# https://python-gitlab.readthedocs.io/en/stable/gl_objects/merge_requests.html#project-merge-requests\nmrs = project.mergerequests.list(state='opened', iterator=True)\n\nseen_mr = {}\n\nfor mr in mrs:\n    # https://docs.gitlab.com/ee/api/merge_requests.html#list-merge-request-diffs\n    real_mr = project.mergerequests.get(mr.get_id())\n    real_mr_id = real_mr.attributes['iid']\n    real_mr_url = real_mr.attributes['web_url']\n\n    for diff in real_mr.diffs.list(iterator=True):\n        real_diff = real_mr.diffs.get(diff.id)\n\n        for d in real_diff.attributes['diffs']:\n            for p in PATH_PATTERNS:\n                if p in d['old_path']:\n                    print(\"MATCH: {p} in MR {mr_id}, status '{s}', title '{t}' - URL: {mr_url}\".format(\n                        p=p,\n                        mr_id=real_mr_id,\n                        s=mr_status,\n                        t=real_mr.attributes['title'],\n                        mr_url=real_mr_url))\n\n                    if not real_mr_id in seen_mr:\n                        seen_mr[real_mr_id] = real_mr\n\nprint(\"\\n# MRs to update\\n\")\n\nfor id, real_mr in seen_mr.items():\n    print(\"- [ ] !{mr_id} - {mr_url}+ Status: {s}, Title: {t}\".format(\n        mr_id=id,\n        mr_url=real_mr.attributes['web_url'],\n        s=real_mr.attributes['detailed_merge_status'],\n        t=real_mr.attributes['title']))\n```\n\n## Cas d’utilisation DevSecOps pour les actions d'écriture de l’API\n\nLe jeton d'accès authentifié nécessite une [portée d’autorisation complète de l’API](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#personal-access-token-scopes). \n\nLes cas d’utilisation suivants sont abordés :\n- Déplacer des epics d’un groupe à l’autre,\n- Conformité : vérifier que les paramètres du projet ne sont pas remplacés,\n- Prendre des notes, générer un aperçu de la date d'échéance,\n\n### Déplacer des epics d’un groupe à l’autre\n\nVous devez parfois déplacer des epics dans un autre groupe. Une question posée dans le Slack de GitLab nous a incité à examiner une [proposition de fonctionnalité pour l'interface utilisateur](https://gitlab.com/gitlab-org/gitlab/-/issues/12689), pour plus tard écrire un script API permettant d'automatiser ces étapes. L'idée consiste à déplacer une epic d'un groupe source vers un groupe cible, et de copier son titre, sa description et ses labels. Puisque les epics permettent de regrouper les tickets, elles doivent également être réaffectées à l'epic cible. Il faut aussi prendre en compte les relations parent-enfant des epics, toutes les epics enfants des epics sources devant être réaffectées à l'epic cible.\n\nLe script suivant recherche d'abord tous les attributs de l'epic source, puis crée une nouvelle epic cible avec des attributs minimaux : titre et description. La liste des labels est copiée et les modifications sont conservées grâce à l'appel `save()`. Les tickets attribués à l'epic doivent être recréés dans l'epic cible. L'appel `create()` crée l'élément de relation, et non un nouvel objet de ticket en tant que tel. Le déplacement des epics enfants nécessite une approche différente, car la relation est inversée : le `parent_id` de l'epic enfant doit être comparé à l'identifiant de l'epic source et, s'il correspond, mis à jour vers l'identifiant de l'epic cible. Après avoir tout copié avec succès, l'epic source doit être passée à l'état `closed`.\n\n```python\n#!/usr/bin/env python\n\n# Description: Show how epics can be moved between groups, including title, description, labels, child epics and issues.\n# Requirements: python-gitlab Python libraries. GitLab API write access, and maintainer access to all configured groups/projects.\n# Author: Michael Friedrich \u003Cmfriedrich@gitlab.com>\n# License: MIT, (c) 2023-present GitLab B.V.\n\nimport gitlab\nimport os\nimport sys\n\nGITLAB_SERVER = os.environ.get('GL_SERVER', 'https://gitlab.com')\n# https://gitlab.com/gitlab-da/use-cases/gitlab-api\nSOURCE_GROUP_ID = os.environ.get('GL_SOURCE_GROUP_ID', 62378643)\n# https://gitlab.com/gitlab-da/use-cases/gitlab-api/epic-move-target\nTARGET_GROUP_ID = os.environ.get('GL_TARGET_GROUP_ID', 62742177)\n# https://gitlab.com/groups/gitlab-da/use-cases/gitlab-api/-/epics/1\nEPIC_ID = os.environ.get('GL_EPIC_ID', 1)\nGITLAB_TOKEN = os.environ.get('GL_TOKEN')\n\nif not GITLAB_TOKEN:\n    print(\"Please set the GL_TOKEN env variable.\")\n    sys.exit(1)\n\ngl = gitlab.Gitlab(GITLAB_SERVER, private_token=GITLAB_TOKEN)\n\n# Main\n# Goal: Move epic to target group, including title, body, labels, and child epics and issues.\nsource_group = gl.groups.get(SOURCE_GROUP_ID)\ntarget_group = gl.groups.get(TARGET_GROUP_ID)\n\n# Create a new target epic and copy all its items, then close the source epic.\nsource_epic = source_group.epics.get(EPIC_ID)\n# print(source_epic) #debug\n\nepic_title = source_epic.title\nepic_description = source_epic.description\nepic_labels = source_epic.labels\nepic_issues = source_epic.issues.list()\n\n# Create the epic with minimal attributes\ntarget_epic = target_group.epics.create({\n    'title': epic_title,\n    'description': epic_description,\n})\n\n# Assign the list\ntarget_epic.labels = epic_labels\n\n# Persist the changes in the new epic\ntarget_epic.save()\n\n# Epic issues need to be re-assigned in a loop\nfor epic_issue in epic_issues:\n    ei = target_epic.issues.create({'issue_id': epic_issue.id})\n\n# Child epics need to update their parent_id to the new epic\n# Need to search in all epics, use lazy object loading\nfor sge in source_group.epics.list(lazy=True):\n    # this epic has the source epic as parent epic?\n    if sge.parent_id == source_epic.id:\n        # Update the parent id\n        sge.parent_id = target_epic.id\n        sge.save()\n\nprint(\"Copied source epic {source_id} ({source_url}) to target epic {target_id} ({target_url})\".format(\n    source_id=source_epic.id, source_url=source_epic.web_url,\n    target_id=target_epic.id, target_url=target_epic.web_url))\n\n# Close the old epic\nsource_epic.state_event = 'close'\nsource_epic.save()\nprint(\"Closed source epic {source_id} ({source_url})\".format(\n    source_id=source_epic.id, source_url=source_epic.web_url))\n```\n\n```shell\n$  python3 move_epic_between_groups.py\nCopied source epic 725341 (https://gitlab.com/groups/gitlab-da/use-cases/gitlab-api/-/epics/1) to target epic 725358 (https://gitlab.com/groups/gitlab-da/use-cases/gitlab-api/epic-move-target/-/epics/6)\nClosed source epic 725341 (https://gitlab.com/groups/gitlab-da/use-cases/gitlab-api/-/epics/1)\n```\n\nL'[epic cible](https://gitlab.com/groups/gitlab-da/use-cases/gitlab-api/epic-move-target/-/epics/5 \"Epic cible\") a été créée et affiche le résultat attendu : même titre, description, labels, epic enfant et tickets. \n\n![Tutoriel sur l'API GitLab : déplacer des epics](https://about.gitlab.com/images/blogimages/efficient-devsecops-workflows-python-gitlab-handson/python_gitlab_moved_epic_with_all_attributes.png){: .shadow}\n\n__Exercice :__ le script ne copie pas encore les [commentaires](https://python-gitlab.readthedocs.io/en/stable/gl_objects/notes.html) et les [fils de discussion](https://python-gitlab.readthedocs.io/en/stable/gl_objects/discussions.html). Faites des recherches et aidez-nous à mettre à jour le script. Les merge requests sont les bienvenues !\n\n### Conformité : vérifier que les paramètres du projet ne sont pas remplacés\n\nLes paramètres des projets et des groupes peuvent être modifiés accidentellement par des membres de l'équipe. Les exigences de conformité doivent être respectées. Autre cas d’utilisation : gérer la configuration avec des outils d’[Infrastructure as Code](https://about.gitlab.com/fr-fr/topics/gitops/infrastructure-as-code/ \"Infrastructure as Code\") et s'assurer que la configuration de GitLab reste la même au niveau du groupe, du projet et autres. Des outils comme Ansible ou Terraform peuvent invoquer un script API ou utiliser la bibliothèque python-gitlab pour effectuer des tâches de gestion des paramètres.\n\nDans l'exemple suivant, seule la branche `main` est protégée.\n\n![API python-gitlab : protection des branches](https://about.gitlab.com/images/blogimages/efficient-devsecops-workflows-python-gitlab-handson/python_gitlab_protected_branches_settings_main.png){: .shadow}\n\nSupposons qu'une nouvelle branche `production` a été ajoutée et qu’elle doit également être protégée. Le script suivant définit le dictionnaire des branches protégées et leurs niveaux d'accès pour les autorisations de push et de fusion au niveau du chargé de maintenance. Il établit la logique de comparaison de la [documentation python-gitlab sur les branches protégées](https://python-gitlab.readthedocs.io/en/stable/gl_objects/protected_branches.html).\n\n```python\n#!/usr/bin/env python\n\nimport gitlab\nimport os\nimport sys\n\nGITLAB_SERVER = os.environ.get('GL_SERVER', 'https://gitlab.com')\n# https://gitlab.com/gitlab-da/use-cases/\nGROUP_ID = os.environ.get('GL_GROUP_ID', 16058698)\nGITLAB_TOKEN = os.environ.get('GL_TOKEN')\n\nPROTECTED_BRANCHES = {\n    'main': {\n        'merge_access_level': gitlab.const.AccessLevel.MAINTAINER,\n        'push_access_level': gitlab.const.AccessLevel.MAINTAINER\n    },\n    'production': {\n        'merge_access_level': gitlab.const.AccessLevel.MAINTAINER,\n        'push_access_level': gitlab.const.AccessLevel.MAINTAINER\n    },\n}\n\nif not GITLAB_TOKEN:\n    print(\"Please set the GL_TOKEN env variable.\")\n    sys.exit(1)\n\ngl = gitlab.Gitlab(GITLAB_SERVER, private_token=GITLAB_TOKEN)\n\n# Main\ngroup = gl.groups.get(GROUP_ID)\n\n# Collect all projects in group and subgroups\nprojects = group.projects.list(include_subgroups=True, all=True)\n\nfor project in projects:\n    # Retrieve a full manageable project object\n    # https://python-gitlab.readthedocs.io/en/stable/gl_objects/groups.html#examples\n    manageable_project = gl.projects.get(project.id)\n\n    # https://python-gitlab.readthedocs.io/en/stable/gl_objects/protected_branches.html\n    protected_branch_names = []\n\n    for pb in manageable_project.protectedbranches.list():\n        manageable_protected_branch = manageable_project.protectedbranches.get(pb.name)\n        print(\"Protected branch name: {n}, merge_access_level: {mal}, push_access_level: {pal}\".format(\n            n=manageable_protected_branch.name,\n            mal=manageable_protected_branch.merge_access_levels,\n            pal=manageable_protected_branch.push_access_levels\n        ))\n\n        protected_branch_names.append(manageable_protected_branch.name)\n\n    for branch_to_protect, levels in PROTECTED_BRANCHES.items():\n        # Fix missing protected branches\n        if branch_to_protect not in protected_branch_names:\n            print(\"Adding branch {n} to protected branches settings\".format(n=branch_to_protect))\n            p_branch = manageable_project.protectedbranches.create({\n                'name': branch_to_protect,\n                'merge_access_level': gitlab.const.AccessLevel.MAINTAINER,\n                'push_access_level': gitlab.const.AccessLevel.MAINTAINER\n            })\n```\n\nL'exécution du script affiche la branche `main` existante, ainsi qu’une note indiquant que la branche `production` sera mise à jour. La capture d'écran des paramètres du dépôt démontre cette action.\n\n```\n$ python3 enforce_protected_branches.py                                                ─╯\nProtected branch name: main, merge_access_level: [{'id': 67294702, 'access_level': 40, 'access_level_description': 'Maintainers', 'user_id': None, 'group_id': None}], push_access_level: [{'id': 68546039, 'access_level': 40, 'access_level_description': 'Maintainers', 'user_id': None, 'group_id': None}]\nAdding branch production to protected branches settings\n```\n\n![Capture d'écran de code en Python avec GitLab](https://about.gitlab.com/images/blogimages/efficient-devsecops-workflows-python-gitlab-handson/python_gitlab_protected_branches_settings_main_production.png){: .shadow}\n\n### Prise de notes : générer un aperçu de la date d'échéance\n\nUne [discussion de Hacker News sur les outils de prise de notes](https://news.ycombinator.com/item?id=32155848) nous a inspiré la création d'un tableau Markdown, extrait de fichiers de prise de notes, et trié par date d'échéance. Le script est plus complexe à comprendre.\n",[236,736,827,737],"DevSecOps",{"slug":829,"featured":6,"template":686},"efficient-devsecops-workflows-hands-on-python-gitlab-api-automation","content:fr-fr:blog:efficient-devsecops-workflows-hands-on-python-gitlab-api-automation.yml","Efficient Devsecops Workflows Hands On Python Gitlab Api Automation","fr-fr/blog/efficient-devsecops-workflows-hands-on-python-gitlab-api-automation.yml","fr-fr/blog/efficient-devsecops-workflows-hands-on-python-gitlab-api-automation",{"_path":835,"_dir":249,"_draft":6,"_partial":6,"_locale":7,"seo":836,"content":842,"config":851,"_id":853,"_type":16,"title":854,"_source":18,"_file":855,"_stem":856,"_extension":21},"/fr-fr/blog/take-advantage-of-git-rebase",{"title":837,"description":838,"ogTitle":837,"ogDescription":838,"noIndex":6,"ogImage":839,"ogUrl":840,"ogSiteName":700,"ogType":701,"canonicalUrls":840,"schema":841},"Améliorez votre workflow avec Git rebase","Exploitez les fonctionnalités de Git rebase pour améliorer votre workflow.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749665560/Blog/Hero%20Images/speedmonorepo.jpg","https://about.gitlab.com/blog/take-advantage-of-git-rebase","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Améliorez votre workflow avec Git rebase\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Christian Couder\"}],\n        \"datePublished\": \"2022-10-06\",\n      }",{"title":837,"description":838,"authors":843,"heroImage":839,"date":845,"body":846,"category":14,"tags":847,"updatedDate":850},[844],"Christian Couder","2022-10-06","Les merge requests permettent à l'équipe de développement logiciel de passer en revue les modifications du code avant de les intégrer au projet principal. De nos jours, cette tâche prend beaucoup de temps. Découvrez comment [Git rebase](https://git-scm.com/docs/git-rebase/fr) peut vous aider à accélérer ces cycles de revues de code. Commençons par certaines\nconsidérations relatives au workflow.\n\n## Comment rectifier le code d'une merge request ? \n\nUn développeur qui a travaillé sur des modifications de code et a créé une merge request pour les intégrer au projet devra souvent procéder à des ajustements ou des corrections. Pourquoi ? Parce que certains tests peuvent échouer, des bogues peuvent être découverts, ou les relecteurs peuvent suggérer des améliorations et repérer des anomalies.\n\n### Méthode simple, mais désordonnée : multiplier les validations\n\nPour rectifier le code de la merge request, vous pouvez simplement apporter d'autres modifications par l'intermédiaire de nouvelles validations sur la branche utilisée pour créer la merge request, puis effectuer à nouveau un push de la branche afin de mettre à jour la merge request.\n\nCependant, lorsque plusieurs validations ont été ajoutées de cette manière, la merge request peut devenir un vrai défi :\n\n- Il est difficile d'effectuer une revue de code de toutes les modifications en les examinant toutes ensemble.\n- Il est difficile d'examiner les validations séparément, car elles peuvent contenir des modifications différentes sans rapport entre elles, voire de plusieurs versions d'un même code.\n\nLes relecteurs préfèrent souvent examiner les modifications de code réparties sur plusieurs petites validations autonomes pouvant faire l'objet de revues de code individuelles.\n\n### Méthode de professionnels : rebaser !\n\nLe meilleur moyen de préparer ou de rectifier le code d'une merge request consiste à toujours s'assurer que chaque validation contient de petites modifications, indépendantes et faciles à réviser.\n\nChaque validation de la branche peut nécessiter des ajustements, plutôt que d'ajouter de nouvelles validations. De prime abord plus complexe et fastidieuse, cette approche dispose d'une botte secrète : `git rebase` !\n\n## Rectifier vos validations avec `git rebase`\n\nSi votre objectif consiste à créer une merge request à partir d'une série de petites validations indépendantes, il est possible que votre branche nécessite un travail précis de rectification avant que ses validations ne soient suffisamment fiables. Une fois les validations prêtes, vous pouvez effectuer un push de la branche et mettre à jour ou créer une merge request avec cette branche.\n\n### Démarrer un rebasage interactif\n\nSi votre branche est basée sur la branche principale `main`, la commande pour rectifier votre branche est la suivante :\n\n```plaintext\ngit rebase -i main\n```\n\nCréer [un alias Git](https://git-scm.com/book/fr/v2/Les-bases-de-Git-Les-alias-Git), un alias shell ou encore une fonction shell pour cette commande pourra s'avérer très pratique dans la mesure où vous l'utiliserez très souvent.\n\nL'option `-i` passée à `git rebase` est un alias pour `--interactive`. Elle lance [un rebasage « interactif »](https://git-scm.com/docs/git-rebase/fr#git-rebase---interactive) qui ouvrira votre éditeur de code. Vous y trouverez une liste des validations de votre branche, suivie de lignes de commentaires commençant par `#`. \n\nVoici à quoi ressemble la liste des validations :\n\n```plaintext\npick 1aac632db2 first commit subject\npick a385014ad4 second commit subject\npick 6af12a88cf other commit subject\npick 5cd121e2a1 last commit subject\n```\n\nCes lignes sont des instructions sur la façon dont `git rebase` doit traiter ces validations. Les validations sont listées dans l'ordre chronologique, la validation la plus ancienne apparaissant en tête. (Cet ordre est l'inverse de l'ordre par défaut de `git log`.) Que contiennent ces lignes ?\n\n- Une instruction (dans cet exemple, `pick`) qui indique à Git l'action à entreprendre\n- Un identifiant abrégé de la validation\n- Un sujet qui vous aide à identifier le contenu de la validation\n\n### Modifier la liste des instructions\n\nVous pouvez modifier ces instructions ! Lorsque vous quittez votre éditeur de texte, `git rebase` lit les instructions que vous venez de modifier et les exécute dans l'ordre pour recréer votre branche comme vous le souhaitez.\n\nAprès les instructions pour toutes les validations, une série de lignes de commentaires explique comment modifier les lignes d'instruction, et comment chaque instruction affectera votre branche :\n\n- Si vous **supprimez la totalité de la ligne d'instruction d'une validation** de la liste,\ncette validation ne sera pas recréée.\n- Si vous **réorganisez les lignes d'instruction**, les validations seront\nrecréées dans l'ordre que vous spécifiez.\n- Si vous **changez l'action** de l'instruction `pick` en la remplaçant par exemple par\n`squash` ou `reword`, Git effectuera l'action que vous spécifiez sur cette\nvalidation.\n- Vous pouvez même **ajouter de nouvelles lignes d'instruction** avant, après ou entre\nles lignes actuelles.\n\nSi les lignes de commentaires ne sont pas suffisantes, vous pouvez trouver de plus amples informations sur ce que vous pouvez faire et le fonctionnement du rebasage Git dans les ressources suivantes :\n\n- Le chapitre [Utilitaires Git - Réécrire l'historique](https://git-scm.com/book/fr/v2/Utilitaires-Git-R%c3%a9%c3%a9crire-l%e2%80%99historique)\ndu livre « Pro Git ».\n- Le chapitre [Mode interactif](https://git-scm.com/docs/git-rebase/fr#_mode_interactif)\n  de la documentation `git rebase`.\n\n### Continuer ou abandonner le rebasage\n\nUn rebasage interactif peut être interrompu en cas de conflit (comme le ferait un rebasage\nstandard) ou si vous avez utilisé une instruction telle que `edit` dans la\nligne d'instruction. Cela vous permet d'apporter certaines modifications : vous pouvez, par exemple, diviser la validation actuelle en deux validations distinctes ou résoudre le conflit de rebasage le cas échéant. Ensuite, deux options s'offrent à vous :\n\n- Continuer le rebasage interactif à l'aide de la commande `git rebase --continue`.\n- Abandonner le rebasage à l'aide de la commande `git rebase --abort`.\n\n(Ces options `git rebase` fonctionnent également lorsqu'un rebasage standard, non interactif,\ns'arrête).\n\n## Autres conseils et avantages\n\n### Essayer les différentes instructions\n\nNous vous recommandons d'essayer les différentes instructions que vous pouvez utiliser dans\nchaque ligne d'instruction, en particulier `reword`, `edit`, `squash` et `fixup`. Vous\npouvez utiliser les versions abrégées de ces instructions : `r`, \n`e`, `s` et `f`.\n\n### Exécuter des commandes shell dans votre rebasage\n\nVous avez peut-être remarqué l'instruction `exec \u003Ccommand>` qui vous permet d'exécuter une commande shell quelle qu'elle soit à tout moment pendant le rebasage interactif. Cette commande sera plus utile pour les rebasages non interactifs, par exemple :\n\n```plaintext\ngit rebase --exec 'make test' main\n```\n\n(Il ne s'agit pas d'un rebasage interactif, car il ne contient pas l'option `-i`).\n\nL'option `--exec \u003Ccommand>` vous permet d'exécuter une commande shell après\nchaque validation rebasée, avec un arrêt du rebase dans le cas où la commande shell échoue (ce qui est signalé par un code de sortie différent de zéro).\n\n### Tester l'ensemble de vos validations\n\nEn passant la commande adéquate qui compile votre logiciel et exécute ses tests (par exemple, `make test`) à l'option `--exec`, vous pouvez vérifier que chaque validation dans votre branche se compile correctement et passe les tests.\n\nSi la commande `make test` échoue, le processus de rebasage s'arrêtera. Vous pouvez alors corriger la validation en cours immédiatement, puis poursuivre le rebasage afin de tester les validations suivantes.\n\nVérifier que la compilation de chaque validation s'effectue correctement et passe tous les tests permet de s'assurer que votre code reste opérationnel. Ceci est particulièrement utile si vous souhaitez utiliser [Git bisect](https://git-scm.com/docs/git-bisect/fr) quand vous rencontrez des régressions.\n\n## Conclusion\n\nDans Git, le rebasage est un outil très polyvalent et très utile pour rectifier le code\ndes validations. Il permet de mettre en place un workflow avec des modifications qualitatives\nproposées dans des validations et des merge requests bien structurées. Développeurs et relecteurs\nn'en seront que plus efficaces. Les revues de code et le débogage gagnent également en facilité et en efficacité.\n",[712,848,849,736],"workflow","releases","2024-11-14",{"slug":852,"featured":6,"template":686},"take-advantage-of-git-rebase","content:fr-fr:blog:take-advantage-of-git-rebase.yml","Take Advantage Of Git Rebase","fr-fr/blog/take-advantage-of-git-rebase.yml","fr-fr/blog/take-advantage-of-git-rebase",{"_path":858,"_dir":249,"_draft":6,"_partial":6,"_locale":7,"seo":859,"content":865,"config":873,"_id":875,"_type":16,"title":876,"_source":18,"_file":877,"_stem":878,"_extension":21},"/fr-fr/blog/observability-vs-monitoring-in-devops",{"title":860,"description":861,"ogTitle":860,"ogDescription":861,"noIndex":6,"ogImage":862,"ogUrl":863,"ogSiteName":700,"ogType":701,"canonicalUrls":863,"schema":864},"DevOps : de la surveillance à l'observabilité","Vous souhaitez bénéficier d'une visibilité totale sur l'ensemble du cycle de développement de vos logiciels ? La réponse tient en un mot : l'observabilité.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749665484/Blog/Hero%20Images/monitoring-update-feature-image.jpg","https://about.gitlab.com/blog/observability-vs-monitoring-in-devops","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"DevOps : de la surveillance à l'observabilité\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Mike Vanbuskirk\"}],\n        \"datePublished\": \"2022-06-14\",\n      }",{"title":860,"description":861,"authors":866,"heroImage":862,"date":868,"body":869,"category":14,"tags":870,"updatedDate":872},[867],"Mike Vanbuskirk","2022-06-14","Presque toutes les infrastructures logicielles modernes comportent des fonctions de surveillance ou de journalisation. Lancé dans les années 1980, le protocole Syslog pour les systèmes Unix a constitué un premier exemple d'audit et d'analyse des opérations à l'intérieur d'un système. Il illustre l'importance d'un mécanisme de surveillance dédié et distinct sur le plan architectural.\n\nEn dépit de son importance, la surveillance (ou monitoring) est cependant trop souvent envisagée et utilisée après coup. Les informations des systèmes de journalisation ne sont pas agrégées ou analysées pour établir des diagnostics, tandis que les systèmes de surveillance installés des années auparavant ne sont pas mis aux normes.\n\nLe paysage opérationnel a cependant évolué, donnant naissance au concept d'observabilité. Plutôt que de former des hypothèses à partir de mesures statiques, l'observabilité apporte une vue d'ensemble du comportement d'une application, et permet de comprendre comment ses performances sont perçues par les utilisateurs et utilisatrices. \n\n## Qu’est-ce que l'observabilité ?\n\nL’observabilité est la collecte et l'analyse exhaustive des données de l'ensemble des composants d'un système informatique. Elle fournit des informations détaillées sur les applications de l'environnement, qui sont essentielles à la compréhension du fonctionnement des architectures dynamiques modernes, et notamment des plateformes dans le cloud. \n\nPour comprendre l’importance de l'observabilité, commençons par définir la notion de surveillance, ainsi que les informations que cette approche permet ou non de couvrir.\n\nLa surveillance consiste à mesurer certaines données et valeurs au sein d'un système ou d'un logiciel, et à en présenter les résultats. Les mesures les plus courantes sont l'utilisation d’un processeur, d’une mémoire vive, et des temps de réponse ou de latence. De même, les systèmes de journalisation classiques fournissent une information statique sur des événements survenus pendant le fonctionnement du système.\n\nLa surveillance fournit des mesures dans un contexte limité, pouvant indiquer un problème plus important dans le système. Les outils de surveillance traditionnels permettent d'agréger et de corréler les informations. Cependant, une configuration manuelle est souvent nécessaire afin d'obtenir une vue d'ensemble. \n\n### Observabilité ou monitoring\n\nAvec le temps, le concept de surveillance a dépassé les mesures statiques d'éléments tels que l'utilisation du processeur. Dans son célèbre ouvrage *Site Reliability Engineering*, Google souligne l'impératif de se concentrer sur quatre [Golden Signals (ou signaux d'or)](https://sre.google/sre-book/monitoring-distributed-systems/ \"Golden Signals de Google\") : \n- La latence : le temps nécessaire pour traiter une requête\n- Le trafic : la mesure du haut niveau de charge global\n- Les erreurs : le taux d'échec des requêtes\n- La saturation : la mesure de l'utilisation des ressources comme fraction de l'ensemble, consacrée généralement aux ressources limitées.\n\nBien que ces mesures aident à comprendre les performances globales du système, elles nécessitent encore un investissement technique tangible afin de concevoir, mettre en place et configurer un système de surveillance complet. L'énumération des modes de défaillance possible demande un effort considérable, tout comme la définition et l’association manuelle des corrélations, même pour des cas simples. \n\nEn revanche, l'observabilité offre une image beaucoup plus intuitive et complète, interopérable avec l'ensemble des modules du système. Ainsi, vous n'avez pas besoin de concevoir un tableau de bord agrégeant des outils de surveillance disparates. Une plateforme d'observabilité est suffisamment flexible pour présenter automatiquement les informations critiques dans le contexte adéquat. Les outils d'observabilité peuvent ainsi fournir aux équipes de développement un retour sur les performances des exécutions CI/CD et une information sur la qualité de leur code.\n\nEn fin de compte, l'observabilité informatique fournit une forme de débogage et de compréhension des erreurs plus globale. Les données d'observabilité d'un système peuvent mettre en évidence des incidents totalement nouveaux (*unknown unknowns*). Ce qui peut revêtir une importance capitale, comme le montre l'exemple fourni dans la section suivante.\n\n## Pourquoi privilégier l'observabilité ?\n\nL'observabilité aide à réduire le temps moyen de résolution (MTTR). Cela se traduit par des interruptions plus courtes, des applications plus performantes et une amélioration de l'expérience des utilisateurs. Si à première vue la surveillance peut sembler offrir les mêmes avantages, considérez l’anecdote suivante. \n\nUne équipe d'ingénieurs reçoit un message du service comptable. La facture des fournisseurs de service cloud est devenue si onéreuse que le directeur financier s'en est rendu compte. Les ingénieurs DevOps consultent le système de surveillance, mais en vain : chaque partie du système est au vert pour des éléments tels que la mémoire, le processeur et les entrées et sorties de disque. En réalité, la cause profonde provient d'un autre événement totalement inconnu. \n\nUne latence DNS dans les [pipelines CI/CD](https://docs.gitlab.com/ee/ci/pipelines/ \"Pipelines CI/CD de GitLab\") provoque un taux d'échec des compilations élevé, et les nouvelles tentatives consomment fortement les ressources cloud. Cependant, le phénomène ne perdure pas assez longtemps pour être repéré par le système de surveillance. En ajoutant des outils d'observabilité et en collectant tous les types d'événements dans l'environnement, l'équipe a pu enfin identifier la source du problème et y remédier. Avec un système de surveillance traditionnel, l'organisation aurait dû a priori connaître le problème de latence DNS pour pouvoir l'identifier.\n\nL'observabilité d'un système a également de l'importance pour les équipes non techniques et commerciales. La technologie étant de plus en plus prégnante au sein de chaque pilier d'activité d'un groupe, les indicateurs clés de performance de l'infrastructure logicielle se confondent avec ceux de l'entreprise. L'observabilité peut ainsi fournir une meilleure vision des indicateurs clés de performance, et des options utilisables en libre-service pour les différentes équipes.\n\nLa qualité de l'expérience utilisateur (UX) se doit d'être au cœur des logiciels et applications modernes. Comme l'illustre l'histoire précédente, la surveillance des mesures statiques ne suffit pas pour connaître l'ensemble des performances de l'expérience utilisateur ou du système. Des tableaux de bord apparemment sains peuvent cacher de graves problèmes. \n\n## Quelles sont les mesures clés de l'observabilité ?\n\nPour les entreprises qui souhaitent utiliser des outils d'observabilité, leur mise en œuvre passe par l'identification d’objectifs principaux de l'observabilité et de la manière dont elle peut être implémentée au sein de leur structure informatique.\n\nLes trois piliers de l'observabilité constituent un excellent point de départ :\n- Les journaux (ou logs) : le suivi des informations et des événements,\n- Les métriques : la mesure de métriques spécifiques et de données de performance,\n- Le traçage : l'enregistrement des performances des requêtes d'un bout à l'autre de leur exécution.\n\nS'ils ont pu paraître insurmontables au départ, des projets comme [OpenTelemetry](https://opentelemetry.io/ \"OpenTelemetry\") aident à standardiser les normes de journalisation, de métriques et de traçage, créant ainsi un écosystème plus cohérent et un retour sur investissement plus rapide pour les entreprises mettant en œuvre l'observabilité.\n\nDes données et des piliers supplémentaires pour l'observabilité incluent :\n\n- Le suivi des erreurs : des journaux à l'information plus fine et agrégée,\n- Le *Continuous Profiling* : l'évaluation de la performance du code en temps réel dans l'environnement de production\n- Le *Real User Monitoring (RUM)* : la surveillance de l'utilisateur réel pour comprendre les performances de l'application de son point de vue.\n\nUn thème commun émerge de l'examen de ces piliers. Un examen limité dans le temps et dans l'espace ne suffit plus. Les systèmes distribués modernes requièrent une vision globale. Pour comprendre les performances d'une application, il faut d’abord effectuer un échantillonnage au niveau du client réel, et effectuer ensuite une analyse complète de ses interactions avec l'ensemble des composants du logiciel.\n\nAu-delà de la surveillance traditionnelle des applications, l'observabilité contribue à améliorer l'excellence opérationnelle des équipes d'ingénierie. C'est souvent à partir de pannes réelles et des leçons que nous en tirons que nous concevons des programmes de surveillance efficaces. La mise en œuvre de l'ingénierie du chaos permet de tester les outils d'observabilité lors de défaillances réelles, mais dans un environnement contrôlé, avec des résultats connus à l'avance. Cette approche peut apporter des gains significatifs en termes d'équilibre opérationnel, dans des systèmes où des « inconnus inconnus » peuvent se cacher dans n'importe quel workflow de l'infrastructure IT. \n\n## L'observabilité, un élément essentiel de l’approche DevOps\n\nL'observabilité est essentielle pour les [équipes DevOps](https://about.gitlab.com/fr-fr/topics/devops/ \"DevOps\"), mais aussi pour l'ensemble de l'entreprise. En remplaçant les données statiques des solutions de surveillance traditionnelles, l'[observabilité](https://about.gitlab.com/blog/observability-is-key-to-cloud-native-transitions-and-modern-application-development/ \"Observabilité\") offre une vue complète de l'infrastructure applicative.\n\nLes équipes DevOps doivent collaborer avec toutes les parties prenantes pour améliorer la mise en œuvre de l'observabilité au sein de l'entreprise et s'assurer qu'elle profite à l'ensemble des équipes. Il est aussi important de former et de sensibiliser les équipes de développement aux avantages de l'observabilité.\n\nLes équipes DevOps peuvent également aider à identifier plus rapidement la cause première des incidents de production. Une bonne instrumentation du code des applications facilitera aussi la distinction entre problèmes de code et d'infrastructure. Enfin, en déplaçant l'observabilité plus en amont dans le cycle de conception logicielle, de possibles dévers dans les objectifs de niveau de service (SLO) peuvent être détectés plus tôt.\n\nLes équipes DevOps qui souhaitent améliorer significativement les performances des applications et les résultats de l'entreprise peuvent considérer l'observabilité comme un moyen d'atteindre ces deux objectifs.\n",[805,871,714],"security","2024-08-20",{"slug":874,"featured":6,"template":686},"observability-vs-monitoring-in-devops","content:fr-fr:blog:observability-vs-monitoring-in-devops.yml","Observability Vs Monitoring In Devops","fr-fr/blog/observability-vs-monitoring-in-devops.yml","fr-fr/blog/observability-vs-monitoring-in-devops",{"_path":880,"_dir":249,"_draft":6,"_partial":6,"_locale":7,"seo":881,"content":887,"config":896,"_id":898,"_type":16,"title":899,"_source":18,"_file":900,"_stem":901,"_extension":21},"/fr-fr/blog/demystifying-ci-cd-variables",{"title":882,"description":883,"ogTitle":882,"ogDescription":883,"noIndex":6,"ogImage":884,"ogUrl":885,"ogSiteName":700,"ogType":701,"canonicalUrls":885,"schema":886},"Variables d’environnement : tout savoir sur les variables CI/CD de GitLab","Les variables CI/CD permettent de contrôler les jobs et les pipelines. Découvrez tout ce que vous devez savoir sur les variables d'environnement de GitLab.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749664679/Blog/Hero%20Images/blog-image-template-1800x945__24_.png","https://about.gitlab.com/blog/demystifying-ci-cd-variables","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Variables d’environnement : tout savoir sur les variables CI/CD de GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Veethika Mishra\"}],\n        \"datePublished\": \"2021-04-09\",\n      }",{"title":882,"description":883,"authors":888,"heroImage":884,"date":890,"body":891,"category":14,"tags":892,"updatedDate":895},[889],"Veethika Mishra","2021-04-09","Définir et utiliser des variables dans le cadre d'une approche [CI/CD](https://about.gitlab.com/fr-fr/topics/ci-cd/) s'avère une méthode très flexible. Ces variables sont d'une grande utilité pour contrôler les jobs et les pipelines, tout en vous permettant d'éviter de coder en dur des valeurs directement dans votre fichier de configuration `.gitlab-ci.yml`. \n\nDans [GitLab CI/CD](https://docs.gitlab.com/ee/ci/), les variables peuvent être utilisées pour personnaliser les jobs en définissant et en stockant des valeurs spécifiques. Pour définir vos variables CI/CD dans GitLab, accédez à **Paramètres >> CI/CD >> Variables** ou définissez-les simplement dans le fichier `.gitlab-ci.yml`. Sachez que les variables servent également d'alternative aux valeurs codées en dur.\n\nUtiliser des variables s’avère particulièrement utile pour configurer des services tiers dans différents environnements de déploiement, tels que l'environnement de test (`testing`), l'environnement de préproduction (`staging`), l'environnement de production (`production`), et plus encore. Pour modifier les services liés à ces environnements, il suffit de changer simplement la variable qui pointe vers le point de terminaison d'API associé aux services. Vous pouvez également utiliser des variables pour configurer les jobs et les rendre disponibles en tant que variables d'environnement dans les jobs lorsqu'ils s'exécutent.\n\nDécouvrez dans cet article tout ce que vous devez savoir sur les variables d’environnement afin de mieux comprendre leur fonctionnement et leur portée. \n\n![GitLab lit le fichier .gitlab-ci.yml pour analyser la variable référencée, puis envoie les informations à GitLab Runner. Les variables sont exposées et générées par le runner.](https://about.gitlab.com/images/blogimages/demystifying-ci-cd-variables/variables_processing.jpeg)\n\n## La relation entre les variables et les environnements\n\nLe processus de développement logiciel comprend plusieurs étapes destinées à tester un produit avant de le déployer et de le mettre à disposition des utilisateurs. Les [environnements](https://docs.gitlab.com/ee/ci/environments/) sont utilisés pour définir ces étapes, qui peuvent différer d'une équipe à l'autre, voire d'une entreprise à l'autre.\n\nLes variables, quant à elles, sont des valeurs de données susceptibles de changer à la suite d'une interaction entre un utilisateur et un produit. Par exemple, son âge, ses préférences ou toute autre information qui pourrait déterminer l'étape suivante qui lui sera présentée dans le flux de tâches du produit.\n\nLe terme [variable d'environnement](https://docs.gitlab.com/ee/administration/environment_variables.html) fait souvent référence à des variables définies dans un environnement donné, mais en dehors de l'application. Les variables dans GitLab CI/CD offrent aux équipes de développement la possibilité de configurer des valeurs dans le code. L'intérêt principal étant de garantir sa flexibilité. Ces variables permettent aux utilisateurs de modifier une application déployée dans un certain environnement sans toucher au code. Il est possible d'exécuter des tests en toute simplicité ou même d'intégrer des services tiers en modifiant une variable d'environnement de configuration en dehors de l'application.\n\n## La portée des variables dans l'approche CI/CD\n\n![Ordre de priorité des variables CI/CD : 1) Exécution manuelle du pipeline, variables de déclenchement et de planification du pipeline, 2) Variables protégées au niveau du projet, au niveau du groupe et au niveau de l'instance, 3) Variables CI/CD héritées, 4) Variables globales définies dans yml au niveau du job, 5) Variables de déploiement, 6) Variables CI/CD prédéfinies](https://about.gitlab.com/images/blogimages/demystifying-ci-cd-variables/variables_precedence.jpeg)\n\n### Variables définies dans `.gitlab-ci.yml`\n\nLes variables qui doivent être disponibles dans l'environnement du job peuvent être ajoutées à GitLab. Ces variables CI/CD stockent la configuration du projet ne contenant pas de données sensibles, comme l'URL de la base de données dans le fichier `.gitlab-ci.yml`. Réutilisez cette variable dans plusieurs jobs ou scripts, là où la valeur est nécessaire. Si la valeur change, vous n'avez besoin de mettre à jour la variable qu'une seule fois. Le changement se reflète ensuite partout où la variable est utilisée.\n\n### Variables CI/CD au niveau du projet\n\nUn cran au-dessus des exigences spécifiques au dépôt, vous pouvez définir des variables CI/CD dans les [paramètres du projet](https://docs.gitlab.com/ee/ci/variables/#for-a-project), afin qu'elles soient disponibles dans les [pipelines CI/CD](https://about.gitlab.com/fr-fr/topics/ci-cd/cicd-pipeline/ \"Qu'est-ce qu'un pipeline CI/CD ?\"). Celles-ci sont stockées en dehors du dépôt (c'est-à-dire qu'elles ne figurent pas dans le fichier `.gitlab-ci.yml`), mais peuvent néanmoins être utilisées dans les scripts et la configuration CI/CD. Le stockage des variables en dehors du fichier `.gitlab-ci.yml` limite ces valeurs à la portée du projet uniquement, sans les enregistrer en texte brut dans le projet.\n\n### Variables CI/CD au niveau du groupe et de l'instance\n\nCertaines variables sont pertinentes à l'échelle du groupe ou de l'instance et peuvent être utiles à tous les projets associés à un groupe ou à une instance spécifique. Définissez les variables dans les [paramètres du groupe ou de l'instance](https://docs.gitlab.com/ee/ci/variables/#for-a-group) afin que tous les projets de ces portées puissent utiliser les variables sans avoir besoin d'en connaître la valeur ou de les recréer pour chaque projet de portée inférieure. Par exemple, une valeur commune à plusieurs projets se gère facilement si elle ne doit être mise à jour qu'à un seul endroit. Alternativement, plusieurs projets peuvent utiliser un mot de passe spécifique sans avoir besoin de connaître la valeur du mot de passe lui-même.\n\n## Jobs et pipelines en tant qu'environnements\n\nEn plus d'être utilisées comme des variables d'environnement, les variables dans GitLab CI/CD fonctionnent également dans la portée du fichier de configuration `.gitlab-ci.yml` pour définir le comportement du pipeline, indépendamment de son environnement. Les variables peuvent être stockées dans les paramètres du projet/groupe/instance et mises à la disposition des jobs dans les pipelines.\n\nPar exemple :\n\n```  \njob:  \n  rules:  \n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH  \n  script:  \n  - echo \"This job ran on the $CI_COMMIT_BRANCH branch.\"  \n```\n\nLa variable `($CI_COMMIT_BRANCH)` dans la section du script s'exécute dans la portée du job dans lequel elle a été définie. Cette portée est l'« environnement du job », ce qui signifie que lorsque le job se lance, le GitLab Runner démarre un conteneur Docker et exécute le job dans cet environnement. Le runner met cette variable (et toutes les autres variables prédéfinies ou personnalisées) à la disposition du job et peut également afficher leur valeur dans les données de sortie du log si nécessaire.\n\nToutefois, la variable est aussi utilisée dans la section `if:` pour déterminer quand le job doit s'exécuter. Il ne s'agit pas en soi d'un environnement, c'est pourquoi nous les appelons variables CI/CD. Elles peuvent être utilisées pour configurer dynamiquement vos jobs CI/CD, ainsi que comme variables d'environnement lorsque le job est en cours d'exécution.\n\n## Variables prédéfinies\n\nUn certain nombre de variables sont [prédéfinies](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html) lorsqu'un pipeline GitLab CI/CD démarre. Un utilisateur peut immédiatement accéder aux valeurs pour des éléments tels que les validations, le projet ou les détails du pipeline sans avoir à définir les variables elles-mêmes.\n\n## Variables CI/CD personnalisées\n\n![Les runners peuvent créer deux types de variables CI/CD personnalisées : Type et Fichier.](https://about.gitlab.com/images/blogimages/demystifying-ci-cd-variables/variable_types.jpeg)\n\nLors de la création d'une variable CI/CD dans les paramètres, GitLab offre à l'utilisateur plus d'options pour configurer la variable. Utilisez ces options de configuration supplémentaires pour exercer un contrôle plus strict sur les variables plus sensibles :\n\n**Portée de l'environnement :** si une variable ne doit être utilisée que dans un environnement spécifique, définissez-la pour qu'elle soit disponible uniquement dans cet environnement. Par exemple, vous pouvez définir un jeton de déploiement pour qu'il ne soit disponible que dans l'environnement `production`.\n\n**Variables protégées :** comme pour la portée de l'environnement, vous pouvez définir une variable pour qu'elle ne soit disponible que lorsque le pipeline s'exécute sur une branche protégée, comme votre branche par défaut.\n\n**Type de variable :** certaines applications nécessitent que la configuration leur soit transmise sous la forme d'un fichier. Si une application nécessite cette configuration, définissez simplement le type de variable comme « Fichier ». Cette configuration de la variable CI/CD signifie que lorsque le runner rend la variable disponible dans l'environnement, il l'écrit dans un fichier temporaire et stocke le chemin d'accès au fichier en tant que valeur. Un utilisateur peut ensuite transmettre le chemin d'accès au fichier à toutes les applications qui en ont besoin.\n\nEn plus des éléments énumérés pour définir et utiliser les variables, GitLab a introduit une fonctionnalité qui génère des variables préremplies lorsqu'un pipeline doit être exécuté manuellement. Les variables préremplies réduisent les risques d'erreur et facilitent l'exécution du pipeline.\n\n**Variables masquées :** les [variables masquées](https://docs.gitlab.com/ee/ci/variables/#mask-a-cicd-variable) sont des variables CI qui ont été **cachées dans les job logs** pour empêcher l'affichage de leur valeur.\n\n**Variables masquées et cachées :** introduites dans [GitLab 17.4](https://about.gitlab.com/releases/2024/09/19/gitlab-17-4-released/#hide-cicd-variable-values-in-the-ui), les variables [masquées et cachées](https://docs.gitlab.com/ee/ci/variables/#hide-a-cicd-variable) offrent la même fonctionnalité de masquage des job logs et **gardent la valeur cachée** **dans l'interface utilisateur des paramètres**. Nous ne recommandons pas d'utiliser ces deux types de variables pour les informations sensibles (comme les secrets), car elles peuvent être exposées par inadvertance.\n\n## Secrets\n\nUn secret est un identifiant de connexion sensible qui doit rester confidentiel. Voici des exemples de secrets :\n\n* Mots de passe\n* Clés SSH\n* Jetons d'accès\n* Tout autre type d'identifiants de connexion dont la divulgation pourrait porter préjudice à l'entreprise\n\nGitLab permet actuellement à ses utilisateurs d'[utiliser des secrets externes](https://docs.gitlab.com/ee/ci/secrets/) dans l'[intégration continue (CI)](https://about.gitlab.com/fr-fr/topics/ci-cd/benefits-continuous-integration/ \"Qu'est-ce que l'intégration continue (CI) ?\"), en tirant parti de HashiCorp Vault, Google Cloud Secret Manager et Azure Key Vault pour gérer de manière sécurisée les clés, les tokens et d'autres secrets au niveau du projet. Les utilisateurs peuvent ainsi séparer ces secrets des autres variables CI/CD pour des raisons de sécurité.\n\n### Gestionnaire de secrets de GitLab\n\nEn plus de fournir une assistance pour les secrets externes dans la CI, GitLab prévoit également de proposer une [solution native de gestion des secrets](https://gitlab.com/groups/gitlab-org/-/epics/10108) permettant de stocker les secrets de manière pratique et sécurisée au sein de sa plateforme. Cette solution aidera également les clients à utiliser les secrets stockés dans les composants et les environnements spécifiques à GitLab, ainsi qu'à gérer facilement les accès au niveau des groupes d'espaces de nommage et des projets.\n\nPour en savoir plus sur le gestionnaire de secrets de GitLab, consultez notre article « [Le gestionnaire de secrets natif de GitLab renforce la sécurité de la chaîne d'approvisionnement logicielle](https://about.gitlab.com/blog/gitlab-native-secrets-manager-to-give-software-supply-chain-security-a-boost/) ». \n\n***Avertissement :** cet article de blog contient des informations relatives aux produits, fonctionnalités et caractéristiques à venir. Il est important de noter que les informations contenues dans cet article de blog ne sont fournies qu'à titre informatif. Veuillez ne pas vous fier à ces informations à des fins d'achat ou de planification. Comme pour tout projet, les éléments mentionnés dans cet article sont susceptibles de changer ou d’être retardés. Le développement, la sortie et le calendrier de tout produit ou fonctionnalité restent à la seule discrétion de GitLab.*\n",[763,893,894,762,111,736],"features","inside GitLab","2025-01-28",{"slug":897,"featured":6,"template":686},"demystifying-ci-cd-variables","content:fr-fr:blog:demystifying-ci-cd-variables.yml","Demystifying Ci Cd Variables","fr-fr/blog/demystifying-ci-cd-variables.yml","fr-fr/blog/demystifying-ci-cd-variables",{"_path":903,"_dir":249,"_draft":6,"_partial":6,"_locale":7,"seo":904,"content":910,"config":918,"_id":920,"_type":16,"title":921,"_source":18,"_file":922,"_stem":923,"_extension":21},"/fr-fr/blog/ci-deployment-and-environments",{"title":905,"description":906,"ogTitle":905,"ogDescription":906,"noIndex":6,"ogImage":907,"ogUrl":908,"ogSiteName":700,"ogType":701,"canonicalUrls":908,"schema":909},"Comment déployer du code dans des environnements multiples avec GitLab CI","GitLab CI est à la fois puissant et polyvalent. Découvrez les capacités de cet outil à travers plusieurs scénarios d'utilisation.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749662033/Blog/Hero%20Images/intro.jpg","https://about.gitlab.com/blog/ci-deployment-and-environments","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Comment déployer du code dans des environnements multiples avec GitLab CI\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Ivan Nemytchenko\"},{\"@type\":\"Person\",\"name\":\"Cesar Saavedra\"}],\n        \"datePublished\": \"2021-02-05\",\n      }",{"title":905,"description":906,"authors":911,"heroImage":907,"date":914,"body":915,"category":14,"tags":916,"updatedDate":917},[912,913],"Ivan Nemytchenko","Cesar Saavedra","2021-02-05","Imaginez-vous gestionnaire d’un site d'information. Heureusement, le code de votre projet est déjà hébergé sur GitLab.com et vous utilisez [GitLab CI/CD](https://docs.gitlab.com/ee/ci/testing/ \"Test avec GitLab CI/CD\") pour vos tests. Maintenant, vous souhaitez connaître toutes les possibilités de [déploiement](https://about.gitlab.com/fr-fr/blog/how-to-keep-up-with-ci-cd-best-practices/ \"Meilleures pratiques CI/CD\").\n\nPar souci de pertinence, supposons que l'application se compose uniquement de fichiers HTML, sans code côté serveur ni compilation sophistiquée des actifs JS. La plateforme de destination sera également générique, nous utiliserons [Amazon S3](https://aws.amazon.com/fr/s3/ \"Amazon S3\").\n\nPlutôt que de fournir des extraits de code à copier-coller, nous allons vous partager les principes et les fonctionnalités de GitLab CI, afin que vous puissiez les appliquer dans votre propre pile technologique. \n\nDéroulons donc notre histoire depuis son commencement, où il n'est pas encore question d'intégration continue.\n\n## La ligne de départ\n\n__Déploiement__ : un ensemble de fichiers HTML devraient apparaître dans votre bucket S3 (déjà configuré pour [héberger un site web statique](https://docs.aws.amazon.com/fr_fr/AmazonS3/latest/userguide/HostingWebsiteOnS3Setup.html \"Héberger un site web statique avec Amazon S3\")). Il y a des millions de façons de procéder. Dans notre cas, nous utiliserons la bibliothèque [AWS CLI](https://aws.amazon.com/fr/cli/ \"AWS CLI\") fournie par Amazon. \n\nLa commande complète ressemble à ceci :\n\n```shell\naws s3 cp ./ s3://yourbucket/ --recursive --exclude \"*\" --include \"*.html\"\n```\n\nLe push du code vers le dépôt et le déploiement sont deux processus distincts.\n\n![Déploiement manuel](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674077/Blog/Content%20Images/19-updated.png){: .center}\n{: .note .text-center}\n\nDétail important : la commande nécessite de [fournir les variables d'environnement](https://docs.aws.amazon.com/fr_fr/cli/latest/userguide/cli-chap-getting-started.html) `AWS_ACCESS_KEY_ID` et `AWS_SECRET_ACCESS_KEY`. Il vous faudra peut-être aussi spécifier `AWS_DEFAULT_REGION`. \n\nEssayons d'automatiser cette procédure avec [l'intégration continue de GitLab](https://about.gitlab.com/fr-fr/solutions/continuous-integration/ \"Intégration continue de GitLab\").\n\n## Votre premier déploiement automatisé\n\nGitLab CI offre une grande flexibilité dans l'exécution des commandes. Sa configuration s'adapte à vos besoins, reproduisant l'environnement de votre terminal local. Ajoutez votre script dans le fichier .gitlab-ci.yml et effectuez un push de votre code : l’outil d'intégration continue de GitLab déclenche un *job* et vos commandes sont exécutées.\n\nPrécisons maintenant le contexte d'utilisation de cet exemple : il s'agit d'un site de taille modeste, avec une trentaine de visiteurs journaliers, et une seule branche principale de dépôt de code. Commençons par spécifier un *job* avec la commande précédente dans le fichier `.gitlab-ci.yml` :\n\n```yaml\ndeploy:\n  script: aws s3 cp ./ s3://yourbucket/ --recursive --exclude \"*\" --include \"*.html\"\n```\n\nOups, la commande a échoué :\n\n![Message d'erreur lors de l'exécution d'un job GitLab.](https://about.gitlab.com/images/blogimages/ci-deployment-and-environments/13.jpg){: .shadow}\n\nIl fallait d'abord vérifier l'existence d'un exécutable `aws`. Pour installer `awscli`, nous avons besoin de `pip`, qui est un outil d'installation de paquets Python. Spécifions une image Docker avec Python préinstallé, qui devrait également contenir `pip` : \n\n```yaml\ndeploy:\n  image: python:latest\n  script:\n  - pip install awscli\n  - aws s3 cp ./ s3://yourbucket/ --recursive --exclude \"*\" --include \"*.html\"\n```\n\n![Déploiement automatisé](https://about.gitlab.com/images/blogimages/ci-deployment-and-environments/fail1.png){: .center}\n{: .note .text-center}\n\nVous effectuez un push de votre code sur GitLab, et il est automatiquement déployé par l’outil CI. \n\nL'installation d'`awscli` rallonge le temps d'exécution du job, mais pour l'instant ce n'est pas un souci. Pour accélérer le processus, [cherchez une image Docker](https://hub.docker.com/ \"Chercher une image Docker\") avec `awscli` préinstallé, ou créez une image vous-même. \n\nN’oublions pas les variables d'environnement récupérées depuis la [console AWS](https://console.aws.amazon.com/) :\n\n```yaml\nvariables:\n  AWS_ACCESS_KEY_ID: \"AKIAIOSFODNN7EXAMPLE\"\n  AWS_SECRET_ACCESS_KEY: \"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\"\ndeploy:\n  image: python:latest\n  script:\n  - pip install awscli\n  - aws s3 cp ./ s3://yourbucket/ --recursive --exclude \"*\" --include \"*.html\"\n```\n\nCela devrait fonctionner, mais attention : ce n'est jamais une bonne idée de dévoiler des clés secrètes de votre code, même dans un dépôt privé. Remédions donc à cette situation.\n\n### Des secrets bien gardés\n\nGitLab dispose d’un endroit spécialement dédié aux variables secrètes : __Paramètres > CI/CD > Variables__.\n\n![Ajouter une variable secrète dans GitLab](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674076/Blog/Content%20Images/add-variable-updated.png)\n\nTout ce que vous y mettez se transforme en variables d'environnement. En cochant la case « Masquée », vous masquerez la variable dans les job logs. En cochant la case « Protéger la variable », vous n’exporterez la variable uniquement vers les pipelines s'exécutant sur des branches et des étiquettes protégées. \n\nSeuls les utilisateurs ayant le statut de propriétaire ou de chargé de maintenance sur un projet auront accès à cette section. Nous pourrions supprimer la section `variables` de notre configuration CI, mais nous allons l'utiliser à d'autres fins.\n\n### Savoir spécifier et utiliser des variables non-secrètes\n\nLorsque votre configuration s'agrandit, il devient pratique de conserver certains paramètres sous formes de variables au début de votre configuration. Le cas présent ne le justifie pas, mais pour les besoins de cette démonstration, nous allons définir le nom du compartiment S3 comme variable :\n\n```yaml\nvariables:\n  S3_BUCKET_NAME: \"yourbucket\"\ndeploy:\n  image: python:latest\n  script:\n  - pip install awscli\n  - aws s3 cp ./ s3://$S3_BUCKET_NAME/ --recursive --exclude \"*\" --include \"*.html\"\n```\n\nJusqu'ici, tout va bien :\n\n![Compilation GitLab CI sans erreur](https://about.gitlab.com/images/blogimages/ci-deployment-and-environments/14.jpg){: .shadow.medium.center}\n\nDans notre scénario, la fréquentation du site est en hausse, et vous avez embauché un développeur pour vous aider. Voyons comment le workflow GitLab CI s'adapte au travail en équipe.\n\n## Comment utiliser GitLab CI en équipe\n\nAvec deux utilisateurs travaillant dans le même dépôt, il n'est plus pratique d'utiliser la branche principale pour le développement. Vous décidez d'utiliser des branches séparées pour les nouvelles fonctionnalités et les nouveaux articles, et de les fusionner dans la branche principale lorsqu'elles sont prêtes.\n\nCependant, votre configuration CI actuelle ne prend pas en charge les branches. Chaque push effectué vers GitLab sera déployé sur S3. La solution est simple : il suffit d'ajouter `only: main` au job `deploy`.\n\nEn plus de ne pas vouloir déployer chaque branche sur l’environnement de production, vous souhaiteriez pouvoir prévisualiser vos modifications depuis les branches de fonctionnalités. \n\n![Déploiement de la branche principale de GitLab vers AWS S3](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674076/Blog/Content%20Images/15-updated.png){: .center}\n{: .note .text-center}  \n\n### Comment configurer un environnement de test ?\n\nMatteo, votre nouveau développeur, vous propose d'utiliser la fonctionnalité [GitLab Pages](https://docs.gitlab.com/ee/user/project/pages/ \"GitLab Pages\"), idéale pour prévisualiser votre travail en cours. Afin d'[héberger des sites web sur GitLab Pages](https://docs.gitlab.com/ee/user/project/pages/getting_started/pages_ui.html \"Héberger des sites web sur GitLab Pages\"), votre fichier de configuration CI doit répondre à trois règles simples :\n\n- Le *job* doit être nommé `pages`\n- Il doit y avoir une section `artifacts` avec un dossier `public`\n- Tout ce que vous souhaitez héberger doit être placé dans le dossier `public`\n\nLe contenu du dossier public sera hébergé à l'adresse suivante : `http://\u003Cusername>.gitlab.io/\u003Cprojectname>/`\n\nVoici la configuration complète après avoir appliqué l’[exemple de configuration pour les sites web en HTML](https://gitlab.com/pages/plain-html/-/blob/main/.gitlab-ci.yml \"Exemple de configuration pour les sites web en HTML\") :\n\n```yaml\nvariables:\n  S3_BUCKET_NAME: \"yourbucket\"\n\ndeploy:\n  image: python:latest\n  script:\n  - pip install awscli\n  - aws s3 cp ./ s3://$S3_BUCKET_NAME/ --recursive --exclude \"*\" --include \"*.html\"\n  only:\n  - main\n\npages:\n  image: alpine:latest\n  script:\n  - mkdir -p ./public\n  - cp ./*.html ./public/\n  artifacts:\n    paths:\n    - public\n  except:\n  - main\n```\n\nNous avons spécifié deux jobs. L'un d'eux déploie le site web pour vos clients sur S3 (`deploy`). L'autre (`pages`) déploie le site web sur GitLab Pages. Nommons-les « Environnement de production » et « Environnement de préproduction ». Toutes les branches seront déployées sur GitLab Pages, à l'exception de la branche principale. \n\n![Déploiement différencié des branches dans GitLab Pages et S3.](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674076/Blog/Content%20Images/16-updated.png){: .center}\n{: .note .text-center}\n\n## Introduction aux environnements\n\nGitLab offre la prise en charge de [nombreux environnements](https://docs.gitlab.com/ee/ci/environments/ \"Environnements GitLab\") (dynamiques ou statiques) ; vous devez simplement spécifier l'environnement correspondant pour chaque *job* de déploiement :\n\n```yaml\nvariables:\n  S3_BUCKET_NAME: \"yourbucket\"\n\ndeploy to production:\n  environment: production\n  image: python:latest\n  script:\n  - pip install awscli\n  - aws s3 cp ./ s3://$S3_BUCKET_NAME/ --recursive --exclude \"*\" --include \"*.html\"\n  only:\n  - main\n\npages:\n  image: alpine:latest\n  environment: staging\n  script:\n  - mkdir -p ./public\n  - cp ./*.html ./public/\n  artifacts:\n    paths:\n    - public\n  except:\n  - main\n```\n\nGitLab garde une trace de tous vos déploiements. Ainsi, vous savez toujours ce qui est actuellement déployé sur vos serveurs :\n\n![Visualisation des environnements sur GitLab CI/CD.](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674076/Blog/Content%20Images/envs-updated.png){: .shadow.center}\n\nL'historique complet de vos déploiements sur chacun de vos environnements actuels vous est aussi fourni :\n\n![Historique des déploiements GitLab.](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674077/Blog/Content%20Images/staging-env-detail-updated.png){: .shadow.center}\n\nMaintenant que tout est automatisé et configuré, de nouveaux défis nous attendent.\n\n## Comment dépanner les déploiements ?\n\nOups ! La branche de fonctionnalités que vous avez poussé sur l'environnement de préproduction vient d'être remplacée par celle de Matteo, qui vient d'effectuer un push de sa propre branche. L'énervement vous gagne, c'est la troisième fois que cela arrive aujourd'hui ! \n\nEt si vous utilisiez Slack pour notifier vos déploiements, afin d'éviter ce genre de désagrément ?\n\n> Recevez des notifications en utilisant l'[application GitLab pour Slack](https://docs.gitlab.com/ee/user/project/integrations/gitlab_slack_application.html).\n\n## Du travail d'équipe à grande échelle\n\nQuelque temps plus tard, et vous voilà à la tête d'un site web très populaire, et d'une équipe de huit personnes. Mais, désormais, les membres de votre équipe perdent un temps précieux à attendre de pouvoir prévisualiser leur travail. Le déploiement de chaque branche en préproduction n'est plus optimal.\n\n![File d'attente de branches à examiner en préproduction](https://about.gitlab.com/images/blogimages/ci-deployment-and-environments/build.png){: .center}\n\nIl est temps de perfectionner le système. Vous convenez avec votre équipe de fusionner au préalable chaque changement sur la branche de préproduction. La modification du fichier `.gitlab-ci.yml` est minime :\n\n```yaml\nexcept:\n- main\n```\n\nest remplacé par\n\n```yaml\nonly:\n- staging\n```\n\n![Dessin de développeurs qui fusionnent leurs changements dans une branche de préproduction avant de les déployer sur S3](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674077/Blog/Content%20Images/17-updated.png){: .center}\n{: .note .text-center}\n\nVos collaborateurs doivent fusionner leurs branches de fonctionnalités avant de prévisualiser leur travail en préproduction. Cela nécessite plus de temps et d'efforts, mais tout le monde s'accorde à dire que c'est toujours mieux que d'attendre.\n\n## Comment gérer les urgences ?\n\nIl arrive parfois que les choses tournent mal. Quelqu'un a mal fusionné des branches et a effectué un push du résultat directement en production, juste au moment où le hashtag de votre site devenait viral sur les réseaux sociaux. Des milliers de personnes voient des visuels cassés au lieu de votre page d'accueil habituelle. Heureusement, la fonction __Restaurer l’environnement__ a permis de résoudre le problème en moins d'une minute.\n\n![Fonctionnalité de restauration sur la plateforme GitLab](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674077/Blog/Content%20Images/18-updated.png){: .shadow.center}\n{: .note .text-center}\n\nLa fonction de restauration de l'environnement relance le job précédent avec la validation précédente. Vous avez décidé de désactiver le déploiement automatique en production et de passer au déploiement manuel. Pour ce faire, vous devez ajouter  `when : manual` à votre *job*. Il n'y aura effectivement plus de déploiement automatique en production. Le déploiement manuel s'effectue en allant dans __Compilation > Pipelines__, et en cliquant sur __« Exécuter des jobs manuels ou différés »__ :\n\n![Déploiement manuel sur GitLab.](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674077/Blog/Content%20Images/prod-env-rollback-arrow-updated.png){: .shadow.center}\n\nEffectuons maintenant un bond en avant dans le temps. Votre entreprise est devenue une société de plusieurs centaines d'employés travaillant sur le site web, et les compromis précédents ne fonctionnent plus.\n\n### Faire ses premiers pas avec les Review Apps\n\nLogiquement, la nouvelle étape consiste à lancer une instance temporaire de l'application par branche de fonctionnalités pour la revue. Pour cela, nous avons configuré un autre bucket S3. Sa seule particularité est que le contenu du site est placé dans un dossier portant le nom de la branche de développement, de sorte que l’URL ressemble à :\n\n`http://\u003CREVIEW_S3_BUCKET_NAME>.s3-website-us-east-1.amazonaws.com/\u003Cbranchname>/`\n\nVoici le remplacement du *job* `pages` utilisé auparavant :\n\n```yaml\nreview apps:\n  variables:\n    S3_BUCKET_NAME: \"reviewbucket\"\n  image: python:latest\n  environment: review\n  script:\n  - pip install awscli\n  - mkdir -p ./$CI_BUILD_REF_NAME\n  - cp ./*.html ./$CI_BUILD_REF_NAME/\n  - aws s3 cp ./ s3://$S3_BUCKET_NAME/ --recursive --exclude \"*\" --include \"*.html\"\n```\n\nIci, il est bon de connaître l'origine de cette variable `$CI_BUILD_REF_NAME`. GitLab prédéfinit de [nombreuses variables d'environnement](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html \"Variables d'environnement dans GitLab\") à utiliser dans vos jobs. Notez que nous avons défini la variable `S3_BUCKET_NAME` à l'intérieur du *job*. Vous pouvez ainsi réécrire les définitions de niveau supérieur. \n\nReprésentation visuelle de la configuration des Review Apps :\n\n![Dessin représentant la configuration Review Apps de GitLab.](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674076/Blog/Content%20Images/manual-pipeline-arrow-updated.png){: .illustration}\n\nLes détails de l'implémentation des Review Apps varient selon votre pile technologique et de votre processus de déploiement. Tout ne sera pas aussi simple qu'avec un site HTML statique. Programmer des instances temporaires à la volée avec tous les logiciels et services requis n'est pas chose aisée. Mais tout cela peut être accompli, notamment à l'aide des conteneurs Docker, Chef ou Ansible.\n\nLe déploiement avec Docker mériterait d'ailleurs un article complet. Et si vous regrettez l'absence de scénarios plus complexes qu'un simple déploiement en HTML statique, nous vous recommandons de lire [cet article](https://about.gitlab.com/blog/building-an-elixir-release-into-docker-image-using-gitlab-ci-part-1/ \"Construire une version d'Elixir dans une image Docker en utilisant GitLab CI - Partie 1\"). Abordons maintenant un dernier sujet.\n\n### Déployer sur différentes plateformes\n\nDans la pratique, nous ne sommes pas limités à S3 et à GitLab Pages. Nous hébergeons et déployons nos applications sur différents services. De plus, si vous décidez un jour de passer à une nouvelle plateforme, vous devrez alors réécrire tous vos scripts de déploiement. Vous pourrez alors utiliser une petite merveille appelée `dpl` pour vous faciliter la tâche.\n\nJusqu'ici, nous avons utilisé `awscli` pour livrer du code à un service comme Amazon S3. Quel que soit le système utilisé, le principe reste le même : vous exécutez une commande avec certains paramètres et transmettez une clé secrète d'authentification. L'outil de déploiement `dpl` utilise ce principe et fournit une interface unique pour cette [liste de fournisseurs](https://github.com/travis-ci/dpl#supported-providers \"Liste de fournisseurs\"). Voici à quoi ressemblerait le déploiement d’un *job* en production avec `dpl`:\n\n```yaml\nvariables:\n  S3_BUCKET_NAME: \"yourbucket\"\n\ndeploy to production:\n  environment: production\n  image: ruby:latest\n  script:\n  - gem install dpl\n  - dpl --provider=s3 --bucket=$S3_BUCKET_NAME\n  only:\n  - main\n```\n\nEn cas de déploiement sur plusieurs systèmes ou de changements fréquents de plateforme de destination, `dpl` vous aide à uniformiser vos scripts de déploiement.\n\n## Cinq points clés à retenir\n\n1. Un déploiement est une commande (ou un ensemble de commandes) régulièrement exécutée. Il peut donc être exécuté dans GitLab CI.\n\n2. La plupart des commandes à exécuter nécessitent de fournir une ou plusieurs clés secrètes, que vous stockez dans __Paramètres > [CI/CD](https://about.gitlab.com/fr-fr/topics/ci-cd/ \"Qu'est-ce que le CI/CD ?\") > Variables__.\n\n3. Avec GitLab CI, vous pouvez spécifier de façon flexible les branches vers lesquelles vous déployez votre code.\n\n4. GitLab conserve l'historique des déploiements dans tous vos environnements, et vous permet de revenir à n'importe quelle version précédente.\n\n5. Pour les éléments critiques de votre infrastructure, vous pouvez activer le déploiement manuel depuis l'interface de GitLab, au lieu du déploiement automatisé.\n",[762,763,736],"2024-11-21",{"slug":919,"featured":6,"template":686},"ci-deployment-and-environments","content:fr-fr:blog:ci-deployment-and-environments.yml","Ci Deployment And Environments","fr-fr/blog/ci-deployment-and-environments.yml","fr-fr/blog/ci-deployment-and-environments",{"_path":925,"_dir":249,"_draft":6,"_partial":6,"_locale":7,"seo":926,"content":932,"config":940,"_id":942,"_type":16,"title":943,"_source":18,"_file":944,"_stem":945,"_extension":21},"/fr-fr/blog/we-need-to-talk-no-proxy",{"title":927,"description":928,"ogTitle":927,"ogDescription":928,"noIndex":6,"ogImage":929,"ogUrl":930,"ogSiteName":700,"ogType":701,"canonicalUrls":930,"schema":931},"Pouvons-nous standardiser la variable d'environnement NO_PROXY ?","Découvrez notre guide complet sur no_proxy, la configuration des paramètres du proxy, ainsi que les spécificités de no_proxy, http_proxy et https_proxy.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659507/Blog/Hero%20Images/AdobeStock_623844718.jpg","https://about.gitlab.com/blog/we-need-to-talk-no-proxy","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Pouvons-nous standardiser la variable d'environnement NO_PROXY ?\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Stan Hu\"}],\n        \"datePublished\": \"2021-01-27\",\n      }",{"title":927,"description":928,"authors":933,"heroImage":929,"date":934,"body":935,"category":14,"tags":936},[681],"2021-01-27","Si vous avez déjà utilisé un serveur proxy Web, vous êtes probablement familier avec les variables d’environnement `http_proxy` ou `HTTP_PROXY`. Cependant, vous l'êtes peut-être moins avec la variable `no_proxy` qui permet d’exclure le trafic destiné à certains hôtes d'utiliser le proxy. Bien que le protocole HTTP soit standardisé, aucune norme ne précise comment utiliser ces variables. Par conséquent, les clients Web prennent en charge ces variables de manière différente.  \n\nDécouvrez dans cet article tout ce que vous devez savoir sur la variable d’environnement no_proxy, ainsi qu’un cas pratique d’un de nos clients GitLab. \n\n## Comprendre http_proxy, https_proxy et no_proxy\n\nDe nos jours, la plupart des clients Web permettent de se connecter à des serveurs proxy via les variables d'environnement suivantes : \n\n- `http_proxy` / `HTTP_PROXY`\n- `https_proxy` / `HTTPS_PROXY`\n- `no_proxy` / `NO_PROXY`\n\nCes variables indiquent au client l'URL à utiliser pour accéder aux serveurs proxy et quelles exceptions appliquer. \n\nPar exemple, si vous avez un serveur proxy attaché à `http://alice.example.com:8080`, vous pourriez l’utiliser via : \n\n```sh\nexport http_proxy=http://alice.example.com:8080\n```\n\nMais quel serveur proxy sera utilisé si Maxime définit aussi la version en majuscules : `HTTP_PROXY` ?\n\n```sh\nexport HTTP_PROXY=http://maxime.example.com:8080\n```\nAussi surprenant que cela puisse paraître, cela dépend. Dans certains cas, le proxy d'Alice est utilisé, dans d'autres cas, c'est celui de Maxime. Nous y reviendrons plus loin dans cet article. \n\nQue se passe-t-il si vous souhaitez définir des exceptions ? Par exemple, admettons que vous souhaitez utiliser un serveur proxy pour tout, sauf pour `internal.example.com` et `internal2.example.com`. C'est ici que la variable `no_proxy` entre en jeu. Vous paramétrez alors `no_proxy` comme suit : \n\n```sh\nexport no_proxy=internal.example.com,internal2.example.com\n```\n\nEt si vous souhaitez exclure certaines adresses IP ? Faut-il utiliser des astérisques ou des caractères génériques ? Ou bien utiliser des blocs CIDR (comme `192.168.1.1/32`) ? Même réponse : cela dépend.\n\n## L'évolution des variables proxy et no_proxy\n\nEn 1994, la plupart des clients Web utilisaient la bibliothèque logicielle `libwww` du CERN, qui prenait en charge les variables d'environnement `http_proxy` et `no_proxy`. `libwww` utilisait uniquement la forme en minuscules de `http_proxy` et [la syntaxe de `no_proxy` était simple](https://github.com/w3c/libwww/blob/8678b3dcb4191065ca39caea54bb1beba809a617/Library/src/HTAccess.c#L234-L239) : \n\n```\nno_proxy is a comma- or space-separated list of machine\nor domain names, with optional :port part.  If no :port\npart is present, it applies to all ports on that domain.\n\nExample:\n\t\tno_proxy=\"cern.ch,some.domain:8001\"\n```\n\nDe nouveaux clients sont apparus, ajoutant leurs propres implémentations HTTP sans les relier à `libwww`. En janvier 1996, Hrvoje Niksic publie `geturl`, le prédécesseur de ce qu'on connaît aujourd'hui sous le nom de `wget`. Un mois plus tard, [`geturl` prend en charge `http_proxy` dans la version v1.1](https://ftp.sunet.se/mirror/archive/ftp.sunet.se/pub/www/utilities/wget/old-versions/). En mai 1996, `geturl` v1.3 ajoute la prise en charge de `no_proxy`. Tout comme `libwww`, `geturl` n'accepte que les minuscules. \n\nEn janvier 1998, Daniel Stenberg publie `curl` v5.1, [qui prend en charge les variables `http_proxy` et `no_proxy`](https://github.com/curl/curl/blob/ae1912cb0d494b48d514d937826c9fe83ec96c4d/CHANGES#L929-L944). De plus, `curl` accepte désormais les majuscules, `HTTP_PROXY` et `NO_PROXY`.\n\n__Nota Bene :__ en mars 2009, [`curl` v7.19.4](https://github.com/curl/curl/releases/tag/curl-7_19_4) abandonne la prise en compte de la forme en majuscules de `HTTP_PROXY` [en raison de problèmes de sécurité](https://github.com/curl/curl/blob/30e7641d7d2eb46c0b67c0c495a0ea7e52333ee2/lib/url.c#L2250-L2261). Cependant, même si `curl` n'accepte plus `HTTP_PROXY`, `HTTPS_PROXY` fonctionne toujours.\n\n## Gestion des variables du serveur proxy\n\nSuite aux [recherches de notre collègue Nourdin el Bacha](https://gitlab.com/gitlab-com/support/support-team-meta/-/issues/2991), nous comprenons que la gestion des variables du serveur proxy varie en fonction du langage ou de l'outil utilisé. \n\n### http_proxy et https_proxy\n\nDans ce tableau, chaque ligne représente une variable, et chaque colonne correspond à l'outil (comme `curl`) ou au langage (comme `Ruby`) auquel elle s'applique : \n\n|                 | curl      | wget           | Ruby          | Python    | Go        |\n|-----------------|-----------|----------------|---------------|-----------|-----------|\n| `http_proxy`    | Oui       | Oui            | Oui           | Oui       | Oui        |\n| `HTTP_PROXY`    | Non        | Non           | Oui ([Mise en garde](https://github.com/ruby/ruby/blob/0ed71b37fa9af134fdd5a7fd1cebd171eba83541/lib/uri/generic.rb#L1519)) | Oui (si `REQUEST_METHOD` n'est pas dans env)       | Oui       |\n| `https_proxy`   | Oui       | Oui            | Oui           | Oui       | Oui       |\n| `HTTPS_PROXY`   | Oui       | Non             | Oui           | Oui       | Oui       |\n| Casse de caractères | Minuscules | Minuscules uniquement | Minuscules     | Minuscules | Majuscules |\n| Sources       | [source](https://github.com/curl/curl/blob/30e7641d7d2eb46c0b67c0c495a0ea7e52333ee2/lib/url.c#L2250-L2266) | [source](https://github.com/jay/wget/blob/099d8ee3da3a6eea5635581ae517035165f400a5/src/retr.c#L1222-L1239) | [source](https://github.com/ruby/ruby/blob/0ed71b37fa9af134fdd5a7fd1cebd171eba83541/lib/uri/generic.rb#L1474-L1543) | [source](https://github.com/python/cpython/blob/030a713183084594659aefd77b76fe30178e23c8/Lib/urllib/request.py#L2488-L2517) | [source](https://github.com/golang/go/blob/682a1d2176b02337460aeede0ff9e49429525195/src/vendor/golang.org/x/net/http/httpproxy/proxy.go#L82-L97) |\n\nNotez que `http_proxy` et `https_proxy` sont toujours pris en charge, alors que `HTTP_PROXY` ne l'est pas. Python (via `urllib`) ne facilite pas les choses : `HTTP_PROXY` peut être utilisé [tant que `REQUEST_METHOD` n'est pas défini dans l'environnement](https://github.com/python/cpython/blob/030a713183084594659aefd77b76fe30178e23c8/Lib/urllib/request.py#L2504-L2508).\n\nLes variables d'environnement sont normalement définies en majuscules, mais puisque `http_proxy` est apparu en premier, il est devenu de fait la norme. En cas de doute, optez pour la forme en minuscules, car elle est universellement prise en charge.\n\nContrairement à la plupart des implémentations, Go essaie d'abord la forme en majuscules avant revenir à la version en minuscules. Nous verrons plus tard pourquoi cela a causé du tort à notre client GitLab. \n\n### no_proxy\n\nCertains utilisateurs ont signalé le [manque d'indications sur `no_proxy`](https://github.com/curl/curl/issues/1208). Puisque `no_proxy` définit une liste d'exceptions, des questions sur son fonctionnement se posent. \n\nPar exemple, vous configurez votre `no_proxy` comme suit : \n\n```sh\nexport no_proxy=example.com\n```\n\nEst-ce que cela signifie que le domaine doit être une correspondance exacte ou que `subdomain.example.com` corresponde aussi à cette configuration ? \n\nLe tableau suivant présente les différentes configurations. Toutes les implémentations correspondent aux suffixes, comme le montre la ligne « `correspondance des suffixes` ».\n\n|                       | curl      | wget           | Ruby      | Python    | Go        |\n|-----------------------|-----------|----------------|-----------|-----------|-----------|\n| `no_proxy`            | Oui       | Oui          | Oui     | Oui      | Oui      |\n| `NO_PROXY`            | Oui       | Non             | Oui       | Oui       | Oui       |\n| Casse de caractères       | Minuscules | Minuscules uniquement | Minuscules | Minuscules | Majuscules |\n| Correspondance des suffixes ?     | Oui       | Oui            | Oui       | Oui       | Oui       |\n| Points initiaux `.` ?   | Oui       | Non             | Oui       | Oui       | Non        |\n| `*` fait correspondre tous les hôtes| Oui       | Non             | Non        | Oui       | Oui       |\n| Prise en charge des expressions régulières ?     | Non        | Non             | Non        | Non        | Non        |\n| Prise en charge des blocs CIDR ? | Non        | Non             | Oui       | Non        | Oui       |\n| Détection des adresses IP de bouclage ? | Non        | Non             | Non        | Non        | Oui       |\n| Sources            | [source](https://github.com/curl/curl/blob/30e7641d7d2eb46c0b67c0c495a0ea7e52333ee2/lib/url.c#L2152-L2206) | [source](https://github.com/jay/wget/blob/099d8ee3da3a6eea5635581ae517035165f400a5/src/retr.c#L1266-L1274) | [source](https://github.com/ruby/ruby/blob/0ed71b37fa9af134fdd5a7fd1cebd171eba83541/lib/uri/generic.rb#L1545-L1554) | [source](https://github.com/python/cpython/blob/030a713183084594659aefd77b76fe30178e23c8/Lib/urllib/request.py#L2519-L2551)| [source](https://github.com/golang/go/blob/682a1d2176b02337460aeede0ff9e49429525195/src/vendor/golang.org/x/net/http/httpproxy/proxy.go#L170-L206) |\n\nCependant, si `no_proxy` est précédé d'un `.`, cela implique des changements. \n\nPar exemple, `curl` et `wget` se comportent différemment. `curl` supprime le `.` dans la configuration pour se coller au suffixe du domaine. Il contourne ainsi le proxy :\n\n```sh\n$ env https_proxy=http://non.existent/ no_proxy=.gitlab.com curl https://gitlab.com\n\u003Chtml>\u003Cbody>You are being \u003Ca href=\"https://about.gitlab.com/\">redirected\u003C/a>.\u003C/body>\u003C/html>\n```\n\nNéanmoins, `wget` ne supprime pas le `.` et utilise la correspondance exacte avec le nom d'hôte. Par conséquent, `wget` essaie d'utiliser un proxy si un domaine de premier niveau est utilisé : \n\n```sh\n$ env https_proxy=http://non.existent/ no_proxy=.gitlab.com wget https://gitlab.com\nResolving non.existent (non.existent)... failed: Name or service not known.\nwget: unable to resolve host address 'non.existent'\n```\n\nToutes les implémentations ne prennent pas en charge les expressions régulières (regex). Utiliser des regex peut compliquer la configuration puisqu'elles peuvent prendre différentes variantes (comme PCRE ou POSIX). L'utilisation d'expressions régulières entraîne également de potentielles failles de sécurité et de performance. \n\nConfigurer `no_proxy` avec un astérisque (`*`) peut désactiver l'utilisation de proxy pour toutes les adresses, bien que ce principe ne soit pas appliqué tout le temps. \n\nAu moment de décider de l'utilisation d'un proxy, aucune implémentation n'effectue de recherche DNS pour résoudre un nom d'hôte en adresse IP. Il est préférable d'éviter de spécifier les adresses IP dans `no_proxy` à moins que le client ne les utilise explicitement. \n\nIl en va de même pour les blocs CIDR, tels que `18.240.0.1/24`. Ces blocs ne fonctionnent que si la requête est faite directement à une adresse IP. Seuls les environnements de développement Go et Ruby permettent l'utilisation de blocs CIDR. Go désactive même automatiquement l'utilisation d'un proxy si une adresse IP de bouclage est détectée, ce qui n'est pas le cas dans d'autres implémentations.\n\n## Pourquoi les paramètres du proxy sont-ils importants ?\n\nSi votre application est codée en plusieurs langages et doit fonctionner avec un pare-feu avec un serveur proxy, il est important de faire attention à ces différences. \n\nPar exemple, GitLab est composé d'éléments codés en Ruby et d'autres en Go. Un de nos clients a configuré son proxy de la façon suivante : \n\n```yaml\nHTTP_PROXY: http://proxy.company.com\nHTTPS_PROXY: http://proxy.company.com\nNO_PROXY: .correct-company.com\n```\n\nIl a ensuite signalé un problème avec GitLab : \n- Un `git push` à partir de la ligne de commande a fonctionné.\n- Les modifications Git effectuées à partir de l'interface Web ont échoué.\n\nNos ingénieurs ont découvert qu'un problème de configuration de [Kubernetes](https://about.gitlab.com/fr-fr/blog/kubernetes-the-container-orchestration-solution/ \"Kubernetes\") entraînait le maintien de valeurs obsolètes. L'environnement ressemblait à : \n\n```yaml\nHTTP_PROXY: http://proxy.company.com\nHTTPS_PROXY: http://proxy.company.com\nNO_PROXY: .correct-company.com\nno_proxy: .wrong-company.com\n```\n\nLes irrégularités entre `no_proxy` et `NO_PROXY` ont entraîné des alertes. Supprimer l'entrée incorrecte ou uniformiser les variables auraient pu résoudre le problème. Observons ce qu'il s'est passé. \n\nRappelez-vous que : \n- Ruby priorise `no_proxy`.\n- Go priorise `NO_PROXY`.\n\nPar conséquent, les services codées en Go, comme [GitLab Workhorse](https://docs.gitlab.com/ee/development/workhorse/), ont un bon paramétrage du proxy. Un `git push` depuis la ligne de commande a fonctionné car les services Go gèrent cette activité : \n\n```mermaid\nsequenceDiagram\n    autonumber\n    participant C as Client\n    participant W as Workhorse\n    participant G as Gitaly\n    C->>W: git push\n    W->>G: gRPC: PostReceivePack\n    G->>W: OK\n    W->>C: OK\n```\n\nL'appel gRPC de l'étape 2 n'a jamais tenté d'utiliser le proxy car `no_proxy` a été configuré correctement pour se connecter directement à Gitaly.\n\nCependant, lorsqu'un utilisateur effectue une modification dans l'interface utilisateur, Gitaly transmet la requête au service `gitaly-ruby`, qui est écrit en Ruby. `gitaly-ruby` effectue des modifications dans le dépôt et renvoie un rapport via un appel gRPC à son processus parent. Malheureusement, comme le montre l'étape 4 ci-dessous, l'étape de reporting n'a pas eu lieu :\n\n```mermaid\nsequenceDiagram\n    autonumber\n    participant C as Client\n    participant R as Rails\n    participant G as Gitaly\n    participant GR as gitaly-ruby\n    participant P as Proxy\n    C->>R: Change file in UI\n    R->>G: gRPC: UserCommitFiles\n    G->>GR: gRPC: UserCommitFiles\n    GR->>P: CONNECT\n    P->>GR: FAIL\n```\n\nPuisque gRPC utilise HTTP/2 comme mode de transport, `gitaly-ruby` tente de se connecter au proxy (il était connecté à une configuration erronée de `no_proxy`). Le proxy a immédiatement rejeté la requête HTTP, ce qui a entraîné l'erreur du push sur l'interface Web. \n\nAprès la suppression des minuscules `no_proxy` de l'environnement, les pushs depuis l'interface utilisateur ont fonctionné comme prévu. `gitaly-ruby` s'est connecté au processus parent Gitaly. L'étape 4 a donc fonctionné comme suit : \n\n```mermaid\nsequenceDiagram\n    autonumber\n    participant C as Client\n    participant R as Rails\n    participant G as Gitaly\n    participant GR as gitaly-ruby\n    participant P as Proxy\n    C->>R: Change file in UI\n    R->>G: gRPC: UserCommitFiles\n    G->>GR: gRPC: UserCommitFiles\n    GR->>G: OK\n    G->>R: OK\n    R->>C: OK\n```\n\n#### Pourquoi faut-il privilégier un proxy HTTPS ?\n\nNotez que le client a défini `HTTPS_PROXY` sur un proxy HTTP non crypté : `http://` est préféré à `https://`. Bien que ce ne soit pas idéal en termes de sécurité, certaines équipes de développement utilisent cette méthode pour éviter les problèmes de certificats TLS (et donc, des problèmes de connexion pour les utilisateurs finaux). \n\nSi un proxy HTTPS avait été spécifié, nous n’aurions pas rencontré ce problème. Lorsqu'un proxy HTTPS est utilisé, gRPC ignore ce paramètre car [les proxy HTTPS ne sont pas pris en charge](https://github.com/grpc/grpc/issues/20939).\n\n## Le plus petit dénominateur commun\n\nPersonne ne devrait définir des valeurs irrégulières avec des paramètres de proxy en minuscules et en majuscules. Cependant, si vous devez gérer une stack dans plusieurs langages, vous pourrez configurer les paramètres de proxy HTTP selon le plus petit dénominateur commun.\n\n### `http_proxy` et `https_proxy`\n\n`HTTP_PROXY` n'est pas toujours pris en charge ou recommandé. Préférez toujours le format en minuscules et si vous devez absolument utiliser la version en majuscules, vérifiez qu'elles partagent la même valeur.\n\n### `no_proxy`\n\n1. Adoptez le format en minuscules.\n2. Utilisez les valeurs `hostname:port` séparées par des virgules.\n3. Les adresses IP sont acceptables, mais les noms d'hôtes ne sont pas résolus.\n4. Les suffixes correspondent toujours (`example.com` correspondra à `test.example.com`).\n5. Évitez d'utiliser le point initial (`.`) pour les domaines de premier niveau.\n6. Veillez à ne pas utiliser de correspondances de blocs CIDR. Seuls Go et Ruby les prennent en charge. \n\n## Standardiser `no_proxy`\n\nConnaître le plus petit dénominateur commun aide à éviter des problèmes si ces définitions sont copiées pour différents clients Web. Mais est-ce que `no_proxy` et les autres configurations de proxy requièrent une version standard documentée plutôt qu'une convention ad hoc ? \n\nVoici quelques points qui peuvent vous aider : \n\n1. Préférez le format en minuscules aux variantes en majuscules (`http_proxy` devrait être utilisé avant `HTTP_PROXY`).\n2. Utilisez des valeurs `hostname:port` séparées par des virgules (chaque valeur peut inclure des espaces facultatifs.). \n3. Ne faites pas de recherche DNS et évitez les expressions régulières (regex). \n4. Appliquez `*` pour faire correspondre tous les hôtes.\n5. Supprimez les points initiaux (`.`) et faites correspondre les suffixes de domaine. \n6. Prenez en charge la correspondance des blocs CIDR. \n7. Évitez les suppositions sur des adresses IP spéciales (comme les adresses de bouclage dans `no_proxy`).\n\n## Conclusion\n\nPlus de 30 ans se sont écoulés depuis la sortie du premier serveur proxy Web. Depuis, les principes fondamentaux pour configurer un client Web grâce à des variables n'ont pas vraiment changé. Néanmoins, certaines subtilités ont vu le jour. \n\nÀ travers un cas pratique, vous avez découvert qu'une définition erronée des variables `no_proxy` et `NO_PROXY` a entraîné des heures de travail pour résoudre le problème, en raison de différences d'acceptation de configuration entre Ruby et Go. \n\nEn mettant en évidence ces différences, nous espérons vous éviter de futurs problèmes dans votre stack de production. Et qui sait, nous verrons peut-être voir le jour une standardisation au niveau des chargés de maintenance des clients Web. \n",[272,937,938,939],"careers","user stories","startups",{"slug":941,"featured":6,"template":686},"we-need-to-talk-no-proxy","content:fr-fr:blog:we-need-to-talk-no-proxy.yml","We Need To Talk No Proxy","fr-fr/blog/we-need-to-talk-no-proxy.yml","fr-fr/blog/we-need-to-talk-no-proxy",{"_path":947,"_dir":249,"_draft":6,"_partial":6,"_locale":7,"seo":948,"content":954,"config":961,"_id":963,"_type":16,"title":964,"_source":18,"_file":965,"_stem":966,"_extension":21},"/fr-fr/blog/basics-of-gitlab-ci-updated",{"title":949,"description":950,"ogTitle":949,"ogDescription":950,"noIndex":6,"ogImage":951,"ogUrl":952,"ogSiteName":700,"ogType":701,"canonicalUrls":952,"schema":953},"Intégration continue : créez votre premier pipeline CI avec GitLab ","Vous débutez dans l'intégration continue ? Apprenez à créer votre premier pipeline CI avec GitLab. Lisez notre guide complet.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749662061/Blog/Hero%20Images/cicdcover.png","https://about.gitlab.com/blog/basics-of-gitlab-ci-updated","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Intégration continue : créez votre premier pipeline CI avec GitLab \",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Itzik Gan Baruch\"}],\n        \"datePublished\": \"2020-12-10\",\n      }",{"title":949,"description":950,"authors":955,"heroImage":951,"date":957,"body":958,"category":14,"tags":959,"updatedDate":960},[956],"Itzik Gan Baruch","2020-12-10","Imaginons que vous ne connaissiez rien au concept d’[intégration continue (CI)](https://about.gitlab.com/fr-fr/topics/ci-cd/benefits-continuous-integration/ \"Qu'est-ce que l'intégration continue (CI) ?\") ni à son rôle clé dans le cycle de vie du développement logiciel.\n\nÀ présent, supposons que vous travaillez sur un projet pour lequel l'intégralité du code est répartie dans seulement deux fichiers. Pour garantir le bon fonctionnement de ce projet, il est impératif que la concaténation de ces deux fichiers contienne la phrase « Hello world ».\n\nToute la réussite du projet repose sur cette simple phrase, car sans elle, tout serait compromis.\n\nConscient de cet enjeu, votre meilleur développeur logiciel a décidé de créer un script qui s'exécute dès qu’un nouveau morceau de code est envoyé aux clients.\n\nVoici à quoi cela ressemble  :\n\n```bash\ncat file1.txt file2.txt | grep -q \"Hello world\"\n```\n\nMême si, en l'état, ce script permet d'exécuter notre tâche, son déclenchement reste manuel. Et, avec une équipe de développement composée de 10 personnes, vous n'êtes pas à l'abri d'une erreur humaine qui pourrait vous coûter très cher. \n\nLa preuve en est, pas plus tard que la semaine dernière, un nouveau membre de votre équipe a oublié d'exécuter le script, provoquant des erreurs de compilation pour trois de vos clients.\n\nVous prenez donc la décision de résoudre ce problème, une bonne fois pour toutes, en utilisant le pipeline d'[intégration et de livraison continues](https://about.gitlab.com/fr-fr/solutions/continuous-integration/ \"Intégration et livraison continues\") de GitLab. Par chance, votre code est déjà sur la plateforme. Il ne vous reste plus qu'à vous lancer.  \n\n## Effectuer un premier test dans le pipeline CI de GitLab\n\nÀ la lecture de la documentation de GitLab, nous savons qu'il suffit de réunir deux lignes de code dans un fichier appelé `.gitlab-ci.yml`:\n\n```yaml\ntest:\n  script: cat file1.txt file2.txt | grep -q 'Hello world'\n```\n\nNous le validons et constatons que la compilation s'est déroulée avec succès\n\n![Compilation réussie dans le pipeline d’intégration continue](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674096/Blog/Content%20Images/build_succeeded.png)\n\nMaintenant, remplaçons « world » par « Africa » dans le deuxième fichier et voyons ce qui se passe :\n\n![Échec de compilation dans le pipeline CI GitLab](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674096/Blog/Content%20Images/build_failed.png)\n\nComme nous pouvions le prévoir, la compilation a échoué.\n\nNous avons désormais mis en place l'automatisation des tests.  \n\nÀ partir de maintenant, [GitLab CI](https://about.gitlab.com/fr-fr/blog/ci-deployment-and-environments/ \"Comment déployer du code dans des environnements multiples avec GitLab CI\") exécutera notre script de test dès que nous effectuerons un push du code vers le dépôt de code source dans l'environnement [DevOps](https://about.gitlab.com/fr-fr/topics/devops/ \"Que signifie DevOps ?\"). \n\nRemarque : dans l'exemple ci-dessus, nous supposons que file1.txt et file2.txt existent sur l'hôte du runner. Pour exécuter cet exemple dans GitLab, utilisez le code ci-dessous, qui crée d'abord les fichiers, puis exécute le script.\n\n```yaml\ntest:\nbefore_script:\n      - echo \"Hello \" > | tr -d \"\\n\" | > file1.txt\n      - echo \"world\" > file2.txt\nscript: cat file1.txt file2.txt | grep -q 'Hello world'\n```\n\nPour simplifier notre démonstration, nous partons du principe que ces fichiers existent déjà sur l'hôte. Nous n'allons donc pas les créer dans les étapes suivantes.\n\n## Rendre les résultats des compilations téléchargeables\n\nLa prochaine étape consiste à empaqueter le code avant de l'envoyer aux clients. Alors, pourquoi ne pas automatiser aussi cette partie du processus de développement logiciel ?\n\nPour cela, tout ce que nous devons faire est de définir un autre job pour l'intégration continue. \n\nCommençons par nommer notre job « package » :\n\n```yaml\ntest:\n  script: cat file1.txt file2.txt | grep -q 'Hello world'\n\npackage:\n  script: cat file1.txt file2.txt | gzip > package.gz\n```\n\nNous avons maintenant deux onglets : \n\n![Deux onglets - générés par deux jobs](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674096/Blog/Content%20Images/two_tabs.png)\n\nCependant, nous avons oublié de spécifier que le nouveau fichier est un artefact de compilation, afin qu’il puisse être téléchargé. Nous pouvons corriger cela en ajoutant une section `artefacts` :\n\n```yaml\ntest:\n  script: cat file1.txt file2.txt | grep -q 'Hello world'\n\npackage:\n  script: cat file1.txt file2.txt | gzip > packaged.gz\n  artifacts:\n    paths:\n    - packaged.gz\n```\n\nVérifions que tout est en place :\n\n![Artefact de compilation téléchargeable dans le pipeline CI/CD de GitLab](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674096/Blog/Content%20Images/artifacts.png)\n\nFélicitations ! Tout semble fonctionnel. En revanche, dans la configuration actuelle, les jobs s'exécutent en parallèle. Cela signifie que notre application pourra être empaquetée, et ce, même si les tests échouent. Pour éviter que cela ne se produise, nous allons devoir exécuter les jobs de manière séquentielle.  \n\n## Exécuter des jobs de manière séquentielle\n\nPour éviter d'empaqueter une application contenant des erreurs, nous allons faire en sorte d'exécuter le job « package » uniquement si les tests sont préalablement réussis. Pour commencer, définissons l'ordre d'exécution en établissant des étapes spécifiques  :\n\n```yaml\nstages:\n  - test\n  - package\n\ntest:\n  stage: test\n  script: cat file1.txt file2.txt | grep -q 'Hello world'\n\npackage:\n  stage: package\n  script: cat file1.txt file2.txt | gzip > packaged.gz\n  artifacts:\n    paths:\n    - packaged.gz\n```\n\nCela devrait maintenant fonctionner.\n\nNous souhaitons également garantir que la compilation (qui est représentée par la concaténation dans notre exemple) ne s'exécute qu'une seule fois. En effet, cette étape pouvant être chronophage, il serait dommage de l'exécuter inutilement.\n\nPour éviter cela, définissons une étape supplémentaire :\n\n```yaml\nstages:\n  - compile\n  - test\n  - package\n\ncompile:\n  stage: compile\n  script: cat file1.txt file2.txt > compiled.txt\n  artifacts:\n    paths:\n    - compiled.txt\n\ntest:\n  stage: test\n  script: cat compiled.txt | grep -q 'Hello world'\n\npackage:\n  stage: package\n  script: cat compiled.txt | gzip > packaged.gz\n  artifacts:\n    paths:\n    - packaged.gz\n```\n\nJetons un œil à nos artefacts :\n\n![Artefacts de compilation dans le pipeline CI de GitLab](https://about.gitlab.com/images/blogimages/the-basics-of-gitlab-ci/clean-artifacts.png)\n\nTout a l'air de fonctionner. En revanche, il faudrait éviter de rendre le fichier « compile » téléchargeable. Pour cela, nous allons rendre nos artefacts temporaires expirables en définissant `expire_in` à « 20 minutes ».  \n\n```yaml\ncompile:\n  stage: compile\n  script: cat file1.txt file2.txt > compiled.txt\n  artifacts:\n    paths:\n    - compiled.txt\n    expire_in: 20 minutes\n```\n\nMaintenant, notre configuration semble plutôt complète : \n- Nous avons trois étapes séquentielles pour compiler, tester et empaqueter notre application. \n- Nous transmettons également l'application compilée aux étapes suivantes pour ne pas exécuter la compilation à deux reprises (ce qui accélère le processus). \n- Et nous stockons une version empaquetée de notre application dans les artefacts de compilation pour une utilisation ultérieure.\n\n## Savoir quelle image Docker utiliser\n\nJusqu'ici, tout va bien. Cependant, en regardant de plus près, nos compilations semblent toujours lentes. Prenons un moment pour regarder les journaux (logs) :\n\n![Image ruby 3.1](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674096/Blog/Content%20Images/ruby-31.png)\n\nEn observant de plus près, nous remarquons la mention suivante : `ruby:3.1`. Cela signifie que GitLab.com utilise des images Docker pour [exécuter nos compilations](https://about.gitlab.com/blog/shared-runners/), et qu’il utilise [par défaut](https://docs.gitlab.com/ee/user/gitlab_com/#shared-runners), l'image [`ruby:3.1`](https://hub.docker.com/_/ruby/).\n\nCette image contient certainement de nombreux paquets dont nous n'avons pas besoin. Dans un souci d'optimisation de notre pipeline CI, il serait donc préférable de changer d'image. Après une courte recherche sur Google, nous découvrons qu'il existe une image Linux presque vierge appelée [`alpine`](https://hub.docker.com/_/alpine/). Nous allons alors l'utiliser. Pour cela, nous devrons ajouter `image: alpine` au fichier `.gitlab-ci.yml`.\n\nEt voilà !  Nous avons maintenant réduit le temps de compilation de presque trois minutes :\n\n![Vitesse de compilation améliorée dans le pipeline de GitLab](https://about.gitlab.com/images/blogimages/the-basics-of-gitlab-ci/speed.png)\n\nVous pouvez également trouver des images libres de droits sur [mysql](https://hub.docker.com/_/mysql/), [Python](https://hub.docker.com/_/python/), [Java](https://hub.docker.com/_/java/) et [php](https://hub.docker.com/_/php/). Il est facile, alors, d'en choisir une pour notre pile technologique. \n\nNote : il sera toujours préférable d'utiliser une image qui ne contient aucun logiciel supplémentaire dont vous n'avez pas besoin, car cela minimise grandement le temps de téléchargement.\n\n## Gérer des scénarios complexes \n\nImaginons maintenant un scénario un peu plus complexe. Par exemple, un nouveau client souhaite que nous empaquetions notre application au format `.iso` plutôt qu'en `.gz`. \n\nÉtant donné que le pipeline d'intégration continue gère tout le processus, et que les images ISO peuvent être créées avec la commande `mkisofs`, il suffit d'ajouter un job supplémentaire.\n\nVoici à quoi notre configuration devrait ressembler :\n\n```yaml\nimage: alpine\n\nstages:\n  - compile\n  - test\n  - package\n\n# ... \"compile\" and \"test\" jobs are skipped here for the sake of compactness\n\npack-gz:\n  stage: package\n  script: cat compiled.txt | gzip > packaged.gz\n  artifacts:\n    paths:\n    - packaged.gz\n\npack-iso:\n  stage: package\n  script:\n  - mkisofs -o ./packaged.iso ./compiled.txt\n  artifacts:\n    paths:\n    - packaged.iso\n```\n\nNotez que les noms des jobs ne doivent pas être nécessairement identiques. S'ils l'étaient, il serait impossible de faire s'exécuter les jobs en parallèle dans la même étape du processus de développement logiciel. \n\nAinsi, dans l'exemple qui suit, ignorez le fait que les jobs et étapes portent le même nom.\n\nQuoi qu'il en soit, la compilation échoue :\n\n![Echec de compilation dans le pipeline de GitLab](https://about.gitlab.com/images/blogimages/the-basics-of-gitlab-ci/mkisofs.png)\n\nLe problème vient de  `mkisofs` qui n'est pas inclus dans l'image `alpine`. Nous devons donc d'abord l'installer.\n\n## Gérer des logiciels et des paquets manquants \n\nSelon le [site Web d’Alpine Linux](https://pkgs.alpinelinux.org/contents?file=mkisofs&path=&name=&branch=edge&repo=&arch= \"Site Web Alpine Linux\"), `mkisofs` fait partie des paquets `xorriso` et `cdrkit`. Voici les commandes que nous devons exécuter pour installer un paquet :\n\n```bash\necho \"ipv6\" >> /etc/modules  # enable networking\napk update                   # update packages list\napk add xorriso              # install package\n```\n\nCes commandes s'exécutent de la même manière que toute autre commande au sein du processus d'intégration continue. La liste complète des commandes que nous devons transmettre à la section `script` devrait ressembler à ceci :\n\n```yml\nscript:\n- echo \"ipv6\" >> /etc/modules\n- apk update\n- apk add xorriso\n- mkisofs -o ./packaged.iso ./compiled.txt\n```\n\nCependant, pour des raisons sémantiques, plaçons les commandes liées à l'installation du paquet dans `before_script`. \n\nNotez que si vous utilisez `before_script` au niveau supérieur d'une configuration, alors les commandes s'exécuteront avant tous les jobs. Dans notre cas, nous voulons simplement qu'elles s'exécutent avant un job spécifique.\n\n## Graphes acycliques orientés pour des pipelines CI plus rapides et flexibles\n\nPlus haut, nous avons configuré des étapes pour que les jobs d'empaquetage ne s'exécutent qu'à la condition que les tests réussissent. Mais, que se passerait-il si nous voulions bouleverser le séquencement des étapes en exécutant certains jobs plus tôt qu'initialement prévu ? \n\nDans certains cas, le séquencement traditionnel des étapes peut ralentir la durée globale d'exécution du [pipeline CI/CD](https://about.gitlab.com/fr-fr/topics/ci-cd/cicd-pipeline/ \"Qu'est-ce qu'un pipeline CI/CD ?\"). Pour éviter cela, nous pouvons choisir de personnaliser le séquencement de nos jobs. \n\nPar exemple : imaginons que notre étape de test comprenne des tests lourds, prenant beaucoup de temps à s'exécuter. Supposons aussi que ces tests ne soient pas nécessairement liés aux jobs d’empaquetage. Dans ce cas, il serait préférable que les jobs d’empaquetage puissent démarrer sans attendre la fin de ces tests. C'est là qu'interviennent les [graphes acycliques orientés](https://about.gitlab.com/blog/directed-acyclic-graph/ \"Graphes acycliques orientés\"). Ces derniers visent à rompre l'ordre normal d'exécution des jobs (ordre séquentiel) grâce à la création de dépendances entre certains jobs. Vous pouvez ainsi définir un ordre personnalisé pour exécuter les différents jobs de votre pipeline CI.\n\nGrâce au mot-clé `needs`, GitLab crée des dépendances entre les jobs et leur permet de s'exécuter plus tôt, dès que leurs jobs dépendants sont terminés.\n\nDans l'exemple ci-dessous, les jobs d’empaquetage commenceront à s'exécuter dès que le test sera terminé. Ainsi, à l'avenir, si quelqu'un ajoute d'autres tests à l'étape de test, les jobs d’empaquetage commenceront à s'exécuter avant la fin des nouveaux tests :\n\n```yaml\npack-gz:\n  stage: package\n  script: cat compiled.txt | gzip > packaged.gz\n  needs: [\"test\"]\n  artifacts:\n    paths:\n    - packaged.gz\n\npack-iso:\n  stage: package\n  before_script:\n  - echo \"ipv6\" >> /etc/modules\n  - apk update\n  - apk add xorriso\n  script:\n  - mkisofs -o ./packaged.iso ./compiled.txt\n  needs: [\"test\"]\n  artifacts:\n    paths:\n    - packaged.iso\n```\n\nVoici notre version définitive de `.gitlab-ci.yml`:\n\n```yaml\nimage: alpine\n\nstages:\n  - compile\n  - test\n  - package\n\ncompile:\n  stage: compile\n  before_script:\n      - echo \"Hello  \" | tr -d \"\\n\" > file1.txt\n      - echo \"world\" > file2.txt\n  script: cat file1.txt file2.txt > compiled.txt\n  artifacts:\n    paths:\n    - compiled.txt\n    expire_in: 20 minutes\n\ntest:\n  stage: test\n  script: cat compiled.txt | grep -q 'Hello world'\n\npack-gz:\n  stage: package\n  script: cat compiled.txt | gzip > packaged.gz\n  needs: [\"test\"]\n  artifacts:\n    paths:\n    - packaged.gz\n\npack-iso:\n  stage: package\n  before_script:\n  - echo \"ipv6\" >> /etc/modules\n  - apk update\n  - apk add xorriso\n  script:\n  - mkisofs -o ./packaged.iso ./compiled.txt\n  needs: [\"test\"]\n  artifacts:\n    paths:\n    - packaged.iso\n```\n\nNous venons de créer un pipeline ! Ainsi, nous avons trois étapes séquentielles avec les \njobs `pack-gz` et `pack-iso` qui s'exécutent en parallèle à l'intérieur de l'étape d'empaquetage :\n\n![Représentation d'un artefact de compilation d'un pipeline CI](https://about.gitlab.com/images/blogimages/the-basics-of-gitlab-ci/pipeline.png)\n\n## Améliorer votre pipeline CI\n\nNous allons maintenant découvrir comment améliorer notre pipeline d'intégration continue.\n\n### Intégrer des tests automatisés dans vos pipelines CI\n\nL'objectif clé du développement logiciel avec une approche DevOps est de réussir à créer des applications offrant une excellente expérience utilisateur. \n\nAvec cet objectif en tête, pourquoi ne pas renforcer le cycle de développement logiciel en cherchant à détecter d'éventuels bogues dès le début du processus ? Pour ce faire, ajoutons des tests à notre pipeline CI. De cette façon, nous pourrons résoudre les problèmes le plus tôt possible.\n\nPar chance, le pipeline CI de GitLab nous facilite la tâche en proposant des templates de tests prêts à l'emploi. Tout ce que nous avons à faire, c'est d'inclure ces templates dans la configuration de notre pipeline CI.\n\nDans cet exemple, nous allons réaliser des [tests d'accessibilité](https://docs.gitlab.com/ee/ci/testing/accessibility_testing.html \"Test d'accessibilité\") :\n\n```yaml\nstages:\n  - accessibility\n\nvariables:\n  a11y_urls: \"https://about.gitlab.com https://www.example.com\"\n\ninclude:\n  - template: \"Verify/Accessibility.gitlab-ci.yml\"\n```\n\nPersonnalisez la variable `a11y_urls` pour répertorier les URL des pages web à tester avec [Pa11y](https://pa11y.org/ \"Pa11y\") et GitLab [Code Quality](https://docs.gitlab.com/ee/ci/testing/code_quality.html \"Code Quality\"). \n\n```yaml\n   include:\n   - template: Jobs/Code-Quality.gitlab-ci.yml\n```\n\nGitLab facilite la consultation du rapport de test directement dans la zone du widget de la [merge request](https://docs.gitlab.com/ee/user/project/merge_requests/ \"Merge request\"). Ce widget vous permet de voir la revue de code, l'état du pipeline et les résultats des tests au même endroit. La capture d'écran ci-dessous montre à quel point ce widget facilite le travail de vos équipes. \n\n![Exemple de rapport d'accessibilité dans le pipeline CI/CD de GitLab](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674096/Blog/Content%20Images/Screenshot_2024-04-02_at_10.56.41.png)\n\u003Ccenter>\u003Ci>Widget pour les merge requests en matière d'accessibilité\u003C/i>\u003C/center>\u003Cp>\u003C/p>\n\n![Exemple de rapport de test sur la qualité du code suite à une merge request dans GitLab](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674096/Blog/Content%20Images/Screenshot_2024-04-02_at_11.00.25.png)\n\u003Ccenter>\u003Ci>Widget de merge request pour GitLab Code Quality\u003C/i>\u003C/center>\n\n### Matrice des compilations\n\nDans certains cas, nous devons tester notre application dans différentes configurations, versions de systèmes d'exploitation et langages de programmation. Nous utilisons alors la compilation « [parallel:matrix](https://docs.gitlab.com/ee/ci/yaml/#parallelmatrix \"parallel:matrix\") ». Cela nous permet de tester notre application à travers diverses combinaisons en parallèle dans un seul job. Maintenant, testons notre code avec différentes versions de Python et avec le mot-clé « matrix ».\n\n```yaml\npython-req:\n  image: python:$VERSION\n  stage: lint\n  script:\n    - pip install -r requirements_dev.txt\n    - chmod +x ./build_cpp.sh\n    - ./build_cpp.sh\n  parallel:\n    matrix:\n      - VERSION: ['3.8', '3.9', '3.10', '3.11']   # https://hub.docker.com/_/python\n```\n\nLors de l'exécution du pipeline, ce job s'exécute en parallèle quatre fois, chaque fois en utilisant une image Python différente comme indiqué ci-dessous :\n\n![Exécution de jobs en parallèle dans le pipeline CI/CD](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674096/Blog/Content%20Images/Screenshot_2024-04-02_at_11.12.48.png)\n\n### Tests unitaires\n\n#### Que sont les tests unitaires ?\n\nLes tests unitaires sont des tests ciblés et de petite envergure qui vérifient des composants ou des fonctions d'un logiciel. Ces tests permettent d'assurer qu'il fonctionne comme prévu. Ils sont essentiels pour vérifier que chaque partie du code fonctionne correctement et permettent de détecter les bogues le plus tôt possible dans le processus de développement logiciel. \n\nExemple : imaginez que vous développiez une application de calculatrice. Un test unitaire pour la fonction « addition » va vérifier si le résultat d'un calcul comme 2 + 2 est bien égale à 4. Si ce test est concluant, nous avons confirmation que la fonction « addition » fonctionne correctement.\n\n#### Tests unitaires : les bonnes pratiques\n\nMettre en place des tests unitaires, c'est bien, mais il est possible d'aller encore plus loin pour faciliter la vie de vos équipes de développement.\n\nPar exemple, lorsqu'un test échoue, vos équipes reçoivent une notification. S'engage alors un long processus de vérification des job logs afin de trouver et de corriger les erreurs. Ce processus est long et pourrait être optimisé.\n\nIl est possible de configurer votre job pour qu'il utilise des [rapports de tests unitaires](https://docs.gitlab.com/ee/ci/testing/unit_test_reports.html \"Rapports de tests unitaires\") (rapports détaillés des erreurs permettant de les traiter plus efficacement). GitLab affiche ces rapports dans la merge request et sur la page de détails des pipelines CI. Cela facilite l'identification des échecs, car il n'y a alors plus besoin de consulter l'intégralité du journal.\n\n#### Rapport de test JUnit\n\nCi-dessous un exemple de rapport de test JUnit : \n\n![Rapport de test JUnit dans un pipeline d'intégration continue](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674097/Blog/Content%20Images/pipelines_junit_test_report_v13_10.png){: .shadow.center}\n\n### Stratégies d'intégration et de tests de bout en bout\n\nAfin de s'assurer que toutes les parties de notre code fonctionnent en harmonie (y compris les [microservices](https://about.gitlab.com/fr-fr/topics/microservices/ \"Que sont les microservices ?\"), les tests d'interface utilisateur), il est capital de configurer un pipeline dédié à l'intégration et aux tests de bout en bout.\n\nCes tests sont exécutés [chaque nuit](https://docs.gitlab.com/ee/ci/pipelines/schedules.html) et il est possible de configurer le système pour que les [résultats soient automatiquement envoyés vers un canal Slack dédié](https://docs.gitlab.com/ee/user/project/integrations/gitlab_slack_application.html#notification-events). Ainsi, lorsque les équipes de développement arrivent le matin, elles peuvent rapidement travailler sur les problèmes identifiés la veille. L'objectif étant de détecter et de corriger les problèmes le plus tôt possible dans le processus de développement logiciel.\n\n### Environnement de test\n\nDans certains cas, nous avons besoin d'un environnement dédié pour tester correctement nos applications. On parle alors d'environnement de test. Avec le pipeline CI/CD de GitLab, nous pouvons automatiser le déploiement des environnements de test, et ainsi gagner un temps considérable. \n\nComme cet article se concentre principalement sur les pipelines d'intégration continue, nous ne nous attarderons pas sur ce point ici. En revanche, libre à vous de consulter la section dédiée à ce sujet dans la [documentation GitLab](https://docs.gitlab.com/ee/topics/release_your_application.html).\n\n## Implémenter des scans de sécurité dans un pipeline CI\n\nVoici comment mettre en œuvre des scans de sécurité dans un pipeline CI.\n\n### Intégration des SAST et des DAST\n\nAvant toute chose, nous souhaitons garder notre code en sécurité. S'il y a la moindre vulnérabilité dans nos dernières modifications, nous voulons en être informés dès que possible. C'est pourquoi il est judicieux d'ajouter des scans de sécurité à votre pipeline CI. \nCes scans vérifient le code à chaque commit et vous alertent dès qu'une faille est détectée. \n\nIl existe deux types de scan : \n- les tests statiques de sécurité des applications ([SAST](https://docs.gitlab.com/ee/user/application_security/sast/ \"SAST\"))\n- les tests dynamiques de sécurité des applications ([DAST](https://docs.gitlab.com/ee/user/application_security/dast/ \"DAST\"))\n\nCi-dessous, consultez notre guide interactif qui vous montre comment ajouter des scans de sécurité à votre pipeline CI. \n\nCliquez sur l'image ci-dessous pour commencer. \n\n[![Scans product tour](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674096/Blog/Content%20Images/Screenshot_2024-04-14_at_13.44.42.png)](https://gitlab.navattic.com/gitlab-scans)\n\nGrâce à l'IA et à ses capacités d'analyse, nous pouvons également obtenir des suggestions sur la manière dont les vulnérabilités peuvent être corrigées. Consultez cette démonstration pour plus d'informations.\n\nCliquez sur l'image ci-dessous pour commencer. \n\n[![product tour explain vulnerability ](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674096/Blog/Content%20Images/Screenshot_2024-04-14_at_13.50.24.png)](https://tech-marketing.gitlab.io/static-demos/pt-explain-vulnerability.html)\n\n## Récapitulatif\n\nDans cet article, nous avons volontairement simplifié les exemples afin de faciliter l'intégration des différents concepts de GitLab CI.\n\nRésumons rapidement ce que nous avons appris :\n1. Pour déléguer certaines tâches à GitLab CI, vous devez définir un ou plusieurs [jobs](https://docs.gitlab.com/ee/ci/jobs/) dans `.gitlab-ci.yml`.\n2. Les jobs doivent avoir des noms, de préférence facilement identifiables.\n3. Chaque job contient un ensemble de règles et d'instructions pour le pipeline de GitLab. Ces derniers sont définis par des mots-clés spécifiques.\n4. Les jobs peuvent s'exécuter de manière séquentielle, en parallèle, ou dans l'ordre de votre choix grâce aux graphes acycliques orientés. \n5. Vous pouvez transférer des fichiers entre les jobs et les stocker dans des artefacts de compilation afin de pouvoir les télécharger depuis l'interface de GitLab CI.\n6. Ajoutez [des tests et des scans de sécurité](https://docs.gitlab.com/ee/development/integrations/secure.html \"Tests et scans de sécurité\") au pipeline CI pour garantir la qualité et la sécurité de votre application.\n\nCi-dessous se trouvent des descriptions des termes et des mots-clés que nous avons abordés dans cet article.\n\n### Mots-clés, descriptions et documentation\n\n{: #keywords}\n\n| Mots-clés/termes       | Description |\n|---------------|--------------------|\n| [.gitlab-ci.yml](https://docs.gitlab.com/ee/ci/yaml/) | Fichier contenant toutes les explications sur la façon dont votre projet doit être construit |\n| [script](https://docs.gitlab.com/ee/ci/yaml/#script)        | Définit un script shell à exécuter |\n| [before_script](https://docs.gitlab.com/ee/ci/yaml/#before_script) | Utilisé pour définir la commande qui doit être exécutée avant tous les jobs |\n| [image](https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-image) | Définit l’image Docker à utiliser |\n| [stages](https://docs.gitlab.com/ee/ci/yaml/#stages)         | Définit une étape du pipeline CI (par défaut : `test`) |\n| [artifacts](https://docs.gitlab.com/ee/ci/yaml/#artifacts)     | Définit une liste d'artefacts de compilation |\n| [artifacts:expire_in](https://docs.gitlab.com/ee/ci/yaml/#artifactsexpire_in) | Utilisé pour supprimer les artefacts téléchargés après une durée spécifiée |\n| [needs](https://docs.gitlab.com/ee/ci/yaml/#needs) | Permet de définir les dépendances entre les jobs et permet d'exécuter des jobs dans l'ordre de votre choix |\n| [pipelines](https://about.gitlab.com/fr-fr/topics/ci-cd/cicd-pipeline/) | Un pipeline est un groupe de compilations exécutées par étapes (batch) |\n\n## En savoir plus sur les pipelines CI/CD\n\n- [Quelles sont les meilleures pratiques CI/CD à connaître ?](https://about.gitlab.com/fr-fr/blog/how-to-keep-up-with-ci-cd-best-practices/ \"Quelles sont les meilleures pratiques CI/CD à connaître ?\")\n- [Le guide CI/CD de GitLab pour les débutants](https://about.gitlab.com/blog/beginner-guide-ci-cd/)\n- [Obtenez des pipelines plus rapides et plus flexibles avec un graphe acyclique orienté](https://about.gitlab.com/blog/directed-acyclic-graph/)\n- [Réduisez le temps de compilation avec une image Docker personnalisée](http://beenje.github.io/blog/posts/gitlab-ci-and-conda/)\n- [Présentation de la version bêta du catalogue GitLab CI/CD](https://about.gitlab.com/blog/introducing-the-gitlab-ci-cd-catalog-beta/)\n\n## FAQ sur le pipeline d’intégration continue\n\n### Comment choisir entre l'exécution séquentielle et parallèle des jobs dans un pipeline CI ?\n\nIl y a plusieurs considérations à prendre en compte pour choisir entre l'exécution séquentielle et parallèle des jobs dans un pipeline CI. Ainsi, il faut considérer les dépendances entre les jobs, la disponibilité des ressources, les temps d'exécution, les interférences potentielles, la structure de la séquence de tests ou encore les coûts que cela implique. \n\nPar exemple, si vous avez un job de compilation qui doit se terminer avant qu'un job de déploiement puisse démarrer, vous exécuterez ces jobs de manière séquentielle pour garantir le bon ordre d'exécution. En revanche, les tâches telles que les tests unitaires et les tests d'intégration peuvent généralement s'exécuter en parallèle, car elles ne dépendent pas de l'achèvement des autres.\n\n### Que sont les graphes acycliques orientés dans GitLab et comment améliorent-ils la flexibilité du pipeline CI ?\n\nUn graphe acyclique orienté dans un pipeline CI permet d'exécuter des jobs en fonction de leurs dépendances, plutôt que dans un ordre strictement séquentiel. Ce graphe vous permet ainsi de définir un ordre d'exécution des jobs pour que ceux des étapes ultérieures commencent dès que les jobs des étapes précédentes se terminent. Cela réduit le temps d'exécution global du pipeline, améliore l'efficacité et laisse même à certains jobs la possibilité de se terminer plus tôt que s'ils avaient été exécutés dans un ordre purement séquentiel (du premier au dernier dans la liste).\n\n### Pourquoi est-il important de choisir la bonne image Docker pour les jobs d'un pipeline CI GitLab ?\n\nGitLab utilise des images Docker pour exécuter des jobs dont l'image par défaut est ruby 3.1. Pour optimiser votre pipeline CI, il sera cependant crucial de choisir l'image la plus appropriée à vos besoins. Comprenez que les jobs téléchargent d'abord l'image Docker spécifiée. Si l'image contient des paquets supplémentaires inutiles, cela augmentera les temps de téléchargement et d'exécution. Il est donc important de s'assurer que l'image choisie contient uniquement les paquets essentiels afin d'éviter des retards inutiles dans l'exécution des jobs.\n\n### Prochaines étapes\n\nPour moderniser davantage vos pratiques de développement logiciel, consultez le [catalogue GitLab CI/CD](https://docs.gitlab.com/ee/architecture/blueprints/ci_pipeline_components/) pour savoir comment standardiser et réutiliser les composants CI/CD.\n",[762,736],"2025-01-07",{"slug":962,"featured":6,"template":686},"basics-of-gitlab-ci-updated","content:fr-fr:blog:basics-of-gitlab-ci-updated.yml","Basics Of Gitlab Ci Updated","fr-fr/blog/basics-of-gitlab-ci-updated.yml","fr-fr/blog/basics-of-gitlab-ci-updated",{"_path":968,"_dir":249,"_draft":6,"_partial":6,"_locale":7,"seo":969,"content":975,"config":981,"_id":983,"_type":16,"title":984,"_source":18,"_file":985,"_stem":986,"_extension":21},"/fr-fr/blog/keep-git-history-clean-with-interactive-rebase",{"title":970,"description":971,"ogTitle":970,"ogDescription":971,"noIndex":6,"ogImage":972,"ogUrl":973,"ogSiteName":700,"ogType":701,"canonicalUrls":973,"schema":974},"Comment conserver un historique Git propre avec le rebase interactif","Le rebase interactif est l'un des outils les plus polyvalents de Git. Découvrez comment l'utiliser pour corriger vos messages de commit, réparer des erreurs et bien plus encore.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749662593/Blog/Hero%20Images/title-image.png","https://about.gitlab.com/blog/keep-git-history-clean-with-interactive-rebase","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Comment conserver un historique Git propre avec le rebase interactif\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Tobias Günther\"}],\n        \"datePublished\": \"2020-11-23\",\n      }",{"title":970,"description":971,"authors":976,"heroImage":972,"date":978,"body":979,"category":14,"tags":980},[977],"Tobias Günther","2020-11-23","## Qu'est-ce qu’un rebase interactif ?\n\nLe rebase interactif, également connu sous le nom de *Git rebase interactive* en anglais, est un peu le « couteau suisse » de [Git](https://about.gitlab.com/fr-fr/blog/what-is-git/ \"Qu'est-ce que Git ? \") car il permet d’avoir accès à différents outils pour de nombreux usages possibles. Son cas d'utilisation principal restant cependant le nettoyage de l'historique des commits locaux.\n\nSoulignons bien ici le mot *local*. Le rebase interactif s'utilise uniquement pour __nettoyer votre propre historique de commits en local__, avant par exemple d'intégrer l’une de vos branches de fonctionnalités au sein d’une branche d’équipe. \n\nEn revanche, le rebase interactif (ou *Git rebase interactive*) ne doit pas être utilisé sur un historique de commits Git dont le push a déjà été effectué et partagé sur un dépôt distant. Le rebase interactif est l’un de ces outils qui « réécrivent » l'historique Git ; il ne doit donc pas être utilisé sur des commits déjà partagés avec d'autres personnes. Passé ce petit avertissement, voyons quelques exemples pratiques !\n\n## Corriger un ancien message de commit avec le rebase interactif\n\nParfois, vous remarquez une coquille dans un vieux message de commit. Ou bien, vous oubliez de mentionner quelque chose d'utile dans une description. Si l'on parle du tout dernier commit en date, vous pouvez utiliser l'option `--amend` de la commande `git commit`. Mais pour les commits plus anciens, le *Git rebase interactive* vous permet de les modifier après coup. \n\nVoici un exemple de message de commit nécessitant une correction :\n\n![Un mauvais message de commit qui nécessite une correction](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/bad-commit-message@2x.png){: .shadow.medium.center}\n{: .note.text-center}\n\nLa première étape dans toute session de *Git rebase interactive* consiste à __déterminer quelle partie de l'historique des commits__ vous souhaitez manipuler. Pour modifier le commit incorrect dans l'exemple précédent, nous devons démarrer la session à partir de son commit parent.\n\n![Démarrage de la session de Git rebase interactive](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/start-at-parent-commit@2x.png){: .shadow.medium.center}\n{: .note.text-center}\n\nNous pouvons maintenant transmettre le hash du commit de départ à la commande *Git rebase interactive* :\n\n```\n$ git rebase -i 0023cddd\n```\n\nUne fenêtre d’édition va alors s'ouvrir, contenant la liste des commits que vous venez de sélectionner. Ne soyez pas surpris s’ils apparaissent dans l'ordre inverse. Dans une session de rebase interactif, Git applique les commits élément après élément, du plus ancien au plus récent, ce qui signifie que l'inversion de l'ordre est correcte du point de vue de Git.\n\n![Fenêtre d'édition avec les commits sélectionnés](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/editor-window-start-ir@2x.png){: .shadow.medium.center}\n{: .note.text-center}\n\nUne chose importante à noter à propos de cette fenêtre d’édition : ce n'est pas ici que vous effectuez les manipulations réelles ! Dans cet exemple concret, ce n’est pas à cet endroit que vous modifiez le message du commit. Vous indiquez seulement le commit que vous allez modifier en appliquant un mot-clé d'action. Dans notre cas, comme nous voulons changer le message d'un commit, nous entrons la ligne « reword ». Si vous sauvegardez et fermez la fenêtre d’édition, une nouvelle fenêtre s'ouvrira, contenant l'ancien message de commit. \n\nIl est temps d'effectuer vos modifications :\n\n![Modifications du message du commit](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/correct-commit-message.gif){: .shadow.medium.center}\n{: .note.text-center}\n\nAprès avoir sauvegardé et fermé la fenêtre une fois de plus, la session de *Git rebase interactive* est terminée et notre ancien message de commit a été corrigé.\n\n## Combiner plusieurs commits en un seul avec le rebase interactif\n\nAutre cas d'usage du *Git rebase interactive* : lorsque vous souhaitez __combiner plusieurs anciens commentaires en un seul__. Bien entendu, la règle d'or du [contrôle de version](https://about.gitlab.com/fr-fr/topics/version-control/ \"Qu'est-ce que le contrôle de version ?\") s'applique : il est généralement conseillé de créer plus de petits commits plutôt que quelques gros. Cependant, nous pouvons parfois nous laisser emporter, et vouloir ensuite fusionner quelques commits en un seul.\n\nPrenons un exemple concret, où nous allons entreprendre de combiner les commits suivants :\n\n![Combinaison de plusieurs commits en un seul](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/squash-selected-commits@2x.png){: .shadow.medium.center}\n{: .note.text-center}\n\nComme dans notre premier cas, nous commençons par démarrer la session de *Git rebase interactive* au niveau du commit parent de celui que nous voulons manipuler.\n\n```\n$ git rebase -i 2b504bee\n```\n\nUne fois encore, une fenêtre d'édition s'ouvre, listant la partie de notre historique de [commits Git](https://about.gitlab.com/fr-fr/blog/keeping-git-commit-history-clean/ \"Commits Git\") que nous souhaitons manipuler.\n\n![Marquage des lignes avec « squash » ](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/squash-mark-commit@2x.png){: .shadow.medium.center}\n{: .note.text-center}\n\n### Marquer les lignes avec le mot-clé « squash »\n\nLe mot-clé d’action que nous allons utiliser ici s'appelle « squash ». Pour bien utiliser cette fonction, retenez que la ligne marquée avec le mot-clé « squash » sera combinée avec la ligne directement au-dessus. Ainsi, comme le montre la capture d'écran ci-dessus, nous avons marqué la ligne #2 avec « squash » afin de la combiner avec le commit de la ligne #1 juste au-dessus.\n\nNous pouvons maintenant sauvegarder et fermer la fenêtre d’édition ; une nouvelle fenêtre va alors apparaître. Il nous est maintenant demandé de fournir un message de commit pour le nouveau commit créé en combinant ces deux anciens.\n\n![Ajout d’un nouveau message pour le nouveau commit fusionné](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/squash-enter-new-message@2x.png){: .shadow.medium.center}\n{: .note.text-center}\n\nEnfin, sauvegardez et fermez cette fenêtre d’édition. Un nouveau commit est créé, contenant les modifications des deux anciens commits. \n\n## Corriger une erreur avec le rebase interactif\n\nUn autre cas d’usage du *Git rebase interactive* consiste à corriger une erreur identifiée dans l'un de vos commits précédents. La nature exacte de l'erreur n'a pas d'importance. Vous pourriez par exemple avoir oublié d'ajouter un changement, de supprimer un fichier, ou simplement de corriger une faute de frappe.\n\nDans une telle situation, nous avons tendance à vouloir créer un nouveau commit pour corriger cette erreur. Cela risque toutefois d'ajouter du désordre à votre historique de commits. Il n'est pas idéal d'ajouter un commit de fortune au commit initial juste pour corriger quelques erreurs. Votre historique de commits deviendra rapidement illisible, car jonché de multiples petits commits de correction. \n\nC'est là que vous pouvez profiter de « fixup », l'un des outils fournis avec le *Git rebase interactive*. « Fixup » applique ce commit de réparation rapide et ses changements au commit initial, le corrigeant ainsi. Ensuite, il se débarrasse simplement du commit de fortune. \n\n![Fonctionnement de « fixup »](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/diagram-fixup.png){: .medium.center}\n{: .note.text-center}\n\n### Comment utiliser « fixup » ?\n\nUne fois la fonction « fixup » utilisée, c'est comme si notre commit initial avait toujours été correct. Voyons cela à l'aide d'un exemple. \n\nLa première étape consiste à faire le nécessaire pour corriger le problème. Il peut s'agir d'ajouter un nouveau fichier, de modifier des fichiers existants ou de supprimer ceux qui sont obsolètes. Vous avez simplement à effectuer les modifications qui corrigent l'erreur.\n\nL'étape suivante consiste à valider ces modifications au niveau du dépôt, mais avec un petit truc en plus. Au moment du commit, nous allons ajouter `--fixup` et indiquer à Git le hash de notre mauvais commit :\n\n```\n$ git add corrections.txt\n$ git commit --fixup 2b504bee\n```\n\nJetez maintenant un coup d'œil à votre historique de commits. Vous constaterez qu'un commit d'apparence ordinaire a été créé. Mais à y voir de plus près, il s'est passé quelque chose. Le nouveau commit affiche la mention « fixup ! » et il reprend le sujet de notre mauvais commit.\n\n![Le commit initial et le commit de correction](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/fixup_create-fix-commit@2x.png){: .shadow.medium.center}\n{: .note.text-center}\n\nEnfin, la troisième étape consiste à démarrer la session de *Git rebase interactive*. Nous sélectionnons à nouveau le commit parent de notre mauvais commit comme point de départ :\n\n```\n$ git rebase -i 0023cddd --autosquash\n```\n\nEt pour conclure, nous utilisons notre botte secrète : `--autosquash`. Cette option nous assure de ne rien avoir à faire au sein de la fenêtre d’édition désormais ouverte. Regardons de plus près la situation :\n\n![Notre commit de correction est marqué « fixup » et classé à la bonne position](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/fixup_editor@2x.png){: .shadow.medium.center}\n{: .note.text-center}\n\nGit a automatiquement effectué deux choses :\n\n1. Le commit de correction de fortune est marqué comme « fixup ». \n2. L'ordre des lignes fait apparaître notre commit de correction directement sous le mauvais commit. Tout comme « squash », « fixup » combine le commit avec celui de la ligne supérieure.\n\nEnfin, il ne nous reste plus qu'à sauvegarder et à fermer la fenêtre d’édition.\n\nJetons un coup d'œil à l'historique des commits :\n\n![Problème résolu](https://about.gitlab.com/images/blogimages/how-to-keep-your-git-history-clean-with-interactive-rebase/fixup_final-corrected@2x.png){: .shadow.medium.center}\n{: .note.text-center}\n\nAinsi, le mauvais commit initial contient maintenant les changements du commit de secours. Mais en plus de cela, le commit de secours a maintenant disparu de l’historique de commits. Tout beau, tout propre, comme s'il n'y avait jamais eu le moindre problème !\n\n## Découvrez la puissance du rebase interactif\n\nVous allez pouvoir utiliser le Git rebase interactive dans de très nombreux cas, la plupart du temps afin de corriger des erreurs. Pour une vue d'ensemble de toutes les choses utiles à faire avec le rebase interactif, nous vous recommandons ce [guide sur Git](https://git-scm.com/book/fr/v2/Utilitaires-Git-R%C3%A9%C3%A9crire-l%E2%80%99historique).\n\n## FAQ sur le rebase interactif\n\n### Quelle est la différence entre rebase et merge ?\n\nVoilà une question souvent posée par les développeurs : rebase ou merge ? Ces commandes permettent d'effectuer des changements d'une branche à l'autre. Avec `git merge`, nous créons un commit de merge dans la branche locale. Avec `git rebase`, chaque commit de la branche locale est recréé en pointe de la branche principale. `Git rebase -i` interactif est similaire à git rebase, mais permet en plus de modifier les commits au moment de les envoyer vers la branche principale.\n\n### Quelle est la différence entre le Git rebase interactive et le Git rebase ?\n\nLorsque l'on ajoute l'option interactive au Git rebase, cela permet d'ouvrir une fenêtre d’édition afin d'éditer en amont chaque commit de votre branche locale avant de les rebaser, notamment pour nettoyer votre historique. Les commandes principales sont `reword` (éditer un message de commit), `squash` (fusionner deux commits), et `fixup` (amender un commit).\n\n### Quelles sont les erreurs à éviter avec le rebase interactif ?\n\nLe rebase interactif est généralement conseillé aux utilisateurs plutôt avancés. Lorsque vous utilisez ces commandes, veillez à éviter les pièges suivants :\n\n- __Ordre des commits.__ Conservez la logique du workflow lorsque vous réordonnez des commits.\n- __Sauvegarde.__ N'oubliez pas de sauvegarder et fermer votre fenêtre d'édition en fin de session de rebase interactif.\n- __Rebasing sur la branche principale.__ Le rebase s'applique toujours à des commits de votre branche locale vers la branche publique. \n\nImage de couverture par David Taljat sur [Pexels](https://www.pexels.com/@david-taljat-3748658/).\n",[712,736],{"slug":982,"featured":6,"template":686},"keep-git-history-clean-with-interactive-rebase","content:fr-fr:blog:keep-git-history-clean-with-interactive-rebase.yml","Keep Git History Clean With Interactive Rebase","fr-fr/blog/keep-git-history-clean-with-interactive-rebase.yml","fr-fr/blog/keep-git-history-clean-with-interactive-rebase",{"_path":988,"_dir":249,"_draft":6,"_partial":6,"_locale":7,"seo":989,"content":995,"config":1006,"_id":1008,"_type":16,"title":1009,"_source":18,"_file":1010,"_stem":1011,"_extension":21},"/fr-fr/blog/using-ansible-and-gitlab-as-infrastructure-for-code",{"ogTitle":990,"schema":991,"ogImage":992,"ogDescription":993,"ogSiteName":700,"noIndex":6,"ogType":701,"ogUrl":994,"title":990,"canonicalUrls":994,"description":993},"Créez des pipelines IaC évolutifs avec GitLab","\n                        { \"@context\": \"https://schema.org\", \"@type\": \"Article\", \"headline\": \"How to use GitLab and Ansible to create infrastructure as code\", \"author\": [{\"@type\":\"Person\",\"name\":\"Brad Downey\"},{\"@type\":\"Person\",\"name\":\"Sara Kassabian\"}], \"datePublished\": \"2019-07-01\", }","https://res.cloudinary.com/about-gitlab-com/image/upload/f_auto,q_auto,w_820,h_500,c_lfill/v1746211002/zlet4rmfg2z0j6lg16mc.png","Automatisez la gestion de votre infrastructure avec des pipelines CI/CD sécurisés, un scan de sécurité intégré, à l’aide de GitLab, Terraform/OpenTofu, Ansible.","https://about.gitlab.com/blog/using-ansible-and-gitlab-as-infrastructure-for-code",{"heroImage":992,"body":996,"authors":997,"updatedDate":1000,"date":1001,"title":1002,"tags":1003,"description":1005,"category":14},"Les outils d'Infrastructure as Code (IaC), tels que TerraForm/OpenTofu, ou de gestion des configurations, tels qu'Ansible, jouent un rôle clé dans de nombreux workflows critiques. Ces projets commencent parfois par de simples scripts d'automatisations, sans nécessairement suivre les bonnes pratiques de développement logiciel ni répondre aux contrôles réglementaires exigés pour les applications logicielles d'entreprise.\n\nSouvent développées par des ingénieurs système ou des ingénieurs d'infrastructure, ces automatisations sont mises en place sans réelle expertise des approches [DevOps](https://about.gitlab.com/fr-fr/topics/devops/ \"Qu'est-ce que le DevOps ?\"), DevSecOps, [CI/CD](https://about.gitlab.com/topics/ci-cd/ \"Qu'est-ce que le CI/CD ?\") et d'automatisation des tests. Dans les grandes entreprises employant de nombreuses équipes d'ingénierie parfois cloisonnées, la situation est encore plus compliquée.\n\nChez GitLab, nous maîtrisons l'[approche DevSecOps](https://about.gitlab.com/fr-fr/topics/devsecops/ \"Qu'est-ce que le DevSecOps ?\") depuis plus de 10 ans et utilisons notre plateforme DevSecOps unifiée en interne pour automatiser des tâches critiques à l'échelle de l'entreprise. Nous accompagnons des milliers de clients qui s'appuient sur notre plateforme GitLab pour une variété de processus : Infrastructure as Code (IaC), automatisation, gestion cloud, [ingénierie de plateforme](https://about.gitlab.com/fr-fr/the-source/platform/driving-business-results-with-platform-engineering/ \"Qu'est-ce que l’ingénierie de plateforme ?\") et bien d'autres encore.\n\nDécouvrez dans cet article les principales fonctionnalités pour transformer vos puissantes automatisations en pipelines de livraison de logiciels évolutifs et auditables.\n\n![Liste d'automatisation](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750433380/oipm6tq8qutoh1ctredd.png)\n\n## Mise en œuvre\n\n[Ce projet de démonstration](https://gitlab.com/gl-demo-ultimate-saberkan/public/ansible-demo) illustre un workflow DevOps complet qui combine la puissance d'OpenTofu avec les pratiques modernes d'Ansible, le tout orchestré via les [pipelines CI/CD](https://about.gitlab.com/fr-fr/topics/ci-cd/cicd-pipeline/ \"Qu'est-ce qu'un pipeline CI/CD ?\") de GitLab. Il met en scène le provisionnement d'un environnement de test AWS à l'aide de composants OpenTofu intégrés à GitLab, suivi du déploiement d'un serveur web Tomcat à l'aide de la version la plus récente d'Ansible, avec exécution dans un environnement personnalisé et prise en charge des collections.\n\nLe projet tire parti de nombreuses fonctionnalités de GitLab :\n\n* Création et stockage d'environnements d'exécution Ansible personnalisés dans le [registre de conteneurs de GitLab](https://docs.gitlab.com/user/packages/container_registry/)\n* [Scan de sécurité des scripts d'IaC et des conteneurs permettant de détecter des vulnérabilités](https://docs.gitlab.com/user/application_security/iac_scanning/)\n* Intégration du [linting Ansible avec GitLab Code Quality](https://docs.gitlab.com/user/application_security/iac_scanning/)\n* Stockage des binaires Tomcat dans le [dépôt de paquets génériques](https://docs.gitlab.com/user/packages/generic_packages/)\n* Utilisation des [variables d'environnement CI/CD à des fins de configuration](https://docs.gitlab.com/ci/variables/)\n\nL'ensemble du workflow est automatisé par le biais d'un [pipeline GitLab](https://docs.gitlab.com/ci/pipelines/) qui gère toutes les étapes, du provisionnement de l'infrastructure au déploiement des applications, en passant par les tests de sécurité.\n\n![ Workflow automatisé via un pipeline GitLab ](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750433380/giatmolwn9inusi4cev2.png)\n\n### Provisionnement de l'environnement avec OpenTofu\n\nLe projet commence par le provisionnement d'un environnement de test AWS à l'aide d'OpenTofu, en s'appuyant sur l'intégration native des [composants OpenTofu de GitLab](https://docs.gitlab.com/user/infrastructure/iac/), qui rationalisent le processus de provisionnement de l'infrastructure. Le pipeline inclut des étapes de validation, de planification et d'application qui garantissent un déploiement approprié de l'infrastructure tout en maintenant les bonnes pratiques IaC de GitLab.\n\nCe projet tire parti des capacités de l'[outil de gestion des fichiers d'état de Terraform intégré à GitLab](https://docs.gitlab.com/user/infrastructure/iac/terraform_state/) ainsi que du [Terraform Module Registry](https://docs.gitlab.com/user/packages/terraform_module_registry/), tous deux compatibles avec OpenTofu et HashiCorp Terraform. Il est également possible d'utiliser les composants OpenTofu de GitLab avec HashiCorp Terraform en procédant à une [légère personnalisation](https://gitlab.com/components/opentofu#can-i-use-this-component-with-terraform) : vous devez créer votre propre image incluant un script nommé `gitlab-tofu` pour maintenir sa compatibilité avec les jobs de composants. Vous pouvez ensuite remplacer les commandes `tofu` par les commandes `Terraform` équivalentes.\n\nL'exemple de composant « OpenTofu Module Release » montre comment créer un module Terraform et le stocker dans Terraform Module Registry dans GitLab. Ce module est ensuite importé dans le fichier `provision_lab.tf` directement depuis GitLab pour déployer l'environnement de test sur AWS. Ensuite, il génère un fichier d'inventaire contenant l'adresse IP publique de l'instance provisionnée, qui peut être utilisée dans les étapes de gestion des configurations avec Ansible.\n\n```\n# From .gitlab-ci.yml\n - component: gitlab.com/components/opentofu/module-release@1.1.0\n   inputs:\n     root_dir: tofu\n     as: 🔍 tofu-module-release\n     stage: 🏗️ build-tofu-module\n     module_version: 0.0.1\n     module_system: aws\n     module_name: aws-lab\n     root_dir: tofu/modules/ansible-demo/aws-lab\n     rules:\n       - if: \"$CI_COMMIT_BRANCH\"\n         when: manual\n```\n\n```\n# From provision_lab.tf\nmodule \"aws-lab\" {\n  source = \"https://gitlab.com/api/v4/projects/67604719/packages/terraform/modules/aws-lab/aws/0.0.1\"\n}\n```\n\nLes composants de validation, de planification et de déploiement sont configurés avec le paramètre `**auto_define_backend: true**`. Ils s'intègrent automatiquement au backend de stockage d’état Terraform intégré à GitLab et éliminent le besoin de configuration manuelle du backend ou de solutions de stockage d'état externes telles que des compartiments S3.\n\n```\n# From gitlab-ci.yml\n- component: gitlab.com/components/opentofu/apply@0.55.0\n  inputs:\n    version: 0.55.0\n    opentofu_version: 1.8.8\n    root_dir: tofu\n    state_name: demo\n    as: ✅ tofu-apply\n    stage: 🏗️ provision-lab\n    auto_define_backend: true\n    rules:\n      - if: \"$CI_COMMIT_BRANCH\"\n        when: manual\n```\n\n![Les composants de validation, de planification et de déploiement sont configurés avec le paramètre `auto_define_backend: true`](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750433380/giatmolwn9inusi4cev2.png)\n\nLa configuration de l'infrastructure crée une instance EC2 CentOS Stream 9 avec des groupes de sécurité appropriés pour autoriser l'accès SSH depuis les runners GitLab et l'accès HTTP au serveur Tomcat.\n\nL'accès SSH et la configuration HTTP sont configurés par le biais des [variables d'environnement GitLab CI/CD](https://docs.gitlab.com/ci/variables/#define-a-cicd-variable-in-the-ui).\n\n![Accès SSH et configuration HTTP](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750433381/cmqtzg6ahz8ua5w8ybgs.png)\n\nPour un accès sécurisé au cloud, le projet met en œuvre [l'intégration OpenID Connect de GitLab](https://docs.gitlab.com/ci/cloud_services/aws/) avec AWS, en utilisant des identifiants de connexion temporaires via AWS Security Token Service (STS) :\n\n```\n# From .gitlab-ci.yml\n.tofu_aws_setup:\n id_tokens:\n   OIDC_TOKEN:\n     aud: https://gitlab.com\n before_script:\n   - echo \"${OIDC_TOKEN}\" > /tmp/web_identity_token\n   - export AWS_PROFILE=\"\"\n   - export AWS_ROLE_ARN=\"${AWS_ROLE_ARN}\"\n   - export AWS_WEB_IDENTITY_TOKEN_FILE=\"/tmp/web_identity_token\"\n```\n\n### Création de l'environnement d'exécution Ansible\n\nLes déploiements modernes avec Ansible reposent largement sur l'utilisation d'[environnements d'exécution](https://docs.ansible.com/ansible/latest/getting_started_ee/index.html) : il s'agit de versions conteneurisées qui encapsulent Ansible avec toutes ses dépendances, y compris les rôles et les collections préinstallés nécessaires. Dans ce projet, un environnement d'exécution personnalisé est créé, basé sur Fedora 39, qui inclut ansible-core, ansible-runner ainsi que des collections spécifiques, telle que ansible.posix, requise dans cet exemple pour configurer le pare-feu et SELinux.\n\nLes rôles et collections tiers de ce projet sont téléchargés en mode natif à partir du dépôt communautaire Ansible Galaxy. Cette approche s'appuie sur l'écosystème de contenu Ansible réutilisable de la communauté, comme le montre la configuration de l'environnement d'exécution. Bien que cette démonstration utilise des ressources Ansible de la communauté, cette mise en œuvre de pipeline est entièrement compatible avec Red Hat Ansible Automation Platform. La structure du pipeline reste identique ; seules les sources de contenu changent. Ainsi, les entreprises qui utilisent la version Enterprise peuvent simplement rediriger leurs sources de contenu d'automatisation vers leur Automation Hub privé au lieu du dépôt Ansible Galaxy par défaut issu de la communauté. Selon la documentation officielle d'Ansible, vous pouvez réaliser cette opération en [configurant votre serveur Automation Hub privé et votre token d'accès dans le fichier ansible.cfg](https://docs.redhat.com/en/documentation/red_hat_ansible_automation_platform/1.2/html/getting_started_with_red_hat_ansible_automation_hub/proc-configure-automation-hub-server#proc-configure-automation-hub-server).\n\n```\n# From execution-environment.yml\n---\nversion: 3\n\nimages:\n  base_image:\n    name: quay.io/fedora/fedora:39\n\ndependencies:\n  ansible_core:\n    package_pip: ansible-core\n  ansible_runner:\n    package_pip: ansible-runner\n  system:\n    - openssh-clients\n    - sshpass\n  galaxy:\n    collections:\n    - name: ansible.posix\n      version: \">=2.0.0\"\n```\n\n![Environnement d'exécution faisant l'objet d'un push vers le registre de conteneurs de GitLab ](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750433384/dh1o2ojjmb04ru4tfr9k.png)\n\nL'environnement d'exécution est défini dans un fichier YAML, généré à l'aide d'ansible-builder, puis faisant l'objet d'un push vers le [registre de conteneurs de GitLab](https://docs.gitlab.com/user/packages/container_registry/). Cette approche garantit des environnements d'exécution cohérents d'un système à l'autre, tout en simplifiant la gestion des dépendances.\n\n```\n# From gitlab-ci.yml\n🔨 ansible-build-ee:\n  stage: 📦 ansible-build-ee\n  image: docker:24.0.5\n  needs: []\n  services:\n    - docker:24.0.5-dind\n  before_script:\n    - apk add --no-cache python3 py3-pip\n    - pip install ansible-builder\n    - cd ansible/execution-environment\n  script:\n    - ansible-builder build -t ${EE_IMAGE_NAME}:${EE_IMAGE_TAG} --container-runtime docker\n    - docker tag ${EE_IMAGE_NAME}:${EE_IMAGE_TAG} ${CI_REGISTRY_IMAGE}/${EE_IMAGE_NAME}:${EE_IMAGE_TAG}\n    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY\n    - docker push ${CI_REGISTRY_IMAGE}/${EE_IMAGE_NAME}:${EE_IMAGE_TAG}\n```\n\n### Déploiement de Tomcat avec Ansible\n\nUne fois l'infrastructure provisionnée et l'environnement d'exécution construit, le pipeline déploie Tomcat à l'aide d'[Ansible Navigator](https://ansible.readthedocs.io/projects/navigator/). L'environnement d'exécution créé à l'étape précédente est utilisé comme image pour le job de déploiement dans le pipeline GitLab.\n\n```\n# From gitlab-ci.yml\n🚀 ansible-deploy:\n  stage: 🚀 ansible-deploy\n  image: ${CI_REGISTRY_IMAGE}/${EE_IMAGE_NAME}:${EE_IMAGE_TAG}\n  needs:\n    - ✅ tofu-apply\n  extends: [.ssh_private_key_setup, .default_rules]\n  script:\n    - ansible-navigator run ansible/playbook.yml \n      -i ansible/inventory/hosts.ini\n      --execution-environment false\n      --mode stdout \n      --log-level debug\n```\n\nCe processus récupère le paquet applicatif depuis le [dépôt de paquets générique de GitLab](https://docs.gitlab.com/user/packages/generic_packages/), configure les utilisateurs et les autorisations système, et définit Tomcat comme service systemd.\n\n```\n# From playbook.yml\n---\n- name: Deploy Tomcat Server\n  hosts: all\n  become: true\n  roles:\n      - role: tomcat\n  \n  vars:\n    # Tomcat package and installation\n    tomcat_package: \"https://gitlab.com/api/v4/projects/67604719/packages/generic/apache-tomcat/10.1.39/apache-tomcat-10.1.39.tar.gz\"\n    tomcat_install_dir: \"/opt/tomcat\"\n    java_package: \"java-17-openjdk-devel\"\n```\n\n![Registre de paquets de GitLab](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750433381/mynak8i2k7ms9vhdijqg.png)\n\n### Scan de sécurité et qualité du code\n\nLa sécurité est intégrée tout au long du pipeline avec plusieurs outils de scan. Ce projet utilise le [scanner SAST IaC intégré de GitLab](https://docs.gitlab.com/user/application_security/iac_scanning/) pour détecter les vulnérabilités dans le code Terraform et Ansible. L'[analyse des conteneurs](https://docs.gitlab.com/user/application_security/container_scanning/) est appliquée à l'image de l'environnement d'exécution pour identifier tout problème de sécurité et générer une [nomenclature logicielle (SBOM)](https://about.gitlab.com/fr-fr/blog/the-ultimate-guide-to-sboms/ \"Qu'est-ce qu'une nomenclature logicielle ?\").\n\n```\n# From gitlab-ci.yml\ninclude: \n- template: Jobs/SAST-IaC.gitlab-ci.yml \n- template: Jobs/Container-Scanning.gitlab-ci.yml\n```\n\n![La sécurité est intégrée à chaque étape du pipeline avec plusieurs outils de scanning](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750433386/e6ejckcv5kdyhhosej2f.png)\n\nDe plus, le projet utilise Ansible Linter et ses résultats sont intégrés à [GitLab Code Quality](https://docs.gitlab.com/ci/testing/code_quality/#import-code-quality-results-from-a-cicd-job). Cette intégration produit des rapports qui sont affichés directement dans l'interface de GitLab, ce qui facilite l'identification et la résolution des anomalies.\n\n```\n# From gitlab-ci.yml\n🔍 ansible-lint:\n  stage: 🚀 ansible-deploy\n  image: ${CI_REGISTRY_IMAGE}/${EE_IMAGE_NAME}:${EE_IMAGE_TAG}\n  needs: []\n  script:\n    - ansible-lint ansible/playbook.yml -f codeclimate | python3 -m json.tool | tee gl-code-quality-report.json || true\n  artifacts:\n    reports:\n      codequality:\n        - gl-code-quality-report.json\n```\n\n![Le projet utilise Ansible Linter et ses résultats sont intégrés à GitLab Code Quality](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750433380/gsfpaldra4rmtkseaudo.png)\n\n### Vérification de l'état du déploiement\n\nAprès le déploiement, le pipeline effectue des vérifications de l'état pour s'assurer que le serveur Tomcat fonctionne correctement. Ce job tente d'établir une connexion au port HTTP du serveur et vérifie qu'il renvoie une réponse confirmant que le service est bien actif. Cette étape garantit que le déploiement s'est correctement terminé et que l'application est accessible.\n\nVous pouvez également tester l'accès de votre navigateur à l'instance provisionnée par Tomcat en utilisant l'adresse IP publique de l'instance provisionnée EC2.\n\n![Vérification de l'état d'un job](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750433385/uksdkjryydxhu94v1naj.png)\n\n## Destruction de l'environnement de test\n\nDernière étape du pipeline : le processus de nettoyage détruit l'environnement de test. Cette opération est mise en œuvre à l'aide du composant de destruction OpenTofu, qui garantit que toutes les ressources créées au cours de l'étape de provisionnement sont correctement supprimées.\n\n## Récapitulatif\n\nGitLab offre une plateforme DevSecOps unifiée et un framework pour gérer, à l'échelle de l'entreprise, les pratiques d'automatisation critiques telles que la gestion des configurations et de l'IaC (Infrastructure as Code). Ce framework inclut le [contrôle de version](https://about.gitlab.com/fr-fr/topics/version-control/ \"Qu'est-ce que le contrôle de version ?\"), la planification de projet, la gestion des tickets, la collaboration entre les équipes, les pipelines CI/CD, la gestion du paquet de binaires et du registre de conteneurs, le scan de sécurité et de nombreuses autres fonctionnalités utiles. Il permet également de renforcer la gouvernance grâce à des contrôles intégrés dans les processus. Si vous cherchez à développer vos pratiques cloud (qu’il s’agisse d’un cloud privé ou public) ou plus généralement, de tout workflow d'automatisation en libre-service doté de règles de gouvernance, envisagez d'utiliser GitLab, TerraForm et Ansible comme les trois piliers d'une plateforme d'automatisation à la fois évolutive et conforme aux exigences de gouvernance.\n\n> Lancez-vous avec un [essai gratuit de 60 jours de GitLab Ultimate](http://bout.gitlab.com/free-trial/). Inscrivez-vous dès aujourd'hui !",[998,999],"George Kichukov","Salahddine Aberkan","2025-07-17","2019-07-01","GitLab DevSecOps : des pipelines IaC au service de votre croissance",[1004,111],"demo","Découvrez comment automatiser la gestion de votre infrastructure pour accompagner la croissance de votre entreprise grâce à des pipelines CI/CD sécurisés et un scan de sécurité intégré, à l'aide de GitLab, Terraform/OpenTofu et Ansible.",{"slug":1007,"featured":6,"template":686},"using-ansible-and-gitlab-as-infrastructure-for-code","content:fr-fr:blog:using-ansible-and-gitlab-as-infrastructure-for-code.yml","Using Ansible And Gitlab As Infrastructure For Code","fr-fr/blog/using-ansible-and-gitlab-as-infrastructure-for-code.yml","fr-fr/blog/using-ansible-and-gitlab-as-infrastructure-for-code",{"_path":1013,"_dir":249,"_draft":6,"_partial":6,"_locale":7,"seo":1014,"content":1020,"config":1027,"_id":1029,"_type":16,"title":1030,"_source":18,"_file":1031,"_stem":1032,"_extension":21},"/fr-fr/blog/keeping-git-commit-history-clean",{"title":1015,"description":1016,"ogTitle":1015,"ogDescription":1016,"noIndex":6,"ogImage":1017,"ogUrl":1018,"ogSiteName":700,"ogType":701,"canonicalUrls":1018,"schema":1019},"Commits Git : comment et pourquoi maintenir un historique propre","L’historique des commits Git peut rapidement devenir désorganisé. Dans cet article, vous découvrirez tous nos conseils pour y remédier.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659457/Blog/Hero%20Images/keep-git-commit-history-clean.jpg","https://about.gitlab.com/blog/keeping-git-commit-history-clean","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Commits Git : comment et pourquoi maintenir un historique propre\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Kushal Pandya\"}],\n        \"datePublished\": \"2018-06-07\",\n      }",{"title":1015,"description":1016,"authors":1021,"heroImage":1017,"date":1023,"body":1024,"category":14,"tags":1025,"updatedDate":1026},[1022],"Kushal Pandya","2018-06-07","Les commits Git sont des éléments fondamentaux d’un [dépôt Git](https://git-scm.com/book/fr/v2/Les-bases-de-Git-D%C3%A9marrer-un-d%C3%A9p%C3%B4t-Git \"Dépôt Git\") (Git Repository), sans oublier les messages de commit qui constituent un véritable journal de bord pour le dépôt. Au fur et à mesure que le projet ou le dépôt évolue dans le temps (avec l’ajout de nouvelles fonctionnalités, la correction de bugs, la refonte de l’architecture), les messages de commit permettent de suivre et de comprendre les modifications apportées. Ces messages doivent donc résumer de manière courte et précise les changements effectués.\n\n## Qu’est-ce qu’un commit Git ?\n\nLes messages de commit Git sont les empreintes laissées sur le code que vous modifiez. Lorsque vous consultez votre code un an plus tard, avoir rédigé un message clair vous aide à comprendre plus facilement et rapidement les raisons derrière vos choix de développement. De plus, ces messages facilitent la collaboration avec vos collègues. Avec des commits Git isolés en fonction du contexte, il est plus rapide pour les développeurs et développeuses de détecter un bug introduit par un seul commit et d’y revenir dessus. \n\nDans le cadre de projets d’envergure, où de nombreuses parties sont ajoutées, modifiées ou supprimées constamment, s’assurer que les messages de commit soient correctement maintenus peut parfois être une tâche compliquée, particulièrement sur les projets qui s’étendent sur plusieurs semaines ou plusieurs mois. \n\nPour vous aider à maintenir un historique de commits Git précis, découvrez dans cet article un certain nombre de situations auxquelles les développeurs et développeuses peuvent être confrontés au quotidien : \n\n- Situation 1 : Je dois modifier le commit le plus récent\n- Situation 2 : Je dois modifier un commit Git spécifique\n- Situation 3 : Je dois ajouter, combiner ou supprimer un commit Git \n- Situation 4 : Mon historique de commits Git est incohérent, je veux repartir à zéro\n\n__Remarque :__ cet article suppose que vous ayez déjà des connaissances sur les fondamentaux de Git comme le fonctionnement des branches, l’ajout de modifications non validées d’une branche à l'étape du staging et la validation des modifications. Vous souhaitez en savoir plus sur ces éléments ? Consultez notre [documentation](https://docs.gitlab.com/ee/topics/git/index.html \"Documentation GitLab sur Git\") avant de continuer la lecture de cet article. \n\nAvant d’entrer dans le vif du sujet, regardons brièvement à quoi ressemble un workflow de développement dans le cadre d’un projet Ruby on Rails hypothétique. \n\n## Exemple de commit Git\n\nDans cet exemple, nous avons besoin d’ajouter une vue de navigation sur la page d’accueil, ce qui implique la mise à jour et l’ajout de nombreux fichiers. \n\nVoici le déroulement de l’ensemble du processus étape par étape : \n\n- Vous commencez à travailler sur une fonctionnalité avec la mise à jour d’un fichier que nous appelons `application_controller.rb`\n\n- Cette fonctionnalité requiert la mise à jour d’une vue : `index.html.haml`\n\n- Vous avez ajouté un partiel utilisé dans la page d’index : `_navigation.html.haml`\n\n- Les styles de la page doivent également être mis à jour pour refléter le partiel ajouté : `styles.css.scss`\n\n- La fonctionnalité est maintenant prête avec les modifications souhaitées, il est temps de mettre à jour les tests. Les fichiers à mettre à jour sont : \n  - `application_controller_spec.rb`\n  - `navigation_spec.rb`\n\n- Les tests sont mis à jour et fonctionnent comme prévu. Désormais, il est temps de valider les changements.\n\nPuisque tous les fichiers appartiennent à différentes parties de l’architecture, nous validons les modifications de manière isolée les unes des autres afin d’assurer que chaque commit représente un certain contexte et soit dans le bon ordre. Les changements des commits Git s’ordonnent généralement comme suit : en commençant par le backend, suivi de la couche intermédiaire puis du frontend.\n\n1. `application_controller.rb` & `application_controller_spec.rb` ; __Add routes for navigation__.\n2. `_navigation.html.haml` & `navigation_spec.rb` ; __Page Navigation View__.\n3. `index.html.haml` ; __Render navigation partial__.\n4. `styles.css.scss` ; __Add styles for navigation__.\n\nMaintenant que nos changements sont validés, il est possible de créer une merge request (requête de fusion) avec la branche. Une fois la merge request ouverte, celle-ci est généralement examinée par un pair avant que les changements ne soient fusionnés dans la branche principale du dépôt Git. Maintenant, observons les différentes situations dans lesquelles vous pouvez vous trouver lors de la révision du code. \n\n## Situation 1 : comment modifier le commit Git le plus récent ?\n\nImaginez que le relecteur examine le fichier `styles.css.scss` et suggère une modification. Dans ce cas, il est très simple d’effectuer cette modification car les changements de la feuille de style font partie du dernier commit sur votre branche. \n\nVoici comment s’y prendre : \n\n- Vous effectuez directement les changements nécessaires dans `styles.css.scss` dans votre branche actuelle. \n\n- Une fois les changements effectués, ajoutez ces modifications au staging; exécutez `git add styles.css.scss`. \n\n- Dès que les changements sont pris en compte, ajoutez-les à votre dernier commit; exécutez la commande `git commit --amend`.\n  - Explication de la commande : Ici, nous demandons à la commande `git commit` d’inclure tout ce qui est présent dans le staging au commit le plus récent.\n\n- Cela ouvrira votre dernier commit dans l’éditeur de texte défini par Git contenant le message de commit « __Add styles for navigation__ ». \n\n- Comme nous avons seulement mis à jour la déclaration CSS, nous n’avons pas besoin de modifier le message de commit. À ce stade, vous pouvez simplement enregistrer et quitter l’éditeur de texte que Git a ouvert et vos changements apparaîtront dans le commit. \n\nPuisque vous avez modifié un commit Git existant, vous devez pousser ces changements vers le dépôt distant (« remote repository ») grâce à la commande : `git push --force-with-lease \u003Cremote_name> \u003Cbranch_name>`. Celle-ci va remplacer le commit `Add styles for navigation` sur le dépôt distant, par le commit mis à jour à l’instant dans notre dépôt local.\n\nGardez en tête que lorsque vous travaillez à plusieurs sur la même branche, le fait de pousser un commit de force peut causer des problèmes pour les autres utilisateurs. En effet, ces derniers peuvent rencontrer des difficultés au moment de pousser normalement leurs changements sur une branche distante contenant de nouveaux commits poussés de force. Par conséquent, utilisez cette fonctionnalité avec prudence. Apprenez-en davantage sur les [Git Push](https://git-scm.com/docs/git-push/fr \"Git Push\") dans la documentation de Git. \n\n## Situation 2 : comment modifier les changements d’un commit Git spécifique ?\n\nDans l’exemple précédent, le changement du commit Git était plutôt simple car vous deviez seulement modifier le dernier commit Git. Maintenant, imaginons que le relecteur avait suggéré de modifier un élément dans `_navigation.html.haml`. Dans cette situation, la modification doit se faire au niveau du deuxième commit en partant du haut. Il est donc nécessaire d’employer une autre méthode pour le changer. \n\nChaque fois qu’un commit est effectué dans une branche, il est identifié par une chaîne de caractères représentant un hachage SHA-1. Cet identifiant unique permet de distinguer un commit d’un autre. Vous pouvez voir tous les commits précédents, ainsi que leurs hachages SHA-1 dans une branche en exécutant la commande `git log`. \n\nVous obtiendrez alors un résultat qui ressemble à peu près à une liste où les commits les plus récents sont en haut :\n\n```\ncommit aa0a35a867ed2094da60042062e8f3d6000e3952 (HEAD -> add-page-navigation)\nAuthor: Kushal Pandya \u003Ckushal@gitlab.com>\nDate: Wed May 2 15:24:02 2024 +0530\n\n    Add styles for navigation\n\ncommit c22a3fa0c5cdc175f2b8232b9704079d27c619d0\nAuthor: Kushal Pandya \u003Ckushal@gitlab.com>\nDate: Wed May 2 08:42:52 2024 +0000\n\n    Render navigation partial\n\ncommit 4155df1cdc7be01c98b0773497ff65c22ba1549f\nAuthor: Kushal Pandya \u003Ckushal@gitlab.com>\nDate: Wed May 2 08:42:51 2024 +0000\n\n    Page Navigation View\n\ncommit 8d74af102941aa0b51e1a35b8ad731284e4b5a20\nAuthor: Kushal Pandya \u003Ckushal@gitlab.com>\nDate: Wed May 2 08:12:20 2024 +0000\n\n    Add routes for navigation\n```\n\nC’est ici que la commande `git rebase` entre en jeu. Chaque fois que vous souhaitez modifier un commit spécifique avec la commande `git rebase`, vous devez d’abord rebaser votre branche en déplaçant le HEAD juste avant le commit que vous souhaitez modifier. Dans le cas présent, nous devons changer le commit `Page Navigation View`.\n\n![Commit Log](https://about.gitlab.com/images/blogimages/keeping-git-commit-history-clean/GitRebase.png){: .shadow.center.medium}\n\nNotez ici le hachage du commit qui se trouve juste avant celui que nous souhaitons modifier. \n\nCopiez le hachage et effectuez les étapes suivantes : \n\n- Rebasez la branche pour vous positionner sur le commit précédant votre commit cible. Exécutez `git rebase -i 8d74af102941aa0b51e1a35b8ad731284e4b5a20`.\n  - Explication de la commande Git : ici, vous exécutez la commande `rebase` de Git en mode interactif avec le hachage SHA-1 comme commit sur lequel se rebaser.\n- Votre éditeur de texte s’ouvre et affiche tous vos commits effectués après le commit sur lequel vous vous rebasez. \n\nCe qui va correspondre à : \n\n```\npick 4155df1cdc7 Page Navigation View\npick c22a3fa0c5c Render navigation partial\npick aa0a35a867e Add styles for navigation\n\n# Rebase 8d74af10294..aa0a35a867e onto 8d74af10294 (3 commands)\n#\n# Commands:\n# p, pick = use commit\n# r, reword = use commit, but edit the commit message\n# e, edit = use commit, but stop for amending\n# s, squash = use commit, but meld into previous commit\n# f, fixup = like \"squash\", but discard this commit's log message\n# x, exec = run command (the rest of the line) using shell\n# d, drop = remove Git commit\n#\n# These lines can be re-ordered; they are executed from top to bottom.\n#\n# If you remove a line here THAT COMMIT WILL BE LOST.\n#\n# However, if you remove everything, the rebase will be aborted.\n#\n# Note that empty commits are commented out\n```\nChaque commit est précédé du mot `pick`. Ci-dessous, vous retrouverez tous les mots-clés disponibles. Pour éditer un commit, vous devez changer `pick 4155df1cdc7 Page Navigation View` en `edit 4155df1cdc7 Page Navigation View`. Sauvegardez les changements et quittez l’éditeur. \n\nVotre branche est désormais rebasée à l’endroit précédent le commit qui incluait `_navigation.html.haml`. Ouvrez le fichier et effectuez les modifications souhaitées selon les retours de vos pairs. Une fois les changements terminés, intégrez-les en exécutant `git add _navigation.html.haml`.\n\nMaintenant que les changements sont intégrés, il est temps de ramener la branche HEAD au commit initial (en incluant les modifications apportées). Exécutez `git rebase -–continue`. \n\nVotre éditeur par défaut s’ouvrira dans le terminal et affichera le message de commit modifié lors du rebasage : `Page Navigation View`. Vous pouvez modifier ce message si vous le souhaitez. Néanmoins, il est préférable de le laisser tel quel. Enregistrez et quittez l’éditeur. \n\nÀ ce stade, Git réexécutera tous les commits qui ont suivi après le commit que vous venez de modifier et maintenant la branche HEAD est de retour au commit supérieur que vous aviez initialement. Il inclut également les nouveaux changements que vous avez apportés à l’un des commits. \n\nPuisque vous avez modifié un commit déjà présent dans le dépôt distant, vous devez à nouveau pousser de force cette branche en exécutant : `git push --force-with-lease \u003Cremote_name> \u003Cbranch_name>`.\n\n## Situation 3 : comment ajouter, combiner ou supprimer des commits Git ?\n\nIl arrive régulièrement que l'on ajoute plusieurs commits pour corriger des éléments déjà validés. Il est possible de les réduire tout en les combinant avec les commits initiaux. \n\nPour cela, commencez le rebase interactif comme vous le feriez dans d’autres scénarios : \n\n```\npick 4155df1cdc7 Page Navigation View\npick c22a3fa0c5c Render navigation partial\npick aa0a35a867e Add styles for navigation\npick 62e858a322 Fix a typo\npick 5c25eb48c8 Ops another fix\npick 7f0718efe9 Fix 2\npick f0ffc19ef7 Argh Another fix!\n```\n\nSi vous souhaitez combiner toutes ces modifications dans `c22a3fa0c5c Render navigation partial`, vous devez : \n\n- Déplacer les corrections afin de les placer juste en-dessous du commit que vous désirez garder à la fin.\n\n- Changer `pick` en `squash` ou `fixup` pour chacune des modifications. \n\n*Remarque:* `squash` conserve les messages de commit des corrections dans la description. `Fixup` oublie les messages de commit des corrections et conserve l’original. \n\nVous obtenez donc : \n\n```\npick 4155df1cdc7 Page Navigation View\npick c22a3fa0c5c Render navigation partial\nfixup 62e858a322 Fix a typo\nfixup 5c25eb48c8 Ops another fix\nfixup 7f0718efe9 Fix 2\nfixup f0ffc19ef7 Argh Another fix!\npick aa0a35a867e Add styles for navigation\n```\n\nEnregistrez les changements et quittez l’éditeur. Voici le résultat : \n\n```\npick 4155df1cdc7 Page Navigation View\npick 96373c0bcf Render navigation partial\npick aa0a35a867e Add styles for navigation\n```\n\nComme précédemment, vous avez juste besoin d’exécuter `git push --force-with-lease \u003Cremote_name> \u003Cbranch_name>` et les changements sont appliqués.\n\nSi vous souhaitez supprimer un commit Git de la branche, utilisez plutôt la commande `drop` ou effacez la ligne. Nous conseillons d’éviter les commandes `squash` et `fixup` pour cela.\n\n### Comment éviter les conflits entre commits ?\n\nPour éviter tout conflit, assurez-vous que les commits que vous faites remonter n’impactent pas de fichiers modifiés par des commits suivants.\n\n```\npick 4155df1cdc7 Page Navigation View\npick c22a3fa0c5c Render navigation partial\nfixup 62e858a322 Fix a typo                 # this changes styles.css\nfixup 5c25eb48c8 Ops another fix            # this changes image/logo.svg\nfixup 7f0718efe9 Fix 2                      # this changes styles.css\nfixup f0ffc19ef7 Argh Another fix!          # this changes styles.css\npick aa0a35a867e Add styles for navigation  # this changes index.html (no conflict)\n```\n\n## Situation 4 : mon historique de commits Git est incohérent, comment repartir à zéro ?\n\nPour une fonctionnalité importante, il est courant d'avoir plusieurs corrections et révisions fréquemment validées. Au lieu de rebaser constamment la branche, vous pouvez retarder le nettoyage des commits jusqu'à la fin du développement. \n\nC'est là que la création de fichiers patch s’avère très utile. En fait, les fichiers patch étaient le moyen principal de partager du code par e-mail lors de la collaboration sur de grands projets open source avant que des services basés sur Git comme GitLab ne soient disponibles pour les développeurs et les développeuses. \n\nImaginez que vous avez une branche (par exemple `add-page-navigation`) où il y a des tonnes de commits qui ne transmettent pas clairement les changements sous-jacents. Voici comment vous pouvez créer un fichier patch pour tous les changements apportés dans cette branche :\n\n- La première étape pour créer ce fichier patch est de s’assurer que votre branche possède bien tous les changements présents dans la branche `master` et n’a pas de conflits avec celle-ci. \n\n- Vous pouvez exécuter `git rebase master` ou `git merge master` pendant que vous êtes dans la branche `add-page-navigation` pour obtenir tous les changements de la branche master sur votre branche. \n\n- Maintenant, créez le fichier patch. Pour ce faire, exécutez `git diff master add-page-navigation > ~/add_page_navigation.patch`.\n  - Explication de la commande : nous utilisons la fonctionnalité diff de Git. Nous demandons une diff entre la branche `master` et la branche `add-page-navigation`. Nous redirigeons le résultat (via le symbole `>`) vers un fichier nommé `add_page_navigation.patch` dans notre répertoire personnel (typiquement `~/` dans les systèmes d'exploitation *nix).\n\n- Vous pouvez spécifier n'importe quel chemin où vous souhaitez conserver ce fichier et choisir le nom et l’extension de ce fichier selon vos envies.\n\n- Une fois que la commande est exécutée et que vous ne voyez aucune erreur, votre fichier patch a bien été généré.\n\n- Maintenant, vérifiez la branche `master`. Exécutez `git checkout master`.\n\n- Supprimez la branche `add-page-navigation` du dépôt local. Exécutez `git branch -D add-page-navigation`. Souvenez-vous que nous avons déjà effectué les modifications sur cette branche avec la création d’un fichier patch. \n\n- Créez une nouvelle branche avec le même nom (pendant que la branche `master` est sélectionnée). Exécutez `git checkout -b add-page-navigation`.\n\n- À ce stade, c'est une nouvelle branche qui n'a aucun de vos changements.\n\n- Enfin, appliquez vos changements à partir du fichier patch `git apply ~/add_page_navigation.patch`.\n\n- Tous vos changements sont appliqués dans une branche et ils apparaîtront comme non validés, comme si toutes vos modifications avaient été faites, mais aucune d’entre elles n'avait été validées dans la branche.\n\n- Vous pouvez maintenant valider des fichiers individuels ou des fichiers groupés par zone d'impact dans l'ordre que vous souhaitez, avec de courts messages de commit.\n\nComme dans les situations précédentes, nous avons essentiellement modifié toute la branche. Il est donc temps de la pousser de force. \n\n## Conclusion sur l'historique des commits Git\n\nBien que nous ayons couvert la plupart des situations qui surviennent dans un workflow avec Git, la réécriture de l’historique Git reste un vaste sujet. Au fur et à mesure que vous vous familiarisez avec les astuces mentionnées ci-dessus, vous pourrez apprendre des concepts plus avancés sur ce sujet dans la [documentation officielle de Git](https://git-scm.com/book/fr/v2/Utilitaires-Git-R%C3%A9%C3%A9crire-l%E2%80%99historique \"Documentation officielle de Git\"). \n\n*Photo par pan xiaozhen sur Unsplash.*\n",[712,848],"2024-07-11",{"slug":1028,"featured":6,"template":686},"keeping-git-commit-history-clean","content:fr-fr:blog:keeping-git-commit-history-clean.yml","Keeping Git Commit History Clean","fr-fr/blog/keeping-git-commit-history-clean.yml","fr-fr/blog/keeping-git-commit-history-clean",2,[693,721,746,770,791,813,834,857,879],1754336065745]